Hello everyone! Hope you all had a great week. Here is a quick update on our note categorization plugin:
Progress from last week:
- Switched to
umap-js: I originally trieddruidjsfor UMAP dimensionality reduction but ran into security issues and TypeScript bugs. I switched toumap-jswhich works perfectly. In my proposal, I had discardedumap-jsbecause the repository is not actively maintained, but after reading more about it, I found out it was developed by Google under PAIR-code, so I thought it was worth giving it a try, and it turned out to be a highly reliable and stable choice. - Implemented 3 Algorithms from Scratch: Wrote K-Means, X-Means, and K-Medoids directly to keep dependencies minimal.
- Added HDBSCAN: Integrated
hdbscan-tsfor density-based clustering. I added a new parameter (minSamples) to control how many notes get flagged as noise, because a lot of notes were being left as noise without it. - Created a Benchmark Pipeline: Set up a pipeline to test all these algorithms side-by-side. I wanted to test on a real set of 48 notes rather than fake data, which made this PR (
feat/umap-clustering-benchmark) quite large.
Benchmark Results:
Here is how the 7 algorithms compared when clustering 48 real notes:
| Strategy | Algorithm | K (Clusters) | Silhouette Score (Higher is Better) | Outliers | Time |
|---|---|---|---|---|---|
hdbscan-5-ms2 |
HDBSCAN | 4 | 0.7504 | 12 | 4ms |
hdbscan-3 |
HDBSCAN | 6 | 0.6794 | 14 | 8ms |
kmedoids-5 |
K-Medoids | 5 | 0.6722 | 0 | 6ms |
hdbscan-3-ms2 |
HDBSCAN | 6 | 0.6700 | 11 | 4ms |
kmeans-5 |
K-Means | 5 | 0.6686 | 0 | 1ms |
kmeans-8 |
K-Means | 8 | 0.5164 | 0 | 0ms |
xmeans-auto |
X-Means | 15 | 0.2825 | 0 | 1ms |
I have added the clustering results in the issue comments: [Feature] UMAP with various clustering algorithms · Issue #15 · joplin/plugin-note-categorization · GitHub
HDBSCAN with tuned parameters (hdbscan-5-ms2) performed best. It successfully grouped topic-specific notes (AI, Finance, Health) and kept unrelated notes (like food recipes) separate as noise.
Plan for this week:
- Work more on the PR: Since this PR is one of the most important ones, I will finish the remaining tests and get the benchmark PR merged.
- Joplin Settings UI: Move the configuration settings out of the code and into the Joplin settings panel.
Problems faced this week:
- Resolving library conflicts with
druidjsand configuringskipLibCheck: trueto bypass TypeScript errors. - Tuning HDBSCAN parameters so it doesn't classify too many notes as noise.
References:
For the mathematical details behind these algorithms, you can refer to these papers. Since the papers were hard to understand at first glance, I also referred to these documentation guides:
- UMAP: UMAP Paper & UMAP User Guide
- HDBSCAN: HDBSCAN Paper & How HDBSCAN Works Guide