├── .gitignore ├── archive ├── readme.md └── word-movers-distance-exploration.ipynb ├── bicluster.xlsx ├── biclustering-with-paul-revere.ipynb ├── binder ├── postBuild └── requirements.txt ├── chart.html ├── cleaned_hm.csv.xz ├── colored-roc-curves.ipynb ├── dimension-reduction-umap-to-plotly-scatterplot.ipynb ├── docs ├── nlp-sbert-umap-hdbscan-tsss-sphere-2d.html ├── nlp-sbert-umap-tsss-hdbscan-chart.html ├── nlp-sbert-umap-tsss-hdbscan-sphere.html └── nlp-use-umap-hdbscan-chart.html ├── holy-nlp.ipynb ├── nlp-sbert-umap-hdbscan.ipynb ├── nlp-use-umap-hdbscan.ipynb ├── output-transformations-roc-impact.ipynb ├── pipfreeze.sh ├── readme.md ├── roc_colored.png ├── rule-based-matching-with-spacy-matcher.ipynb └── w2v_tsne.csv /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | *.gz 107 | .vscode/ 108 | .DS_Store -------------------------------------------------------------------------------- /archive/readme.md: -------------------------------------------------------------------------------- 1 | # The Archive 2 | 3 | Notebooks here are not guaranteed to work due to outdated dependencies or other issues. -------------------------------------------------------------------------------- /bicluster.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbaumgartner/binder-notebooks/cfee899187c9ba5e7a11a5b26fb37aa78cbc1201/bicluster.xlsx -------------------------------------------------------------------------------- /biclustering-with-paul-revere.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Biclustering (with Paul Revere)\n", 8 | "\n", 9 | "\n", 10 | "ref: http://scikit-learn.org/stable/auto_examples/bicluster/bicluster_newsgroups.html" 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "metadata": {}, 16 | "source": [ 17 | "Biclustering is a helpful clustering procedure that derives cluster membership for both rows and columns. Clustering rows and columns individually is fairly common. I view biclustering as an extension that allows me to ask: \"If these columns are clustered together, which rows (if any) point towards that clustering? Accordingly, if any rows are clustered together, which column values might tell me why they're clustered?\"\n", 18 | "\n", 19 | "I have found it helpful with:\n", 20 | "- Incidence Matrix / Cooccurence data (typically found before converting something into a graph/network structure)\n", 21 | "- Text data (the [original paper](http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.140.3011&rep=rep1&type=pdf) on coclustering does this)\n", 22 | "\n", 23 | "The example below performs coclustering on the awesome \"Paul Revere dataset\" originally analyzed in an [amazing blog post](https://kieranhealy.org/blog/archives/2013/06/09/using-metadata-to-find-paul-revere/) by [Kieran Healy](https://kieranhealy.org/).\n", 24 | "\n", 25 | "## References:\n", 26 | "> Biclustering algorithms simultaneously cluster rows and columns of a data matrix. These clusters of rows and columns are known as biclusters. Each determines a submatrix of the original data matrix with some desired properties.\n", 27 | "\n", 28 | "[sklearn - Biclustering](http://scikit-learn.org/stable/modules/biclustering.html#biclustering)" 29 | ] 30 | }, 31 | { 32 | "cell_type": "code", 33 | "execution_count": 1, 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "import re\n", 38 | "\n", 39 | "from sklearn.datasets.twenty_newsgroups import fetch_20newsgroups\n", 40 | "from sklearn.feature_extraction.text import TfidfVectorizer\n", 41 | "from sklearn.cluster.bicluster import SpectralCoclustering\n", 42 | "\n", 43 | "import pandas as pd\n", 44 | "import numpy as np\n", 45 | "import matplotlib.pylab as plt\n", 46 | "\n", 47 | "%matplotlib inline" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "## Data Import" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 2, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "data = pd.read_csv(\n", 64 | " \"https://raw.githubusercontent.com/kjhealy/revere/master/data/PaulRevereAppD.csv\",\n", 65 | " index_col=0,\n", 66 | ")" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 3, 72 | "metadata": {}, 73 | "outputs": [ 74 | { 75 | "data": { 76 | "text/html": [ 77 | "
\n", 78 | "\n", 91 | "\n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | " \n", 107 | " \n", 108 | " \n", 109 | " \n", 110 | " \n", 111 | " \n", 112 | " \n", 113 | " \n", 114 | " \n", 115 | " \n", 116 | " \n", 117 | " \n", 118 | " \n", 119 | " \n", 120 | " \n", 121 | " \n", 122 | " \n", 123 | " \n", 124 | " \n", 125 | " \n", 126 | " \n", 127 | " \n", 128 | " \n", 129 | " \n", 130 | " \n", 131 | " \n", 132 | " \n", 133 | " \n", 134 | " \n", 135 | " \n", 136 | " \n", 137 | " \n", 138 | " \n", 139 | " \n", 140 | " \n", 141 | " \n", 142 | " \n", 143 | " \n", 144 | " \n", 145 | " \n", 146 | " \n", 147 | " \n", 148 | " \n", 149 | " \n", 150 | " \n", 151 | " \n", 152 | " \n", 153 | " \n", 154 | " \n", 155 | " \n", 156 | "
StAndrewsLodgeLoyalNineNorthCaucusLongRoomClubTeaPartyBostonCommitteeLondonEnemies
Adams.John0011000
Adams.Samuel0011011
Allen.Dr0010000
Appleton.Nathaniel0010010
Ash.Gilbert1000000
\n", 157 | "
" 158 | ], 159 | "text/plain": [ 160 | " StAndrewsLodge LoyalNine NorthCaucus LongRoomClub \\\n", 161 | "Adams.John 0 0 1 1 \n", 162 | "Adams.Samuel 0 0 1 1 \n", 163 | "Allen.Dr 0 0 1 0 \n", 164 | "Appleton.Nathaniel 0 0 1 0 \n", 165 | "Ash.Gilbert 1 0 0 0 \n", 166 | "\n", 167 | " TeaParty BostonCommittee LondonEnemies \n", 168 | "Adams.John 0 0 0 \n", 169 | "Adams.Samuel 0 1 1 \n", 170 | "Allen.Dr 0 0 0 \n", 171 | "Appleton.Nathaniel 0 1 0 \n", 172 | "Ash.Gilbert 0 0 0 " 173 | ] 174 | }, 175 | "execution_count": 3, 176 | "metadata": {}, 177 | "output_type": "execute_result" 178 | } 179 | ], 180 | "source": [ 181 | "data.head()" 182 | ] 183 | }, 184 | { 185 | "cell_type": "code", 186 | "execution_count": 4, 187 | "metadata": {}, 188 | "outputs": [], 189 | "source": [ 190 | "data.index = [i.replace(\".\", \", \") for i in data.index]" 191 | ] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": 5, 196 | "metadata": {}, 197 | "outputs": [ 198 | { 199 | "name": "stdout", 200 | "output_type": "stream", 201 | "text": [ 202 | "rows: 254 columns: 7\n" 203 | ] 204 | } 205 | ], 206 | "source": [ 207 | "nrows, ncolumns = data.shape\n", 208 | "print(\"rows:\", nrows, \"columns:\", ncolumns)" 209 | ] 210 | }, 211 | { 212 | "cell_type": "markdown", 213 | "metadata": {}, 214 | "source": [ 215 | "## Fit Model" 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": 6, 221 | "metadata": {}, 222 | "outputs": [ 223 | { 224 | "data": { 225 | "text/plain": [ 226 | "SpectralCoclustering(init='k-means++', mini_batch=False, n_clusters=6,\n", 227 | " n_init=10, n_jobs=None, n_svd_vecs=None, random_state=666,\n", 228 | " svd_method='arpack')" 229 | ] 230 | }, 231 | "execution_count": 6, 232 | "metadata": {}, 233 | "output_type": "execute_result" 234 | } 235 | ], 236 | "source": [ 237 | "cocluster = SpectralCoclustering(n_clusters=6, random_state=666, svd_method=\"arpack\")\n", 238 | "cocluster.fit(data)" 239 | ] 240 | }, 241 | { 242 | "cell_type": "markdown", 243 | "metadata": {}, 244 | "source": [ 245 | "## Explore Results" 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": 7, 251 | "metadata": {}, 252 | "outputs": [ 253 | { 254 | "name": "stdout", 255 | "output_type": "stream", 256 | "text": [ 257 | "Cluster: 0 \tMembers: 68 \tOrgs: 3\n", 258 | "Orgs: LongRoomClub; BostonCommittee; LondonEnemies\n", 259 | "Members: Adams, John; Adams, Samuel; Appleton, Nathaniel; Austin, Benjamin; Austin, Samuel; Baldwin, Cyrus; Boyer, Peter; Boynton, Richard; Brackett, Jos; Bradford, John; Brimmer, Herman; Brimmer, Martin; Broomfield, Henry; Brown, Enoch; Brown, John; Cheever, Ezekiel; Church, Benjamin; Cooper, William; Davis, Caleb; Davis, Edward; Davis, William; Dawes, Thomas; Dennie, William; Dexter, Samuel; Fleet, Thomas; Foster, Bos; Gill, Moses; Greenleaf, Joseph; Greenleaf, William; Greenough, Newn; Hancock, Eben; Hancock, John; Hill, Alexander; Hopkins, Caleb; Isaac, Pierce; Ivers, James; Jarvis, Charles; Johnston, Eben; Lambert, John; Mackay, William; Marshall, Thomas; Marson, John; Mason, Jonathan; Noyces, Nat; Otis, James; Parkman, Elias; Partridge, Sam; Phillips, Samuel; Phillips, William; Pierpont, Robert; Pitts, John; Pitts, Samuel; Powell, William; Prince, Job; Pulling, John; Quincy, Josiah; Roylson, Thomas; Ruddock, Abiel; Sweetser, John; Tyler, Royall; Vernon, Fortesque; Waldo, Benjamin; Wendell, Oliver; Whitwell, Samuel; Whitwell, William; Williams, Jonathan; Winslow, John; Winthrop, John\n", 260 | "---\n", 261 | "Cluster: 1 \tMembers: 81 \tOrgs: 1\n", 262 | "Orgs: TeaParty\n", 263 | "Members: Barnard, Samuel; Bolter, Thomas; Bradlee, David; Bradlee, Josiah; Bradlee, Nathaniel; Bradlee, Thomas; Bewer, James; Bruce, Stephen; Burton, Benjamin; Campbell, Nicholas; Clarke, Benjamin; Cochran, John; Colesworthy, Gilbert; Collier, Gershom; Crane, John; Davis, Robert; Dolbear, Edward; Eaton, Joseph; Eckley, Unknown; Etheridge, William; Fenno, Samuel; Foster, Samuel; Frothingham, Nathaniel; Gammell, John; Gore, Samuel; Greene, Nathaniel; Hammond, Samuel; Hendley, William; Hewes, George; Hicks, John; Hobbs, Samuel; Hooton, John; Howard, Samuel; Howe, Edward; Hunnewell, Jonathan; Hunnewell, Richard; Hunstable, Thomas; Hunt, Abraham; Ingersoll, Daniel; Kinnison, David; Lee, Joseph; Lincoln, Amos; Loring, Matthew; Machin, Thomas; MacKintosh, Capt; MacNeil, Archibald; May, John; Melville, Thomas; Moore, Thomas; Morse, Anthony; Mountford, Joseph; Newell, Eliphelet; Palmer, Joseph; Parker, Jonathan; Payson, Joseph; Peters, John; Pierce, William; Pitts, Lendall; Porter, Thomas; Prentiss, Henry; Prince, John; Purkitt, Henry; Randall, John; Roby, Joseph; Russell, John; Russell, William; Sessions, Robert; Shed, Joseph; Simpson, Benjamin; Slater, Peter; Spear, Thomas; Sprague, Samuel; Spurr, John; Starr, James; Stearns, Phineas; Stevens, Ebenezer; Wheeler, Josiah; Williams, Jeremiah; Williams, Thomas; Willis, Nathaniel; Wyeth, Joshua\n", 264 | "---\n", 265 | "Cluster: 2 \tMembers: 46 \tOrgs: 1\n", 266 | "Orgs: StAndrewsLodge\n", 267 | "Members: Ash, Gilbert; Bell, William; Blake, Increase; Bray, George; Brown, Hugh; Burbeck, Edward; Burbeck, William; Cailleteau, Edward; Callendar, Elisha; Chipman, Seth; Collins, Ezra; Deshon, Moses; Doyle, Peter; Ferrell, Ambrose; Flagg, Josiah; Gould, William; Graham, James; Gray, Wait; Ham, William; Hitchborn, Nathaniel; Hoffins, John; Inglish, Alexander; Jarvis, Edward; Jefferds, Unknown; Jenkins, John; Kerr, Walter; Lewis, Phillip; Marett, Phillip; Marlton, John; McAlpine, William; Milliken, Thomas; Moody, Samuel; Nicholls, Unknown; Obear, Israel; Palfrey, William; Phillips, John; Potter, Edward; Pulling, Richard; Seward, James; Sloper, Ambrose; Stanbridge, Henry; Tabor, Philip; Webb, Joseph; Webster, Thomas; Whitten, John; Wingfield, William\n", 268 | "---\n", 269 | "Cluster: 3 \tMembers: 12 \tOrgs: 0\n", 270 | "Orgs: \n", 271 | "Members: Bass, Henry; Chase, Thomas; Collson, Adam; Condy, JamesFoster; Cooper, Samuel; Eayres, Joseph; Grant, Moses; Molineux, William; Proctor, Edward; Story, Elisha; Swan, James; Young, Thomas\n", 272 | "---\n", 273 | "Cluster: 4 \tMembers: 37 \tOrgs: 1\n", 274 | "Orgs: NorthCaucus\n", 275 | "Members: Allen, Dr; Avery, John; Ballard, John; Barber, Nathaniel; Boit, John; Breck, William; Burt, Benjamin; Cazneau, Capt; Chadwell, Mr; Champney, Caleb; Chrysty, Thomas; Edes, Benjamin; Emmes, Samuel; Hickling, William; Hitchborn, Thomas; Holmes, Nathaniel; Hoskins, William; Johonnott, Gabriel; Kent, Benjamin; Kimball, Thomas; Lowell, John; Matchett, John; Merrit, John; Morton, Perez; Palms, Richard; Pearce, IsaacJun; Pearce, Isaac; Peck, Thomas; Sharp, Gibbens; Sigourney, John; Stoddard, Asa; Stoddard, Jonathan; Symmes, Eben; Symmes, John; Tileston, Thomas; Warren, Joseph; White, Samuel\n", 276 | "---\n", 277 | "Cluster: 5 \tMembers: 10 \tOrgs: 1\n", 278 | "Orgs: LoyalNine\n", 279 | "Members: Barrett, Samuel; Cleverly, Stephen; Crafts, Thomas; Field, Joseph; Peck, Samuel; Revere, Paul; Smith, John; Trott, George; Urann, Thomas; Welles, Henry\n", 280 | "---\n" 281 | ] 282 | } 283 | ], 284 | "source": [ 285 | "cluster_data = []\n", 286 | "for cluster in range(cocluster.n_clusters):\n", 287 | " row_ix, col_ix = cocluster.get_indices(cluster)\n", 288 | " data_subset = data.iloc[row_ix, col_ix]\n", 289 | " c_rows, c_cols = data_subset.shape\n", 290 | " orgs = data_subset.columns\n", 291 | " names = data_subset.index\n", 292 | " print(\"Cluster: \", cluster, \"\\tMembers:\", c_rows, \"\\tOrgs:\", c_cols)\n", 293 | " print(\"Orgs: \", \"; \".join([\"{}\".format(org) for org in orgs]))\n", 294 | " print(\"Members:\", \"; \".join([\"{}\".format(name) for name in names]))\n", 295 | " print(\"---\")\n", 296 | " cluster = {\n", 297 | " \"Cluster\": cluster,\n", 298 | " \"Members\": \"; \".join([\"{}\".format(name) for name in names]),\n", 299 | " \"Orgs\": \"; \".join([\"{}\".format(org) for org in orgs]),\n", 300 | " }\n", 301 | " cluster_data.append(cluster)" 302 | ] 303 | }, 304 | { 305 | "cell_type": "code", 306 | "execution_count": 8, 307 | "metadata": {}, 308 | "outputs": [], 309 | "source": [ 310 | "cluster_info = pd.DataFrame(cluster_data)" 311 | ] 312 | }, 313 | { 314 | "cell_type": "code", 315 | "execution_count": 9, 316 | "metadata": {}, 317 | "outputs": [ 318 | { 319 | "data": { 320 | "text/html": [ 321 | "
\n", 322 | "\n", 335 | "\n", 336 | " \n", 337 | " \n", 338 | " \n", 339 | " \n", 340 | " \n", 341 | " \n", 342 | " \n", 343 | " \n", 344 | " \n", 345 | " \n", 346 | " \n", 347 | " \n", 348 | " \n", 349 | " \n", 350 | " \n", 351 | " \n", 352 | " \n", 353 | " \n", 354 | " \n", 355 | " \n", 356 | " \n", 357 | " \n", 358 | " \n", 359 | " \n", 360 | " \n", 361 | " \n", 362 | " \n", 363 | " \n", 364 | " \n", 365 | " \n", 366 | " \n", 367 | " \n", 368 | " \n", 369 | " \n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | "
ClusterMembersOrgs
00Adams, John; Adams, Samuel; Appleton, Nathanie...LongRoomClub; BostonCommittee; LondonEnemies
11Barnard, Samuel; Bolter, Thomas; Bradlee, Davi...TeaParty
22Ash, Gilbert; Bell, William; Blake, Increase; ...StAndrewsLodge
33Bass, Henry; Chase, Thomas; Collson, Adam; Con...
44Allen, Dr; Avery, John; Ballard, John; Barber,...NorthCaucus
55Barrett, Samuel; Cleverly, Stephen; Crafts, Th...LoyalNine
\n", 383 | "
" 384 | ], 385 | "text/plain": [ 386 | " Cluster Members \\\n", 387 | "0 0 Adams, John; Adams, Samuel; Appleton, Nathanie... \n", 388 | "1 1 Barnard, Samuel; Bolter, Thomas; Bradlee, Davi... \n", 389 | "2 2 Ash, Gilbert; Bell, William; Blake, Increase; ... \n", 390 | "3 3 Bass, Henry; Chase, Thomas; Collson, Adam; Con... \n", 391 | "4 4 Allen, Dr; Avery, John; Ballard, John; Barber,... \n", 392 | "5 5 Barrett, Samuel; Cleverly, Stephen; Crafts, Th... \n", 393 | "\n", 394 | " Orgs \n", 395 | "0 LongRoomClub; BostonCommittee; LondonEnemies \n", 396 | "1 TeaParty \n", 397 | "2 StAndrewsLodge \n", 398 | "3 \n", 399 | "4 NorthCaucus \n", 400 | "5 LoyalNine " 401 | ] 402 | }, 403 | "execution_count": 9, 404 | "metadata": {}, 405 | "output_type": "execute_result" 406 | } 407 | ], 408 | "source": [ 409 | "cluster_info" 410 | ] 411 | }, 412 | { 413 | "cell_type": "markdown", 414 | "metadata": {}, 415 | "source": [ 416 | "## Format and Sort DataFrame with MultiIndex\n", 417 | "Since rows and columns now have hierarchical information with cluster membership, we can reindex the dataframe to take this into account and index easily on cluster. This should allow us to see the block cluster structure along the diagonal." 418 | ] 419 | }, 420 | { 421 | "cell_type": "code", 422 | "execution_count": 10, 423 | "metadata": {}, 424 | "outputs": [], 425 | "source": [ 426 | "data_mi = data.copy()\n", 427 | "\n", 428 | "cocluster_rows = list(zip(cocluster.row_labels_, data.index))\n", 429 | "row_index = pd.MultiIndex.from_tuples(cocluster_rows, names=[\"cluster\", \"person\"])\n", 430 | "data_mi.index = row_index\n", 431 | "data_mi = data_mi.sort_index(axis=0)\n", 432 | "\n", 433 | "cocluster_columns = list(zip(cocluster.column_labels_, data.columns))\n", 434 | "col_index = pd.MultiIndex.from_tuples(cocluster_columns, names=[\"cluster\", \"org\"])\n", 435 | "data_mi.columns = col_index\n", 436 | "data_mi = data_mi.sort_index(axis=1)" 437 | ] 438 | }, 439 | { 440 | "cell_type": "code", 441 | "execution_count": 11, 442 | "metadata": {}, 443 | "outputs": [ 444 | { 445 | "data": { 446 | "text/html": [ 447 | "
\n", 448 | "\n", 465 | "\n", 466 | " \n", 467 | " \n", 468 | " \n", 469 | " \n", 470 | " \n", 471 | " \n", 472 | " \n", 473 | " \n", 474 | " \n", 475 | " \n", 476 | " \n", 477 | " \n", 478 | " \n", 479 | " \n", 480 | " \n", 481 | " \n", 482 | " \n", 483 | " \n", 484 | " \n", 485 | " \n", 486 | " \n", 487 | " \n", 488 | " \n", 489 | " \n", 490 | " \n", 491 | " \n", 492 | " \n", 493 | " \n", 494 | " \n", 495 | " \n", 496 | " \n", 497 | " \n", 498 | " \n", 499 | " \n", 500 | " \n", 501 | " \n", 502 | " \n", 503 | " \n", 504 | " \n", 505 | " \n", 506 | " \n", 507 | " \n", 508 | " \n", 509 | " \n", 510 | " \n", 511 | " \n", 512 | " \n", 513 | " \n", 514 | " \n", 515 | " \n", 516 | " \n", 517 | " \n", 518 | " \n", 519 | " \n", 520 | " \n", 521 | " \n", 522 | " \n", 523 | " \n", 524 | " \n", 525 | " \n", 526 | " \n", 527 | " \n", 528 | " \n", 529 | " \n", 530 | " \n", 531 | " \n", 532 | " \n", 533 | " \n", 534 | " \n", 535 | " \n", 536 | " \n", 537 | " \n", 538 | " \n", 539 | " \n", 540 | " \n", 541 | " \n", 542 | " \n", 543 | " \n", 544 | " \n", 545 | " \n", 546 | " \n", 547 | " \n", 548 | " \n", 549 | " \n", 550 | " \n", 551 | " \n", 552 | " \n", 553 | " \n", 554 | " \n", 555 | " \n", 556 | " \n", 557 | " \n", 558 | " \n", 559 | " \n", 560 | " \n", 561 | " \n", 562 | " \n", 563 | " \n", 564 | " \n", 565 | " \n", 566 | " \n", 567 | " \n", 568 | " \n", 569 | " \n", 570 | " \n", 571 | " \n", 572 | " \n", 573 | " \n", 574 | " \n", 575 | " \n", 576 | " \n", 577 | " \n", 578 | " \n", 579 | " \n", 580 | " \n", 581 | " \n", 582 | " \n", 583 | " \n", 584 | " \n", 585 | " \n", 586 | " \n", 587 | " \n", 588 | " \n", 589 | " \n", 590 | " \n", 591 | " \n", 592 | " \n", 593 | " \n", 594 | " \n", 595 | " \n", 596 | " \n", 597 | " \n", 598 | " \n", 599 | " \n", 600 | " \n", 601 | " \n", 602 | "
cluster01245
orgBostonCommitteeLondonEnemiesLongRoomClubTeaPartyStAndrewsLodgeNorthCaucusLoyalNine
clusterperson
0Adams, John0010010
Adams, Samuel1110010
Appleton, Nathaniel1000010
Austin, Benjamin0100000
Austin, Samuel0100000
Baldwin, Cyrus0100000
Boyer, Peter0100000
Boynton, Richard1100000
Brackett, Jos0100000
Bradford, John1100000
\n", 603 | "
" 604 | ], 605 | "text/plain": [ 606 | "cluster 0 \\\n", 607 | "org BostonCommittee LondonEnemies LongRoomClub \n", 608 | "cluster person \n", 609 | "0 Adams, John 0 0 1 \n", 610 | " Adams, Samuel 1 1 1 \n", 611 | " Appleton, Nathaniel 1 0 0 \n", 612 | " Austin, Benjamin 0 1 0 \n", 613 | " Austin, Samuel 0 1 0 \n", 614 | " Baldwin, Cyrus 0 1 0 \n", 615 | " Boyer, Peter 0 1 0 \n", 616 | " Boynton, Richard 1 1 0 \n", 617 | " Brackett, Jos 0 1 0 \n", 618 | " Bradford, John 1 1 0 \n", 619 | "\n", 620 | "cluster 1 2 4 5 \n", 621 | "org TeaParty StAndrewsLodge NorthCaucus LoyalNine \n", 622 | "cluster person \n", 623 | "0 Adams, John 0 0 1 0 \n", 624 | " Adams, Samuel 0 0 1 0 \n", 625 | " Appleton, Nathaniel 0 0 1 0 \n", 626 | " Austin, Benjamin 0 0 0 0 \n", 627 | " Austin, Samuel 0 0 0 0 \n", 628 | " Baldwin, Cyrus 0 0 0 0 \n", 629 | " Boyer, Peter 0 0 0 0 \n", 630 | " Boynton, Richard 0 0 0 0 \n", 631 | " Brackett, Jos 0 0 0 0 \n", 632 | " Bradford, John 0 0 0 0 " 633 | ] 634 | }, 635 | "execution_count": 11, 636 | "metadata": {}, 637 | "output_type": "execute_result" 638 | } 639 | ], 640 | "source": [ 641 | "data_mi.head(10)" 642 | ] 643 | }, 644 | { 645 | "cell_type": "markdown", 646 | "metadata": {}, 647 | "source": [ 648 | "## Verify Coclustering structure\n", 649 | "\"The resulting bicluster structure is block-diagonal, since each row and each column belongs to exactly one bicluster.\" - [sklearn SpectralCoclustering Docs](http://scikit-learn.org/stable/modules/generated/sklearn.cluster.bicluster.SpectralCoclustering.html)" 650 | ] 651 | }, 652 | { 653 | "cell_type": "code", 654 | "execution_count": 12, 655 | "metadata": {}, 656 | "outputs": [ 657 | { 658 | "data": { 659 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAA6YAAACdCAYAAACn12UYAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAUAUlEQVR4nO3df7DldX3f8edrF1ABrWt2ZVJ+iCbUSjqGZe9C7BoqpjFinGBbJdKYpKQzWztsxUinxfSHMTOZxsloTEKk3Si/Jv4YmkhDIyKMhYI0rntX1vBLKoMgMJDdxY1BcaAL7/5xvrternvu/d4f3/s9557nY+bMOd9fn8/73Pu+33ve8/18PydVhSRJkiRJfVnTdwCSJEmSpMlmYSpJkiRJ6pWFqSRJkiSpVxamkiRJkqReWZhKkiRJknplYSpJkiRJ6tVIFaZJ3pzkviT3J7mk73ik+SR5MMmdSXYnmW7WvSzJTUm+0Tyv6ztOCSDJ5Un2JLlrxrrD5msG/qA5H/9VktP7i1yTbkju/maSR5vz7+4kb5mx7f1N7t6X5Of6iVoaSHJikpuT3JPk7iQXNes9/2qkzZG7nZx/R6YwTbIW+CPgHOBU4Pwkp/YbldTK2VV1WlVNNcuXAF+sqlOALzbL0ii4EnjzrHXD8vUc4JTmsRW4bIVilA7nSn44dwF+rzn/nlZV1wM0nx3eCfxEc8zHms8YUl8OABdX1anATwEXNnnq+VejbljuQgfn35EpTIEzgPur6oGqegb4DHBuzzFJi3EucFXz+irgbT3GIh1SVbcC3561eli+ngtcXQNfBl6a5EdXJlLp+Ybk7jDnAp+pqqer6pvA/Qw+Y0i9qKrHquqrzesngXuB4/H8qxE3R+4Os6Tz7ygVpscDD89YfoS537g0Cgq4McmuJFubdcdV1WPN68eB4/oJTWplWL56TtY42NYMdbx8xm0T5q5GVpKTgY3ADjz/aozMyl3o4Pw7SoWpNI5eX1WnMxh2c2GSs2ZurKpiULxKI8981Zi5DPgx4DTgMeDD/YYjzS3JscCfAe+tqr+duc3zr0bZYXK3k/PvKBWmjwInzlg+oVknjayqerR53gNcy2C4wl8fHHLTPO/pL0JpXsPy1XOyRlpV/XVVPVtVzwF/zA+Gi5m7GjlJjmTwwf6TVfXZZrXnX428w+VuV+ffUSpMdwKnJHllkqMY3Dh7Xc8xSUMlOSbJiw++Bt4E3MUgb3+12e1XgT/vJ0KplWH5eh3wK83skD8FfGfGkDOpd7PuufsnDM6/MMjddyZ5QZJXMphA5isrHZ90UJIAnwDuraqPzNjk+VcjbVjudnX+PWLpIS+PqjqQZBvwBWAtcHlV3d1zWNJcjgOuHfzNcgTwqaq6IclO4Jok/xJ4CDivxxilQ5J8GngDsD7JI8AHgN/h8Pl6PfAWBhMXPAVcsOIBS40hufuGJKcxGP74IPCvAKrq7iTXAPcwmFHywqp6to+4pcYW4JeBO5Psbtb9Bp5/NfqG5e75XZx/MxjSLkmSJElSP0ZpKK8kSZIkaQJZmEqSJEmSemVhKkmSJEnqlYWpJEmSJKlXFqaSJEmSpF6NXGGaZGvfMUiLZf5qnJm/Gmfmr8aVuatxtpz5O3KFKeAfp8aZ+atxZv5qnJm/GlfmrsbZqi5MJUmSJEkTJFXVdwyHrF+/vo4+5hg2rN/QdyjSouzdt9f81dgyfzXOzF+ttDvu/dbQbRtfc1LrdlYyd2fHvJA4l9soxTJp5srd2eb6vdxx77eoA98nR7xozuNm9lfPPEkd+H4O195IFaabNk3V7Tum+w5DkiRJmtO6zduGbtu/89IVjKS92TH3GecoxTJp5srd2eb6vbT9G5i539P3XcNzT+05bGHqUF5JkiRJUq8sTCVJkiRJveq0ME3y0iR/muTrSe5N8rou+5MkSZIkjZ8jOm7/94EbqurtSY4Cju64P0mSJEnSmOmsME3yd4CzgH8BUFXPAM901Z8kSZIkaTx1OZT3lcBe4IokdyT5eJJjOuxPkiRJkjSGuixMjwBOBy6rqo3A94BLZu+UZGuS6STTe/ft7TAcSZIkSdIo6rIwfQR4pKp2NMt/yqBQfZ6q2l5VU1U15RdjS5IkSdLk6awwrarHgYeTvLpZ9TPAPV31J0mSJEkaT13PyvtvgE82M/I+AFzQcX+SJEmSpDHTaWFaVbuBqS77kCRJkiSNty7vMZUkSZIkaV4WppIkSZKkXlmYSpIkSZJ6larqO4ZD1hz98nrBq89rte/+nZd2HM3yWLd529Bty/EeZre/2DZntjMuP9vlslw/w+Xof66++45ztknOGUmS5vqMN5eF/K9fbrP77ro/jY6VrjuGfU7ccuYUu3ZN53DHeMVUkiRJktQrC1NJkiRJUq8sTCVJkiRJver0e0yTPAg8CTwLHKgqv9NUkiRJkvQ8nRamjbOrat8K9CNJkiRJGkMO5ZUkSZIk9WpRhWmSo1ruWsCNSXYl2bqYviRJkiRJq9u8hWmSW5KcPGP5DGBny/ZfX1WnA+cAFyY56zDtb00ynWS6Dny/ZbOSJEmSpNWizT2m/wW4IckfAMczKDIvaNN4VT3aPO9Jci1wBnDrrH22A9sB1hz98mofuiRJkiRpNZi3MK2qLyR5N3ATsA/YWFWPz3dckmOANVX1ZPP6TcBvLTVgSZIkSdLqMm9hmuQ/AecBZwGvBW5JcnFVfW6eQ48Drk1ysJ9PVdUNS4xXkiRJkrTKtBnK+yPAGVX1feAvk9wAfByYszCtqgeAn1x6iJIkSZKk1azNUN73AiQ5uqqeqqqHgJ/tPDJJkiRJ0kRoMyvv65LcA3y9Wf7JJB/rPDJJkiRJ0kRo8z2mHwV+DngCoKq+xuB+U0mSJEmSlixVc39DS5IdVXVmkjuqamOz7mtVtez3j27aNFW375he7mYlSdIqsm7ztr5DkNi/89K+Q5CeZ+a5cXZ+Lse22eb6Gxh23NP3XcNzT+3J4ba1mfzo4ST/EKgkRwIXAfe2OE6SJEmSpHm1Gcr7buBC4HjgUeC0ZlmSJEmSpCVrMyvvPuCXViAWSZIkSdIEGlqYJvlDYOgNqFX1njYdJFkLTAOPVtVbFxyhJEmSJGlVm2so7zSwC3ghcDrwjeZxGnDUAvrwnlRJkiRJ0lBDr5hW1VUASf418PqqOtAs/1fgtjaNJzkB+Hngt4H3LTlaSZIkSdKq02byo3XAS2YsH9usa+OjwL8DnltgXJIkSZKkCdHm62J+B7gjyc1AgLOA35zvoCRvBfZU1a4kb5hjv63AVoATTzqpRTiSJEmSpNWkzay8VyT5PHBms+rfV9XjLdreAvxCkrcwuE/1JUn+pKreNav97cB2gE2bpoZOtiRJkiRJWp3aDOUFWAvsBfYDfy/JWfMdUFXvr6oTqupk4J3A/5pdlEqSJEmSNO8V0yQfAn4RuJsf3CtawK0dxiVJkiRJmhBt7jF9G/Dqqnp6sZ1U1S3ALYs9XpIkSZK0erUZyvsAcGTXgUiSJEmSJlObK6ZPAbuTfBE4dNW0qt7TWVSSJEmSpInRpjC9rnlIkiRJkrTs2nxdzFUrEYik8bVu87a+Q5A0QfbvvLTvEKSx+d/X9u9l9vvx72z8zPU7W+y25TCz/S1nfnnofkML0yTXVNV5Se5kMAvv81TVa5cYoyRJkiRJc14xvah5futKBCJJkiRJmkxDC9Oqeqx5fmjlwpEkSZIkTZo2XxezKElemOQrSb6W5O4kH+yqL0mSJEnS+GozK+9iPQ28saq+m+RI4EtJPl9Vw+94lSRJkiRNnM4K06oq4LvN4pHN44cmUZIkSZIkTbZ5h/Im2ZLkpiT/N8kDSb6Z5IE2jSdZm2Q3sAe4qap2LDVgSZIkSdLq0uaK6SeAXwd2Ac8upPGqehY4LclLgWuT/IOqumvmPkm2AlsBTjzppIU0L0mSJElaBdpMfvSdqvp8Ve2pqicOPhbSSVX9DXAz8ObDbNteVVNVNbVh/YaFNCtJkiRJWgXaFKY3J/ndJK9LcvrBx3wHJdnQXCklyYuAnwW+vsR4JUmSJEmrTJuhvGc2z1Mz1hXwxnmO+1HgqiRrGRTA11TVXyw8REmSJEnSajZvYVpVZy+m4ar6K2DjYo6VJEmSJE2OeQvTZjjurwAnz9y/qt7TXViSJEmSpEnRZijv9cCXgTuB57oNR5IkSZI0adoUpi+sqvd1HokkSZIkaSKlqubeIfl14LvAXwBPH1xfVd9e7mDWHP3yesGrzzvstv07L13u7lbcus3bhm5byPub2c7s45arj+WIZZT7aNvm7J9n13m42P5WIs6V/llIkrQarcRnJ02mrnNrOT4Lbjlzil27pnO4bW2umD4D/C7wHxjMxkvz/KoFRyJJkiRJ0ixtCtOLgR+vqn1dByNJkiRJmjxrWuxzP/BU14FIkiRJkiZTmyum3wN2J7mZ599jOufXxSQ5EbgaOI7B0N/tVfX7S4hVkiRJkrQKtSlM/0fzWKgDwMVV9dUkLwZ2Jbmpqu5ZRFuSJEmSpFVq3sK0qq5aTMNV9RjwWPP6yST3AscDFqaSJEmSpEPmLUyTfJMfzMZ7SFW1npU3ycnARmDHAmKTJEmSJE2ANkN5p2a8fiHwDuBlbTtIcizwZ8B7q+pvD7N9K7AVgCOPbdusJEmSJGmVmHdW3qp6Ysbj0ar6KPDzbRpPciSDovSTVfXZIe1vr6qpqprKES9aUPCSJEmSpPHXZijv6TMW1zC4gtrmuACfAO6tqo8sOkJJkiRJ0qrWZijvh2e8PgA8CJzX4rgtwC8DdybZ3az7jaq6fkERSpIkSZJWtTaz8p69mIar6ktAFnOsJEmSJGlyDC1Mk7xvrgMdnitJkiRJWg5zXTF98YpFIUmSJEmaWEML06r64EoGIkmSJEmaTG1m1z0B+EMGkxkB3AZcVFWPLHcwG19zErfvuPTQ8rrN24buO9e2cbF/Z7v3OtdxC9m20j+z5eqvi/fU9mc/u++Z+861bbEW0ubMfbuIZa7+Zvcx1+9IkqTVqO3/6Nn7dfEZpK2FxOL/9tVlHD63zfs9psAVwHXA320e/7NZJ0mSJEnSkrUpTDdU1RVVdaB5XAls6DguSZIkSdKEaFOYPpHkXUnWNo93AU90HZgkSZIkaTK0KUx/DTgPeBx4DHg7cMF8ByW5PMmeJHctLURJkiRJ0mo27+RHVfUQ8AuLaPtK4FLg6kUcK0mSJEmaEPNeMU1yVZKXzlhel+Ty+Y6rqluBby8xPkmSJEnSKtdmKO9rq+pvDi5U1X5gY3chSZIkSZImSZvCdE2SdQcXkryMFkOA20qyNcl0kum9+/YuV7OSJEmSpDHRpsD8MPCXSf57s/wO4LeXK4Cq2g5sB9i0aaqWq11JkiRJ0nhoM/nR1UmmgTc2q/5pVd3TbViSJEmSpEnRakhuU4guqBhN8mngDcD6JI8AH6iqTyw4QkmSJEnSqrZs94rOVlXnd9W2JEmSJGn1aDP5kSRJkiRJnbEwlSRJkiT1ysJUkiRJktSrVI3ON7Rs2jRVt++YPrS8bvO2ofvu33npovqY2ebsNubathxmv5+Zfcy1bbFtLiW2PmNZiT6W43e9kFja9tdFm8t1nCRJWjkr/dlwJT7HqVvj8Blvy5lT7No1ncNt84qpJEmSJKlXFqaSJEmSpF5ZmEqSJEmSetVpYZrkzUnuS3J/kku67EuSJEmSNJ46K0yTrAX+CDgHOBU4P8mpXfUnSZIkSRpPXV4xPQO4v6oeqKpngM8A53bYnyRJkiRpDHVZmB4PPDxj+ZFmnSRJkiRJh/Q++VGSrUmmk0zv3be373AkSZIkSSusy8L0UeDEGcsnNOuep6q2V9VUVU1tWL+hw3AkSZIkSaOoy8J0J3BKklcmOQp4J3Bdh/1JkiRJksbQEV01XFUHkmwDvgCsBS6vqru76k+SJEmSNJ46K0wBqup64Pou+5AkSZIkjbfeJz+SJEmSJE02C1NJkiRJUq8sTCVJkiRJvUpV9R3DIUn2At8D9vUdi7RI6zF/Nb7MX40z81fjytzVOFto/r6iqg77HaEjVZgCJJmuqqm+45AWw/zVODN/Nc7MX40rc1fjbDnz16G8kiRJkqReWZhKkiRJkno1ioXp9r4DkJbA/NU4M39XQJLfSvKPF3jMg0nWdxXTKmH+alyZuxpny5a/I3ePqSRJoyZJGPzPfK6n/h8EpqrKCVIkSavSKF4xlSSpd0lOTnJfkquBu4ATk5yf5M4kdyX5ULPfO5J8pHl9UZIHmtevSnL7Ydq9Msnbm9cPJvlgkq827f79Zv2PJLkxyd1JPg5kxvHvSvKVJLuT/Lcka5O8Isk3kqxPsibJbUne1PkPSZKkZWJhKknScKcAH6uqnwD+H/Ah4I3AacDmJG8DbgN+utn/p4EnkhzfvL61RR/7qup04DLg3zbrPgB8qen3WuAkgCSvAX4R2FJVpwHPAr9UVQ81sV0GXAzcU1U3LumdS5K0gixMJUka7qGq+nLzejNwS1XtraoDwCeBs6rqceDYJC8GTgQ+BZzFoDC9rUUfn22edwEnN6/PAv4EoKo+B+xv1v8MsAnYmWR3s/yqZr+PAy8B3s0PClxJksbCEX0HIEnSCPtey/3+D3ABcB+DYvTXgNcxuHo5n6eb52eZ//9ygKuq6v0/tCE5GjihWTwWeLJF35IkjQSvmEqS1M5XgH/U3Me5Fjgf+N/NttsYXKW8FbgDOBt4uqq+s8i+bgX+OUCSc4B1zfovAm9P8vJm28uSvKLZ9iEGV3H/M/DHi+xXkqReeMVUkqQWquqxJJcANzO4cvm5qvrzZvNtDIbx3lpVzyZ5GPj6Err7IPDpJHczuBr7rSaGe5L8R+DGJGsY3Pd6YZKTGQw13tL0/8+SXFBVVywhBkmSVoxfFyNJkiRJ6pVDeSVJkiRJvbIwlSRJkiT1ysJUkiRJktQrC1NJkiRJUq8sTCVJkiRJvbIwlSRJkiT1ysJUkiRJktQrC1NJkiRJUq/+P7C4g0NYCGw1AAAAAElFTkSuQmCC\n", 660 | "text/plain": [ 661 | "
" 662 | ] 663 | }, 664 | "metadata": { 665 | "needs_background": "light" 666 | }, 667 | "output_type": "display_data" 668 | } 669 | ], 670 | "source": [ 671 | "plt.matshow(data_mi.values.T, cmap=plt.cm.Blues, aspect=\"auto\", origin=\"lower\")\n", 672 | "plt.xlabel(\"row index\")\n", 673 | "plt.ylabel(\"column index\")\n", 674 | "plt.show()\n", 675 | "# I plotted the transpose so it doesn't give us a long image" 676 | ] 677 | }, 678 | { 679 | "cell_type": "markdown", 680 | "metadata": {}, 681 | "source": [ 682 | "## Brief Analysis\n", 683 | "Let's take a look and see where the actual Loyal Nine members ended up. The organization ended up in our `Cluster 5`, but how many members of that bicluster match?\n", 684 | "\n", 685 | "Loyal Nine [members](https://books.google.com/books?id=iNgNCgAAQBAJ&pg=PA26#v=onepage&q&f=false\n", 686 | "):\n", 687 | "\n", 688 | "- John Avery, a distiller and club secretary;\n", 689 | "- John Smith and Stephen Cleverly, both braziers;\n", 690 | "- Thomas Crafts, a printer;\n", 691 | "- Benjamin Edes, who along with John Gill produced the important Boston Gazette;\n", 692 | "- Thomas Chase, a distiller;\n", 693 | "- Joseph Field, a ship's captain;\n", 694 | "- George Trott, a jeweler;\n", 695 | "- Henry Bass, a merchant related to Samuel Adams" 696 | ] 697 | }, 698 | { 699 | "cell_type": "code", 700 | "execution_count": 13, 701 | "metadata": {}, 702 | "outputs": [], 703 | "source": [ 704 | "loyal_nine = [\n", 705 | " \"Avery, John\",\n", 706 | " \"Smith, John\",\n", 707 | " \"Cleverly, Stephen\",\n", 708 | " \"Crafts, Thomas\",\n", 709 | " \"Edes, Benjamin\",\n", 710 | " \"Chase, Thomas\",\n", 711 | " \"Field, Joseph\",\n", 712 | " \"Trott, George\",\n", 713 | " \"Bass, Henry\",\n", 714 | "]" 715 | ] 716 | }, 717 | { 718 | "cell_type": "code", 719 | "execution_count": 14, 720 | "metadata": {}, 721 | "outputs": [ 722 | { 723 | "data": { 724 | "text/html": [ 725 | "
\n", 726 | "\n", 743 | "\n", 744 | " \n", 745 | " \n", 746 | " \n", 747 | " \n", 748 | " \n", 749 | " \n", 750 | " \n", 751 | " \n", 752 | " \n", 753 | " \n", 754 | " \n", 755 | " \n", 756 | " \n", 757 | " \n", 758 | " \n", 759 | " \n", 760 | " \n", 761 | " \n", 762 | " \n", 763 | " \n", 764 | " \n", 765 | " \n", 766 | " \n", 767 | " \n", 768 | " \n", 769 | " \n", 770 | " \n", 771 | " \n", 772 | " \n", 773 | " \n", 774 | " \n", 775 | " \n", 776 | " \n", 777 | " \n", 778 | " \n", 779 | " \n", 780 | " \n", 781 | " \n", 782 | " \n", 783 | " \n", 784 | " \n", 785 | " \n", 786 | " \n", 787 | " \n", 788 | " \n", 789 | " \n", 790 | " \n", 791 | " \n", 792 | " \n", 793 | " \n", 794 | " \n", 795 | " \n", 796 | " \n", 797 | " \n", 798 | " \n", 799 | " \n", 800 | " \n", 801 | " \n", 802 | " \n", 803 | " \n", 804 | " \n", 805 | " \n", 806 | " \n", 807 | " \n", 808 | " \n", 809 | " \n", 810 | " \n", 811 | " \n", 812 | " \n", 813 | " \n", 814 | " \n", 815 | " \n", 816 | " \n", 817 | " \n", 818 | " \n", 819 | " \n", 820 | " \n", 821 | " \n", 822 | " \n", 823 | " \n", 824 | " \n", 825 | " \n", 826 | " \n", 827 | " \n", 828 | " \n", 829 | " \n", 830 | " \n", 831 | " \n", 832 | " \n", 833 | " \n", 834 | " \n", 835 | " \n", 836 | " \n", 837 | " \n", 838 | " \n", 839 | " \n", 840 | " \n", 841 | " \n", 842 | " \n", 843 | " \n", 844 | " \n", 845 | " \n", 846 | " \n", 847 | " \n", 848 | " \n", 849 | " \n", 850 | " \n", 851 | " \n", 852 | " \n", 853 | " \n", 854 | " \n", 855 | " \n", 856 | " \n", 857 | " \n", 858 | " \n", 859 | " \n", 860 | " \n", 861 | " \n", 862 | " \n", 863 | " \n", 864 | " \n", 865 | " \n", 866 | " \n", 867 | " \n", 868 | " \n", 869 | " \n", 870 | " \n", 871 | " \n", 872 | "
cluster01245
orgBostonCommitteeLondonEnemiesLongRoomClubTeaPartyStAndrewsLodgeNorthCaucusLoyalNine
clusterperson
3Bass, Henry0101011
Chase, Thomas0101011
4Avery, John0100001
Edes, Benjamin0000011
5Cleverly, Stephen0000001
Crafts, Thomas0000101
Field, Joseph0000001
Smith, John0000001
Trott, George0000001
\n", 873 | "
" 874 | ], 875 | "text/plain": [ 876 | "cluster 0 1 \\\n", 877 | "org BostonCommittee LondonEnemies LongRoomClub TeaParty \n", 878 | "cluster person \n", 879 | "3 Bass, Henry 0 1 0 1 \n", 880 | " Chase, Thomas 0 1 0 1 \n", 881 | "4 Avery, John 0 1 0 0 \n", 882 | " Edes, Benjamin 0 0 0 0 \n", 883 | "5 Cleverly, Stephen 0 0 0 0 \n", 884 | " Crafts, Thomas 0 0 0 0 \n", 885 | " Field, Joseph 0 0 0 0 \n", 886 | " Smith, John 0 0 0 0 \n", 887 | " Trott, George 0 0 0 0 \n", 888 | "\n", 889 | "cluster 2 4 5 \n", 890 | "org StAndrewsLodge NorthCaucus LoyalNine \n", 891 | "cluster person \n", 892 | "3 Bass, Henry 0 1 1 \n", 893 | " Chase, Thomas 0 1 1 \n", 894 | "4 Avery, John 0 0 1 \n", 895 | " Edes, Benjamin 0 1 1 \n", 896 | "5 Cleverly, Stephen 0 0 1 \n", 897 | " Crafts, Thomas 1 0 1 \n", 898 | " Field, Joseph 0 0 1 \n", 899 | " Smith, John 0 0 1 \n", 900 | " Trott, George 0 0 1 " 901 | ] 902 | }, 903 | "execution_count": 14, 904 | "metadata": {}, 905 | "output_type": "execute_result" 906 | } 907 | ], 908 | "source": [ 909 | "data_mi[data_mi.index.get_level_values(\"person\").isin(loyal_nine)]" 910 | ] 911 | }, 912 | { 913 | "cell_type": "markdown", 914 | "metadata": {}, 915 | "source": [ 916 | "In `Cluster 5` we recovered all individuals who were *exclusively* members of the Loyal Nine, plus Thomas Crafts. `Cluster 4` pulled two Loyal Nine members also part of the North Caucus and London Enemies, and `Cluster 3` holds members that were additionally part of the North Cacus, Tea Party, and London Enemies each. Also note Cluster 3 contains no organizations -- it's members are part of several organizations." 917 | ] 918 | }, 919 | { 920 | "cell_type": "markdown", 921 | "metadata": {}, 922 | "source": [ 923 | "## Export to Excel\n", 924 | "It's helpful to export this to Excel because the MultiIndex formats nicely into merged cells and retains the hierarchical indexing structure.\n", 925 | "\n", 926 | "The data is on the `data` sheet, and cluster details are on the `clusters` sheet." 927 | ] 928 | }, 929 | { 930 | "cell_type": "code", 931 | "execution_count": 15, 932 | "metadata": {}, 933 | "outputs": [], 934 | "source": [ 935 | "data_sheets = [(data_mi, \"data\"), (cluster_info, \"clusters\")]\n", 936 | "\n", 937 | "filename = \"bicluster.xlsx\"\n", 938 | "writer = pd.ExcelWriter(filename, engine=\"xlsxwriter\")\n", 939 | "for data in data_sheets:\n", 940 | " data[0].to_excel(writer, sheet_name=data[1])\n", 941 | "writer.save()" 942 | ] 943 | }, 944 | { 945 | "cell_type": "code", 946 | "execution_count": null, 947 | "metadata": {}, 948 | "outputs": [], 949 | "source": [] 950 | } 951 | ], 952 | "metadata": { 953 | "anaconda-cloud": {}, 954 | "kernelspec": { 955 | "display_name": "Python 3", 956 | "language": "python", 957 | "name": "python3" 958 | }, 959 | "language_info": { 960 | "codemirror_mode": { 961 | "name": "ipython", 962 | "version": 3 963 | }, 964 | "file_extension": ".py", 965 | "mimetype": "text/x-python", 966 | "name": "python", 967 | "nbconvert_exporter": "python", 968 | "pygments_lexer": "ipython3", 969 | "version": "3.7.3" 970 | } 971 | }, 972 | "nbformat": 4, 973 | "nbformat_minor": 1 974 | } 975 | -------------------------------------------------------------------------------- /binder/postBuild: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | python -m spacy download en 3 | python -m spacy download en_core_web_md 4 | python -m gensim.downloader --download word2vec-google-news-300 5 | python -m nltk.downloader wordnet 6 | jupyter nbextension enable --py widgetsnbextension -------------------------------------------------------------------------------- /binder/requirements.txt: -------------------------------------------------------------------------------- 1 | altair==4.1.0 2 | black==19.3b0 3 | gensim==3.8.3 4 | hdbscan==0.8.26 5 | importlib-metadata==1.7.0 6 | ipykernel==5.3.2 7 | ipython==8.10.0 8 | jsonschema==3.2.0 9 | jupyter-client==6.1.5 10 | jupyter-core==4.6.3 11 | matplotlib==3.2.2 12 | nbformat>=4.2.0 13 | pandas==1.0.5 14 | plac==1.1.3 15 | plotly==4.14.3 16 | scikit-learn==0.23.1 17 | sentence-transformers==0.4.1.2 18 | spacy==2.3.1 19 | srsly==1.0.2 20 | tabulate==0.8.7 21 | tensorboard==2.2.2 22 | tensorboard-plugin-wit==1.7.0 23 | tensorflow==2.9.3 24 | tensorflow-estimator==2.2.0 25 | tensorflow-hub==0.8.0 26 | tqdm==4.47.0 27 | umap-learn==0.5 28 | -------------------------------------------------------------------------------- /cleaned_hm.csv.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbaumgartner/binder-notebooks/cfee899187c9ba5e7a11a5b26fb37aa78cbc1201/cleaned_hm.csv.xz -------------------------------------------------------------------------------- /colored-roc-curves.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Colored ROC Curves" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "The Receiver Operating Characteristic (ROC) curve is helpful in evaluating model performance, especially since Area Under the Curve (AUC ROC) has a several friendly interpretations. I use ROC curves in evaluating models and have to explain the output to non-technical folks. I was reading through [Machine Learning: The Art and Science of Algorithms that Make Sense of Data](http://a.co/dnKG3eO) and stumbled upon this nice visual and interpretation of ROC (tied to AUC):\n", 15 | "\n", 16 | "![png](https://i.imgur.com/nWXd3Q0.png)\n", 17 | "\n", 18 | ">Flach, P. (2012). Machine Learning: The Art and Science of Algorithms that Make Sense of Data. Cambridge University Press.\n", 19 | "\n", 20 | "The interpretation that each cell is a pair of true and false outcomes and their scores doesn't always map to reality -- usually you have more than 100 pairs and in imbalanced dataset -- but in general it helps me imagine model performance and explain to someone what the curve means." 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 1, 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "import numpy as np\n", 30 | "import matplotlib.pyplot as plt\n", 31 | "\n", 32 | "from sklearn.datasets import load_digits\n", 33 | "from sklearn.tree import DecisionTreeClassifier\n", 34 | "from sklearn.metrics import roc_curve, auc\n", 35 | "from sklearn.model_selection import train_test_split\n", 36 | "\n", 37 | "%matplotlib inline" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "## Load Data\n", 45 | "From the digits dataset we'll try to predict if a digit is `4` " 46 | ] 47 | }, 48 | { 49 | "cell_type": "code", 50 | "execution_count": 2, 51 | "metadata": {}, 52 | "outputs": [], 53 | "source": [ 54 | "digits = load_digits()\n", 55 | "X = digits.data\n", 56 | "y = digits.target\n", 57 | "\n", 58 | "y = y == 4" 59 | ] 60 | }, 61 | { 62 | "cell_type": "markdown", 63 | "metadata": {}, 64 | "source": [ 65 | "## Build Model\n", 66 | "We're making a purposefully bad model so the ROC curve is more interesting. Then building the ROC curve from predictions on a test set." 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 3, 72 | "metadata": {}, 73 | "outputs": [], 74 | "source": [ 75 | "dt = DecisionTreeClassifier(max_depth=5)\n", 76 | "\n", 77 | "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=666)\n", 78 | "\n", 79 | "probas_ = dt.fit(X_train, y_train).predict_proba(X_test)\n", 80 | "\n", 81 | "fpr, tpr, thresholds = roc_curve(y_test, probas_[:, 1])\n", 82 | "roc_auc = auc(fpr, tpr)" 83 | ] 84 | }, 85 | { 86 | "cell_type": "markdown", 87 | "metadata": {}, 88 | "source": [ 89 | "## Build Coloring Matrix\n", 90 | "We'll create a `100x100` matrix and color each chunk of cells according to the coordinates given by `FPR` and `TPR`" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 4, 96 | "metadata": {}, 97 | "outputs": [], 98 | "source": [ 99 | "coordlist = list(zip(((fpr * 100).astype(int)), ((tpr * 100).astype(int))))\n", 100 | "\n", 101 | "roc_array = np.zeros((100,100))\n", 102 | "\n", 103 | "for i, coords in enumerate(coordlist):\n", 104 | " if i == len(coordlist) - 1:\n", 105 | " continue\n", 106 | " else:\n", 107 | " # orange\n", 108 | " roc_array[coords[0]:coordlist[i+1][0], coords[1]:coordlist[i+1][1]] = 0\n", 109 | " # red\n", 110 | " roc_array[coords[0]:coordlist[i+1][0], coordlist[i+1][1]:100] = -1\n", 111 | " # green\n", 112 | " roc_array[coords[0]:100, 0:coords[1]] = 1" 113 | ] 114 | }, 115 | { 116 | "cell_type": "markdown", 117 | "metadata": {}, 118 | "source": [ 119 | "## Plot Colored Matrix & ROC Curve\n", 120 | "There is still a small issue of the colors not exactly lining up with the gridlines." 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 5, 126 | "metadata": {}, 127 | "outputs": [ 128 | { 129 | "data": { 130 | "image/png": "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\n", 131 | "text/plain": [ 132 | "
" 133 | ] 134 | }, 135 | "metadata": {}, 136 | "output_type": "display_data" 137 | } 138 | ], 139 | "source": [ 140 | "fig = plt.figure(figsize=(8,8))\n", 141 | "\n", 142 | "# ROC Curve\n", 143 | "plt.plot((fpr * 100).astype(int), (tpr * 100).astype(int),\n", 144 | " lw=1.5, linestyle='--', color='navy',\n", 145 | " label='ROC (AUC = %0.2f)' % (roc_auc))\n", 146 | "\n", 147 | "# Dummy Model\n", 148 | "plt.plot([0.0, 100.0], [0.0, 100.0],\n", 149 | " linestyle='-', lw=1, color='k', alpha=0.75,\n", 150 | " label='Baseline')\n", 151 | "\n", 152 | "# ROC Color Matrix\n", 153 | "plt.imshow(roc_array.T, \n", 154 | " cmap=plt.cm.RdYlGn, alpha=0.9, origin='lower',\n", 155 | " aspect='auto', interpolation='nearest', extent=[0.0, 100.0, 0.0, 100.0])\n", 156 | "plt.legend(loc=\"lower right\")\n", 157 | "\n", 158 | "# adding the lines to the chart automatically extends the axis by (-20, -20)\n", 159 | "ax = fig.axes[0]\n", 160 | "ax.set_xlim([0,100])\n", 161 | "ax.set_ylim([0,100])\n", 162 | "\n", 163 | "# axis labels\n", 164 | "plt.xlabel('Negatives sorted on decreasing score')\n", 165 | "plt.ylabel('Positives sorted on decreasing score')\n", 166 | "\n", 167 | "# minor ticks each unit\n", 168 | "minor_ticks = np.arange(0, 100, 1) \n", 169 | "ax.set_xticks(minor_ticks, minor=True) \n", 170 | "ax.set_yticks(minor_ticks, minor=True)\n", 171 | "ax.grid(which='minor', alpha=0.6, linestyle='-')\n", 172 | "\n", 173 | "# tight_layout for figures sometimes getting cutoff\n", 174 | "plt.tight_layout()\n", 175 | "plt.savefig('roc_colored.png')" 176 | ] 177 | }, 178 | { 179 | "cell_type": "markdown", 180 | "metadata": {}, 181 | "source": [ 182 | "## Relevant `matplotlib` StackOverflow Posts\n", 183 | "- [matching axis in imshow](http://stackoverflow.com/questions/12324176/matplotlib-imshow-offset-to-match-axis)\n", 184 | "- [limiting y-axis](http://stackoverflow.com/questions/3777861/setting-y-axis-limit-in-matplotlib)\n", 185 | "- [specifing minor axis grid aesthetics](http://stackoverflow.com/questions/24943991/matplotlib-change-grid-interval-and-specify-tick-labels)" 186 | ] 187 | } 188 | ], 189 | "metadata": { 190 | "anaconda-cloud": {}, 191 | "kernelspec": { 192 | "display_name": "Python 3", 193 | "language": "python", 194 | "name": "python3" 195 | } 196 | }, 197 | "nbformat": 4, 198 | "nbformat_minor": 1 199 | } -------------------------------------------------------------------------------- /nlp-sbert-umap-hdbscan.ipynb: -------------------------------------------------------------------------------- 1 | {"cells":[{"cell_type":"markdown","metadata":{},"source":["# Sentence Embeddings, Custom Distances, and Spherical Projections\n","This notebook is a workflow for generating, analyzing, and interpreting embeddings of sentences. If you're used to the basic workflow of getting embeddings and projecting them to two dimensions, this notebook contains some unique jumping off points:\n","\n","1. It uses the `paraphrase-distilroberta-base-v1` model from the `sentence-transformers` library instead of Universal Sentence Encoder. I find this gives much better results.\n","2. It uses a custom distance metric, TS-SS, from the paper: [A. Heidarian and M. J. Dinneen, \"A Hybrid Geometric Approach for Measuring Similarity Level Among Documents and Document Clustering,\"](https://ieeexplore.ieee.org/document/7474366?reload=true). I used [this implementation](https://github.com/taki0112/Vector_Similarity/blob/master/README.md) as a reference, but corrected an error and turned it into a numba function for faster computation.\n","3. In projecting using UMAP, it projects to onto spherical coordinates instead of a traditional Euclidean 2D plane. I personally believe this leads to a much more intuitive understanding of embeddings. Rather than an interpretation on a 2D plane where in some sense we are \"bound\" by the limits of the x-axis and y-axis, it makes more sense to me that the embedding space is \"wrapped\" and doesn't have an end.\n"," 1. We are also able to use this spherical projection with haversine distance to develop clusters derived from the spherical projection rather than the planar projection."]},{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["import altair as alt\n","import numpy as np\n","import pandas as pd\n","import plotly.express as px\n","from hdbscan import HDBSCAN\n","from sentence_transformers import SentenceTransformer\n","from umap import UMAP\n","import numba\n"]},{"cell_type":"code","execution_count":2,"metadata":{},"outputs":[],"source":["@numba.njit()\n","def tsss(vec1, vec2):\n"," euclidean_distance = np.linalg.norm(vec1 - vec2)\n"," cosine_distance = np.dot(vec1, vec2.T) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))\n"," magnitude_difference = abs(np.linalg.norm(vec1) - np.linalg.norm(vec2))\n"," theta = np.arccos(cosine_distance) + np.radians(10.0)\n"," triangle = (np.linalg.norm(vec1) * np.linalg.norm(vec2) * np.sin(theta)) / 2\n"," sector = np.pi * ((euclidean_distance + magnitude_difference) ** 2) * (np.degrees(theta) / 360)\n"," return triangle * sector\n"]},{"cell_type":"code","execution_count":3,"metadata":{},"outputs":[],"source":["df = (\n"," pd.read_csv(\"cleaned_hm.csv.xz\")\n"," .dropna(subset=[\"ground_truth_category\", \"cleaned_hm\"], how=\"any\")\n"," .drop_duplicates(subset=[\"cleaned_hm\"])\n"," .loc[:, [\"cleaned_hm\", \"ground_truth_category\"]]\n"," .reset_index(drop=True)\n",")\n"]},{"cell_type":"code","execution_count":4,"metadata":{},"outputs":[],"source":["model = SentenceTransformer(\"paraphrase-distilroberta-base-v1\")\n","\n"]},{"cell_type":"code","execution_count":5,"metadata":{},"outputs":[{"name":"stderr","output_type":"stream","text":["Batches: 100%|██████████| 199/199 [05:54<00:00, 1.78s/it]\n"]}],"source":["docs = df[\"cleaned_hm\"].str.lower().tolist()\n","embeddings = model.encode(docs, show_progress_bar=True, device=\"cpu\", batch_size=64)\n"]},{"cell_type":"code","execution_count":6,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["UMAP(dens_frac=0.0, dens_lambda=0.0,\n"," metric=CPUDispatcher(), min_dist=0.0,\n"," n_neighbors=30, random_state=1234, verbose=True)\n","Construct fuzzy simplicial set\n","Fri Jan 29 08:42:42 2021 Finding Nearest Neighbors\n","Fri Jan 29 08:42:42 2021 Building RP forest with 11 trees\n","Fri Jan 29 08:42:43 2021 NN descent for 14 iterations\n","\t 1 / 14\n","\t 2 / 14\n","\t 3 / 14\n","\t 4 / 14\n","\tStopping threshold met -- exiting after 4 iterations\n","Fri Jan 29 08:44:31 2021 Finished Nearest Neighbor Search\n","Fri Jan 29 08:44:34 2021 Construct embedding\n","\tcompleted 0 / 200 epochs\n","\tcompleted 20 / 200 epochs\n","\tcompleted 40 / 200 epochs\n","\tcompleted 60 / 200 epochs\n","\tcompleted 80 / 200 epochs\n","\tcompleted 100 / 200 epochs\n","\tcompleted 120 / 200 epochs\n","\tcompleted 140 / 200 epochs\n","\tcompleted 160 / 200 epochs\n","\tcompleted 180 / 200 epochs\n","Fri Jan 29 08:44:44 2021 Finished embedding\n"]}],"source":["umap = UMAP(min_dist=0.00, n_neighbors=30, metric=tsss, random_state=1234, verbose=True)\n","embeddings_umap = umap.fit_transform(embeddings)\n"]},{"cell_type":"code","execution_count":7,"metadata":{},"outputs":[],"source":["embeddings_df = pd.DataFrame()\n","embeddings_df[\"Document\"] = docs\n","embeddings_df[\"Component 1\"] = embeddings_umap[:, 0]\n","embeddings_df[\"Component 2\"] = embeddings_umap[:, 1]\n","embeddings_df[\"Ground Truth\"] = df[\"ground_truth_category\"]\n"]},{"cell_type":"code","execution_count":8,"metadata":{},"outputs":[],"source":["hdbscan = HDBSCAN(cluster_selection_method=\"leaf\")\n","\n"]},{"cell_type":"code","execution_count":9,"metadata":{},"outputs":[],"source":["clusters = hdbscan.fit_predict(embeddings_umap)\n","embeddings_df[\"Cluster\"] = clusters\n"]},{"cell_type":"code","execution_count":10,"metadata":{},"outputs":[{"data":{"text/plain":"DataTransformerRegistry.enable('default')"},"execution_count":10,"metadata":{},"output_type":"execute_result"}],"source":["alt.data_transformers.disable_max_rows()\n"]},{"cell_type":"code","execution_count":11,"metadata":{},"outputs":[],"source":["chart = (\n"," (\n"," alt.Chart(\n"," embeddings_df,\n"," height=1000,\n"," width=1000,\n"," title=\"Happy Moments - SBERT → UMAP (TSSS) → HDBSCAN\",\n"," )\n"," .mark_point()\n"," .encode(\n"," x=alt.X(\"Component 1\", axis=None),\n"," y=alt.Y(\"Component 2\", axis=None),\n"," tooltip=[\"Document\", \"Cluster\", \"Ground Truth\"],\n"," color=\"Cluster:N\",\n"," )\n"," )\n"," .configure_axis(grid=False)\n"," .configure_view(strokeWidth=0)\n"," .interactive()\n",")\n"]},{"cell_type":"code","execution_count":12,"metadata":{},"outputs":[],"source":["chart.save(\"docs/nlp-sbert-umap-tsss-hdbscan-chart.html\")\n"]},{"cell_type":"code","execution_count":13,"metadata":{},"outputs":[{"name":"stdout","output_type":"stream","text":["UMAP(dens_frac=0.0, dens_lambda=0.0,\n"," metric=CPUDispatcher(), min_dist=0.0,\n"," n_neighbors=30, output_metric='haversine', random_state=42, verbose=True)\n","Construct fuzzy simplicial set\n","Fri Jan 29 08:44:44 2021 Finding Nearest Neighbors\n","Fri Jan 29 08:44:44 2021 Building RP forest with 11 trees\n","Fri Jan 29 08:44:45 2021 NN descent for 14 iterations\n","\t 1 / 14\n","\t 2 / 14\n","\t 3 / 14\n","\t 4 / 14\n","\tStopping threshold met -- exiting after 4 iterations\n","Fri Jan 29 08:46:24 2021 Finished Nearest Neighbor Search\n","Fri Jan 29 08:46:24 2021 Construct embedding\n","\tcompleted 0 / 200 epochs\n","\tcompleted 20 / 200 epochs\n","\tcompleted 40 / 200 epochs\n","\tcompleted 60 / 200 epochs\n","\tcompleted 80 / 200 epochs\n","\tcompleted 100 / 200 epochs\n","\tcompleted 120 / 200 epochs\n","\tcompleted 140 / 200 epochs\n","\tcompleted 160 / 200 epochs\n","\tcompleted 180 / 200 epochs\n","Fri Jan 29 08:47:33 2021 Finished embedding\n"]}],"source":["sphere_mapper = UMAP(\n"," min_dist=0.00,\n"," n_neighbors=30,\n"," metric=tsss,\n"," output_metric=\"haversine\",\n"," random_state=42,\n"," verbose=True,\n",")\n","umap_sphere_embeddings = sphere_mapper.fit_transform(embeddings)\n","\n","e1, e2 = umap_sphere_embeddings[:, 0], umap_sphere_embeddings[:, 1]\n","\n","x = np.sin(e1) * np.cos(e2)\n","y = np.sin(e1) * np.sin(e2)\n","z = np.cos(e1)\n","\n","embeddings_df[\"Sphere Embedding X\"] = x\n","embeddings_df[\"Sphere Embedding Y\"] = y\n","embeddings_df[\"Sphere Embedding Z\"] = z\n","\n","embeddings_df[\"2D Sphere Projection X\"] = np.arctan2(x, y)\n","embeddings_df[\"2D Sphere Projection Y\"] = -np.arccos(z)\n"]},{"cell_type":"code","execution_count":14,"metadata":{},"outputs":[],"source":["hdbscan_sphere = HDBSCAN(cluster_selection_method=\"eom\", metric=\"haversine\")\n","clusters_sphere = hdbscan_sphere.fit_predict(\n"," np.radians(embeddings_df[[\"2D Sphere Projection X\", \"2D Sphere Projection Y\"]].values)\n",")\n","embeddings_df[\"Cluster Sphere\"] = clusters_sphere\n","embeddings_df[\"Cluster Sphere (str)\"] = embeddings_df[\"Cluster Sphere\"].astype(str)\n"]},{"cell_type":"code","execution_count":15,"metadata":{},"outputs":[],"source":["fig = px.scatter(\n"," embeddings_df,\n"," x=\"2D Sphere Projection X\",\n"," y=\"2D Sphere Projection Y\",\n"," color=\"Cluster Sphere (str)\",\n"," hover_data=[\"Document\", \"Cluster Sphere\", \"Ground Truth\"],\n"," opacity=0.8,\n"," color_discrete_sequence=px.colors.qualitative.Alphabet,\n",")\n","\n","fig.write_html(\"docs/nlp-sbert-umap-hdbscan-tsss-sphere-2d.html\")\n"]},{"cell_type":"code","execution_count":16,"metadata":{},"outputs":[],"source":["fig = px.scatter_3d(\n"," embeddings_df,\n"," x=\"Sphere Embedding X\",\n"," y=\"Sphere Embedding Y\",\n"," z=\"Sphere Embedding Z\",\n"," color=\"Cluster Sphere (str)\",\n"," hover_data=[\"Document\", \"Cluster Sphere\", \"Ground Truth\"],\n"," color_discrete_sequence=px.colors.qualitative.Alphabet,\n"," opacity=0.8,\n",")\n","\n","camera = dict(up=dict(x=0, y=0, z=0), center=dict(x=0, y=0, z=0), eye=dict(x=0, y=0, z=0))\n","\n","fig.update_layout(\n"," scene_camera=camera,\n"," scene=dict(\n"," bgcolor=\"black\",\n"," xaxis=dict(\n"," showbackground=False,\n"," gridcolor=\"black\",\n"," zerolinecolor=\"black\",\n"," ),\n"," yaxis=dict(\n"," showbackground=False,\n"," gridcolor=\"black\",\n"," zerolinecolor=\"black\",\n"," ),\n"," zaxis=dict(\n"," showbackground=False,\n"," gridcolor=\"black\",\n"," zerolinecolor=\"black\",\n"," ),\n"," ),\n",")\n","\n","fig.write_html(\"docs/nlp-sbert-umap-tsss-hdbscan-sphere.html\")\n"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":[]}],"metadata":{"kernelspec":{"display_name":"Python 3.7.7 64-bit ('binder-notebooks': conda)","metadata":{"interpreter":{"hash":"71584da51981f72ec8f61ce2b9591b38d12385468c0adbe248ba9aa552e53946"}},"name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.7"},"orig_nbformat":2},"nbformat":4,"nbformat_minor":2} -------------------------------------------------------------------------------- /nlp-use-umap-hdbscan.ipynb: -------------------------------------------------------------------------------- 1 | {"cells":[{"cell_type":"code","execution_count":1,"metadata":{},"outputs":[],"source":["from itertools import chain\n","\n","import altair as alt\n","import pandas as pd\n","import tensorflow_hub as hub\n","from hdbscan import HDBSCAN\n","from IPython.display import display\n","from umap import UMAP"]},{"cell_type":"code","execution_count":2,"metadata":{},"outputs":[],"source":["df = (\n"," pd.read_csv(\"cleaned_hm.csv.xz\")\n"," .dropna(subset=[\"ground_truth_category\", \"cleaned_hm\"], how=\"any\")\n"," .loc[:, [\"cleaned_hm\", \"ground_truth_category\"]]\n"," .reset_index(drop=True)\n",")\n","\n",""]},{"cell_type":"code","execution_count":3,"metadata":{},"outputs":[],"source":["embed = hub.load(\"https://tfhub.dev/google/universal-sentence-encoder/4\")"]},{"cell_type":"code","execution_count":4,"metadata":{},"outputs":[],"source":["docs = df[\"cleaned_hm\"].tolist()\n","embeddings = embed(docs)"]},{"cell_type":"code","execution_count":5,"metadata":{},"outputs":[],"source":["umap = UMAP(min_dist=0.00, n_neighbors=30, metric=\"cosine\", random_state=1234)\n","embeddings_umap = umap.fit_transform(embeddings)"]},{"cell_type":"code","execution_count":6,"metadata":{},"outputs":[],"source":["embeddings_df = pd.DataFrame()\n","embeddings_df[\"Document\"] = docs\n","embeddings_df[\"Component 1\"] = embeddings_umap[:, 0]\n","embeddings_df[\"Component 2\"] = embeddings_umap[:, 1]\n","embeddings_df[\"Ground Truth\"] = df[\"ground_truth_category\"]"]},{"cell_type":"code","execution_count":7,"metadata":{},"outputs":[],"source":["hdbscan = HDBSCAN(cluster_selection_method=\"leaf\", min_cluster_size=len(embeddings_df) // 100)"]},{"cell_type":"code","execution_count":8,"metadata":{},"outputs":[],"source":["clusters = hdbscan.fit_predict(embeddings_umap)\n","embeddings_df[\"Cluster\"] = clusters"]},{"cell_type":"code","execution_count":9,"metadata":{},"outputs":[{"output_type":"execute_result","data":{"text/plain":"DataTransformerRegistry.enable('default')"},"metadata":{},"execution_count":9}],"source":["alt.data_transformers.disable_max_rows()"]},{"cell_type":"code","execution_count":10,"metadata":{},"outputs":[],"source":["chart = (\n"," (\n"," alt.Chart(\n"," embeddings_df,\n"," height=1000,\n"," width=1000,\n"," title=\"Happy Moments - USE → UMAP → HDBSCAN\",\n"," )\n"," .mark_point()\n"," .encode(\n"," x=alt.X(\"Component 1\", axis=None),\n"," y=alt.Y(\"Component 2\", axis=None),\n"," tooltip=[\"Document\", \"Cluster\", \"Ground Truth\"],\n"," color=\"Cluster:N\",\n"," shape=\"Ground Truth\"\n"," )\n"," )\n"," .configure_axis(grid=False)\n"," .configure_view(strokeWidth=0)\n"," .interactive()\n",")"]},{"cell_type":"code","execution_count":11,"metadata":{},"outputs":[],"source":["chart.save(\"docs/nlp-use-umap-hdbscan-chart.html\")"]},{"cell_type":"code","execution_count":12,"metadata":{},"outputs":[],"source":["exemplars = list(map(tuple, chain.from_iterable(hdbscan.exemplars_)))\n","\n","def exemplar(row):\n"," return (row[\"Component 1\"], row[\"Component 2\"]) in exemplars\n","\n","embeddings_df[\"Exemplar\"] = embeddings_df.apply(exemplar, axis=1)\n"]},{"cell_type":"code","execution_count":13,"metadata":{},"outputs":[{"output_type":"execute_result","data":{"text/plain":"False 10829\nTrue 3296\nName: Exemplar, dtype: int64"},"metadata":{},"execution_count":13}],"source":["embeddings_df[\"Exemplar\"].value_counts()"]},{"cell_type":"code","execution_count":14,"metadata":{},"outputs":[],"source":["grouped_df = embeddings_df.groupby(\"Cluster\")"]},{"cell_type":"code","execution_count":15,"metadata":{},"outputs":[],"source":["pd.set_option(\"display.max_colwidth\", 200)"]},{"cell_type":"code","execution_count":18,"metadata":{"tags":[]},"outputs":[{"output_type":"stream","name":"stdout","text":"No Cluster (outlier) \tN Total: 6831 (48.4%)\n-------------------------\nCluster: 0 \tN Total: 144 (1.0%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n606 I WENT TO MOVIE\n749 I WEND TO MOVIE\n750 I WENT TO MOVIE\n875 I WENT TO MOVIE\n877 I WENT TO MOVIE\n... ...\n13909 I WENT TO MOVIE\n13992 I WENT MOVIE\n13998 I WENT TO MOVIE\n14069 I WENT TO MOVIE\n14096 I saw a romantic comedy.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
606I WENT TO MOVIE
749I WEND TO MOVIE
750I WENT TO MOVIE
875I WENT TO MOVIE
877I WENT TO MOVIE
......
13909I WENT TO MOVIE
13992I WENT MOVIE
13998I WENT TO MOVIE
14069I WENT TO MOVIE
14096I saw a romantic comedy.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nleisure 144","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
leisure144
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 1 \tN Total: 153 (1.1%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n94 My cat snuggled with me while we slept.\n241 My cat cuddled with me when I went to sleep. \n256 I was able to take my cat out for a walk while the sky was clear.\n257 I played with my new kitten, we have only had him for 3 weeks!\n272 My friend sent me pictures of his cat.\n... ...\n13655 We found a stray cat and couldnt catch it but we fed it . that made me happy . \n13666 My wife found a kitten on her morning walk. She is really cute and my kids love her.\n13754 My cats came and cuddled with me, including the male the cat that does not like the cuddle much.\n13791 My son learned to meow like a cat. \n13808 An event that made me happy in the past 24 hours was petting my cats after feeding them this morning.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
94My cat snuggled with me while we slept.
241My cat cuddled with me when I went to sleep.
256I was able to take my cat out for a walk while the sky was clear.
257I played with my new kitten, we have only had him for 3 weeks!
272My friend sent me pictures of his cat.
......
13655We found a stray cat and couldnt catch it but we fed it . that made me happy .
13666My wife found a kitten on her morning walk. She is really cute and my kids love her.
13754My cats came and cuddled with me, including the male the cat that does not like the cuddle much.
13791My son learned to meow like a cat.
13808An event that made me happy in the past 24 hours was petting my cats after feeding them this morning.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\naffection 124\nenjoy_the_moment 11\nachievement 8\nbonding 5\nleisure 5","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
affection124
enjoy_the_moment11
achievement8
bonding5
leisure5
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 2 \tN Total: 159 (1.1%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n56 I bought a new phone\n97 I bought a new laptop.\n171 I picked up a new phone this afternoon with an Android operating system instead of the terrible Windows phone I have been using. \n337 I bought a new cell phone with latest features and specifications.\n401 I've got a new laptop and it works really well.\n... ...\n13545 I bought a new laptop.\n13683 I managed to install a new screen on a broken phone.\n13903 I bought a new laptop.\n13959 I was shopping for a new cell phone at Target and found out that I will receive a $200 gift card when I buy a new phone and activate service.\n14107 My smart phone was giving problems due to virus and I repaired my phone with a help of Internet videos. I am very happy with that because I am not a service engineer.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
56I bought a new phone
97I bought a new laptop.
171I picked up a new phone this afternoon with an Android operating system instead of the terrible Windows phone I have been using.
337I bought a new cell phone with latest features and specifications.
401I've got a new laptop and it works really well.
......
13545I bought a new laptop.
13683I managed to install a new screen on a broken phone.
13903I bought a new laptop.
13959I was shopping for a new cell phone at Target and found out that I will receive a $200 gift card when I buy a new phone and activate service.
14107My smart phone was giving problems due to virus and I repaired my phone with a help of Internet videos. I am very happy with that because I am not a service engineer.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nachievement 134\naffection 9\nenjoy_the_moment 8\nleisure 5\nbonding 3","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
achievement134
affection9
enjoy_the_moment8
leisure5
bonding3
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 3 \tN Total: 299 (2.1%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n114 My friend, Sheryl came over to visit me and my puppy. \n235 Spending time with my dogs outside made me happy. I love watching them play and having fun\n285 Both of my dogs and my toddler played together nicely outside while I enjoyed the nice sunny weather.\n521 I petted and played with a friend's beautiful dog (golden retriever).\n532 My dogs were all three vying for my attention by jumping at my feet and simultaneous giving me lots of doggy kisses.\n... ...\n13488 I was able to play with my parents' dog for the first time in a few weeks.\n13775 I took my dog on a drive around town and she seemed really happy about it.\n13783 My fiancee and our two dogs were all lying in bed comfortably. I watched them just lie there for a couple minutes before going to bed myself.\n13854 I was happy when my dog showed improvement with a new trick that I am trying to teach her when I worked on it with her this morning.\n14097 I was happy tonight coming home and seeing my dog wag his tail and give me big lick on the cheek after missing me while I was at work. \n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
114My friend, Sheryl came over to visit me and my puppy.
235Spending time with my dogs outside made me happy. I love watching them play and having fun
285Both of my dogs and my toddler played together nicely outside while I enjoyed the nice sunny weather.
521I petted and played with a friend's beautiful dog (golden retriever).
532My dogs were all three vying for my attention by jumping at my feet and simultaneous giving me lots of doggy kisses.
......
13488I was able to play with my parents' dog for the first time in a few weeks.
13775I took my dog on a drive around town and she seemed really happy about it.
13783My fiancee and our two dogs were all lying in bed comfortably. I watched them just lie there for a couple minutes before going to bed myself.
13854I was happy when my dog showed improvement with a new trick that I am trying to teach her when I worked on it with her this morning.
14097I was happy tonight coming home and seeing my dog wag his tail and give me big lick on the cheek after missing me while I was at work.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\naffection 246\nachievement 17\nbonding 17\nenjoy_the_moment 6\nleisure 5\nnature 4\nexercise 4","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
affection246
achievement17
bonding17
enjoy_the_moment6
leisure5
nature4
exercise4
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 4 \tN Total: 222 (1.6%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n109 I watched a wonderful movie that I have not seen in years. My family and I were thrilled.\n138 I watched a movie with my wife, and we both enjoyed it.\n430 I was able to see one of my most anticipated movies, Logan, starring Hugh Jackman.\n540 In the last 24 hours I was happy because I went to a movie theater and enjoyed a movie.\n696 There was a funny scene in a movie that I was seeing for the first time. \n... ...\n13425 today made me happy to invite my wife and my best childhood friend to watch a movie in the cinema.\n13682 My sister and I watched \"An Affair to Remember\" and really enjoyed watching it together.\n13773 I love watch movies with my wife in my bedroom \n13809 watched Bahubali movie with my friends\n13957 An event that made me happy is my lyrics as be selected for a movie. When my lyrics is played on the big screen it brings me proud movement. The Director and the Hero said if this lyrics is played...\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
109I watched a wonderful movie that I have not seen in years. My family and I were thrilled.
138I watched a movie with my wife, and we both enjoyed it.
430I was able to see one of my most anticipated movies, Logan, starring Hugh Jackman.
540In the last 24 hours I was happy because I went to a movie theater and enjoyed a movie.
696There was a funny scene in a movie that I was seeing for the first time.
......
13425today made me happy to invite my wife and my best childhood friend to watch a movie in the cinema.
13682My sister and I watched \"An Affair to Remember\" and really enjoyed watching it together.
13773I love watch movies with my wife in my bedroom
13809watched Bahubali movie with my friends
13957An event that made me happy is my lyrics as be selected for a movie. When my lyrics is played on the big screen it brings me proud movement. The Director and the Hero said if this lyrics is played...
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nleisure 96\naffection 70\nbonding 37\nenjoy_the_moment 15\nachievement 4","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
leisure96
affection70
bonding37
enjoy_the_moment15
achievement4
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 5 \tN Total: 179 (1.3%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n51 Watched a new episode of a show that I like. \n99 Watching Bob's Burgers streaming on Fox.\n131 I watched a particularly compelling episode of a show that I enjoy on Netflix.\n219 I saw that there was a new episode of Mindy Project and I was excited to watch it.\n228 I watched a TV show I like a lot.\n... ...\n13803 My favorite TV show is back on for a new season on AMC, and I can't wait to binge on it.\n13851 I managed to find time to catch up on Netflix series.\n13885 I was able to watch my favorite show, which I hadn't had time for in a while.\n13974 i watched the game of thrones trailer\n14078 I have a favorite tv show, and today a new episode which I did not realize was going to air, happened to come on.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
51Watched a new episode of a show that I like.
99Watching Bob's Burgers streaming on Fox.
131I watched a particularly compelling episode of a show that I enjoy on Netflix.
219I saw that there was a new episode of Mindy Project and I was excited to watch it.
228I watched a TV show I like a lot.
......
13803My favorite TV show is back on for a new season on AMC, and I can't wait to binge on it.
13851I managed to find time to catch up on Netflix series.
13885I was able to watch my favorite show, which I hadn't had time for in a while.
13974i watched the game of thrones trailer
14078I have a favorite tv show, and today a new episode which I did not realize was going to air, happened to come on.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nleisure 146\nenjoy_the_moment 13\naffection 13\nbonding 4\nachievement 3","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
leisure146
enjoy_the_moment13
affection13
bonding4
achievement3
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 6 \tN Total: 309 (2.2%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n122 Increased my max bench press this morning, heaviest I've ever lifted\n147 I went to the gym. Hitting a new personal record on the bench press made me more confident in my abilities. \n214 I completed a goal that I set for myself at the gym and it pumped me up for tomorrow. \n231 I went to the gym with a friend of mine who I hadn't seen in a long time.\n555 Getting to do yoga unexpectedly. \n... ...\n13447 I helped my friend Kyle create a workout regiment, he was really thankful. \n13456 I felt extra flexible today and was able to push into a deeper pose like I was Gumby.\n13734 I had a good workout.\n13843 I successfully rolled out the perpetual knots in my calves last night (after a week of work), and my posture and foot pain have improved drastically. \n14047 I exercise well today after a long time.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
122Increased my max bench press this morning, heaviest I've ever lifted
147I went to the gym. Hitting a new personal record on the bench press made me more confident in my abilities.
214I completed a goal that I set for myself at the gym and it pumped me up for tomorrow.
231I went to the gym with a friend of mine who I hadn't seen in a long time.
555Getting to do yoga unexpectedly.
......
13447I helped my friend Kyle create a workout regiment, he was really thankful.
13456I felt extra flexible today and was able to push into a deeper pose like I was Gumby.
13734I had a good workout.
13843I successfully rolled out the perpetual knots in my calves last night (after a week of work), and my posture and foot pain have improved drastically.
14047I exercise well today after a long time.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nachievement 154\nexercise 147\naffection 4\nbonding 3\nenjoy_the_moment 1","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
achievement154
exercise147
affection4
bonding3
enjoy_the_moment1
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 7 \tN Total: 222 (1.6%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n11 INDIA WON THE SERIES AGAINST AUSTRALIA MADE ME TO FEEL HAPPY\n52 A good win for my sports team\n123 I watched a Blackhawks game last night.\n210 The team I coach won its match today.\n273 I made plans with my brother to get together this weekend to watch the Final Four. My nephew could win $700, because he has Gonzaga beating Oregon in the championship game.\n... ...\n13440 I watched a basketball game.\n13445 I watched a double overtime game 7 in the Eastern Conference Hockey finals. \n13531 The Seattle Mariners won last night 6-4.\n13690 I was happy when the Mets came from behind to beat the Cubs.\n13715 The red sox won and I watched it with friends at a bar\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
11INDIA WON THE SERIES AGAINST AUSTRALIA MADE ME TO FEEL HAPPY
52A good win for my sports team
123I watched a Blackhawks game last night.
210The team I coach won its match today.
273I made plans with my brother to get together this weekend to watch the Final Four. My nephew could win $700, because he has Gonzaga beating Oregon in the championship game.
......
13440I watched a basketball game.
13445I watched a double overtime game 7 in the Eastern Conference Hockey finals.
13531The Seattle Mariners won last night 6-4.
13690I was happy when the Mets came from behind to beat the Cubs.
13715The red sox won and I watched it with friends at a bar
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nleisure 65\nachievement 51\nenjoy_the_moment 40\nbonding 38\naffection 20\nexercise 8","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
leisure65
achievement51
enjoy_the_moment40
bonding38
affection20
exercise8
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 8 \tN Total: 273 (1.9%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n20 I was able to play my video game that I enjoy the most quite a bit and that made me relaxed and happy.\n104 Did well in the videogame I was playing\\r\\n\n149 I completed a modification for a video game that I was able to release to the public.\n167 I found something unexpected in a video game I am playing.\n442 Started a new game that I have been waiting a long time to play.\n... ...\n13849 Completing valkyr prime in a video game.\n13956 A small event that made me happy in the past 24 hours was the release of a Nintendo game called arms.\n14040 I made a great scorekeeping spreadsheet for a game I play.\n14093 Purchasing and playing a new video game.\n14111 I was able to buy a really fun video game on sal at half price.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
20I was able to play my video game that I enjoy the most quite a bit and that made me relaxed and happy.
104Did well in the videogame I was playing\\r\\n
149I completed a modification for a video game that I was able to release to the public.
167I found something unexpected in a video game I am playing.
442Started a new game that I have been waiting a long time to play.
......
13849Completing valkyr prime in a video game.
13956A small event that made me happy in the past 24 hours was the release of a Nintendo game called arms.
14040I made a great scorekeeping spreadsheet for a game I play.
14093Purchasing and playing a new video game.
14111I was able to buy a really fun video game on sal at half price.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nleisure 125\nachievement 83\nbonding 40\naffection 13\nenjoy_the_moment 12","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
leisure125
achievement83
bonding40
affection13
enjoy_the_moment12
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 9 \tN Total: 224 (1.6%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n335 I'm finally about to buy a car. My savings just got their few days ago. Now I'm looking. It's exciting.\n438 i bought a new vehicle.\n726 I saw a really nice car on my way home, which is rare in my town.\n945 I m very happy when i first time drive my own gifted car.\n1159 It was so amazing I get my new car.\n... ...\n13227 Last day I got my new brand car.\n13301 My friend took my car to get an oil change for me.\n13581 I test-drove a new vehicle that I ended up really liking.\n13899 I BOUGHT A NEW CAR\n13981 I went and bought some new tires for my car.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
335I'm finally about to buy a car. My savings just got their few days ago. Now I'm looking. It's exciting.
438i bought a new vehicle.
726I saw a really nice car on my way home, which is rare in my town.
945I m very happy when i first time drive my own gifted car.
1159It was so amazing I get my new car.
......
13227Last day I got my new brand car.
13301My friend took my car to get an oil change for me.
13581I test-drove a new vehicle that I ended up really liking.
13899I BOUGHT A NEW CAR
13981I went and bought some new tires for my car.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nachievement 179\naffection 15\nenjoy_the_moment 14\nbonding 14\nleisure 2","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
achievement179
affection15
enjoy_the_moment14
bonding14
leisure2
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 10 \tN Total: 232 (1.6%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n17 After 3 long weeks of deep snow covered ground we finally had enough warm days in the Northeast for the snow to melt and I was able to start my day with a fantastic hike up the Appalachian trail t...\n81 I went for a walk early in the morning and air was clear and crisp.\n186 I stepped outside without a jacket today. The sun is shining and it finally feels a bit like spring!\n189 I picked up running again now that the winter weather has finally died down. I feel much better physically and emotionally because of it.\n287 The temperature today was 70 degrees and the sun was shining. I don't like cold weather so this was heaven for me.\n... ...\n13780 The wind blowing my hair while I stuck my head out of the car's window.\n13869 I read outside for hours in the sunshine. \n13939 There was a sudden shower of rain in our area.\n14027 It started to pour down rain and storm\n14041 I felt more comfortable due to the weather cooling down.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
17After 3 long weeks of deep snow covered ground we finally had enough warm days in the Northeast for the snow to melt and I was able to start my day with a fantastic hike up the Appalachian trail t...
81I went for a walk early in the morning and air was clear and crisp.
186I stepped outside without a jacket today. The sun is shining and it finally feels a bit like spring!
189I picked up running again now that the winter weather has finally died down. I feel much better physically and emotionally because of it.
287The temperature today was 70 degrees and the sun was shining. I don't like cold weather so this was heaven for me.
......
13780The wind blowing my hair while I stuck my head out of the car's window.
13869I read outside for hours in the sunshine.
13939There was a sudden shower of rain in our area.
14027It started to pour down rain and storm
14041I felt more comfortable due to the weather cooling down.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nnature 168\nenjoy_the_moment 19\nexercise 13\nachievement 10\naffection 9\nleisure 8\nbonding 5","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
nature168
enjoy_the_moment19
exercise13
achievement10
affection9
leisure8
bonding5
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 11 \tN Total: 205 (1.5%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n1 I meditated last night.\n120 I got a full night of sleep. That does not often happen with a 3 month-old in the house. \\r\\n\n169 I got to take a nap on the couch.\n213 I had an amazing dream this morning.\n480 When I jumped in bed at night after a fairly exhaustive day.\n... ...\n13846 I took a really nice nap while the air conditioner was on and woke up feeling very refreshed.\n13852 Getting a good night sleep made me happy.\n13970 I was able to get a great nights sleep.\n14063 I WAS SLEEPING IN LONG TIME. SO I FELT VERY RELAXED.\n14122 I woke up in the middle of the night and realizing that I still had another four hours of sleep left before having to get up.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
1I meditated last night.
120I got a full night of sleep. That does not often happen with a 3 month-old in the house. \\r\\n
169I got to take a nap on the couch.
213I had an amazing dream this morning.
480When I jumped in bed at night after a fairly exhaustive day.
......
13846I took a really nice nap while the air conditioner was on and woke up feeling very refreshed.
13852Getting a good night sleep made me happy.
13970I was able to get a great nights sleep.
14063I WAS SLEEPING IN LONG TIME. SO I FELT VERY RELAXED.
14122I woke up in the middle of the night and realizing that I still had another four hours of sleep left before having to get up.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nenjoy_the_moment 85\nleisure 53\nachievement 39\naffection 22\nexercise 5\nnature 1","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
enjoy_the_moment85
leisure53
achievement39
affection22
exercise5
nature1
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 12 \tN Total: 427 (3.0%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n14 A made quite the progress on an old rusty workbench I am restoring at the moment. With the new paint it looks like new.\n67 I managed to throw out a few items that were cluttering a room. I enjoyed the space I have after. \n91 I finally cleaned out my basement. \n157 A friend came over to help install an appliance. I was very happy I didn't have to pay a professional.\n174 I completed upgrading the switches in our house so everything looks much better.\n... ...\n13562 Cleaned the garage out.\n13685 I bought a new appliance for kitchen.\n13700 Got halfway done painting the guest bedroom.\n13944 I found a new, simple way to clean some things.\n14116 I made our new house that we just bought look better by getting things put away.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
14A made quite the progress on an old rusty workbench I am restoring at the moment. With the new paint it looks like new.
67I managed to throw out a few items that were cluttering a room. I enjoyed the space I have after.
91I finally cleaned out my basement.
157A friend came over to help install an appliance. I was very happy I didn't have to pay a professional.
174I completed upgrading the switches in our house so everything looks much better.
......
13562Cleaned the garage out.
13685I bought a new appliance for kitchen.
13700Got halfway done painting the guest bedroom.
13944I found a new, simple way to clean some things.
14116I made our new house that we just bought look better by getting things put away.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nachievement 331\nenjoy_the_moment 51\naffection 23\nleisure 11\nbonding 10\nnature 1","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
achievement331
enjoy_the_moment51
affection23
leisure11
bonding10
nature1
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 13 \tN Total: 148 (1.0%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n225 I was able to turn in the forbearance form for my student loans.\n446 That I finally paid off my hospital bills!\n583 I got my bills paid. \n648 I checked my bank account after I was paid via direct deposit, and made more than I thought I did.\n713 I finally completed the process of divesting from a big bank with unethical investing practices.\n... ...\n13587 I received a refund check from an account that I had at least 10 years ago and forgot that I had it.\n13619 I got a refund of $99.00 from an online newspaper which, three days ago, removed the same amount from my checking account.\n13649 My electric bill was $20 less than I expected.\n13796 I transferred money into my bank account.\n14090 I was supposed to send a payment to someone who made the payment on my behalf. It is mid-month and was difficult, but we managed to send the funds. This made me happy.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
225I was able to turn in the forbearance form for my student loans.
446That I finally paid off my hospital bills!
583I got my bills paid.
648I checked my bank account after I was paid via direct deposit, and made more than I thought I did.
713I finally completed the process of divesting from a big bank with unethical investing practices.
......
13587I received a refund check from an account that I had at least 10 years ago and forgot that I had it.
13619I got a refund of $99.00 from an online newspaper which, three days ago, removed the same amount from my checking account.
13649My electric bill was $20 less than I expected.
13796I transferred money into my bank account.
14090I was supposed to send a payment to someone who made the payment on my behalf. It is mid-month and was difficult, but we managed to send the funds. This made me happy.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nachievement 130\nenjoy_the_moment 9\naffection 6\nbonding 3","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
achievement130
enjoy_the_moment9
affection6
bonding3
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 14 \tN Total: 233 (1.6%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n106 I got done with a test that I had been nervous about taking. I think I did pretty good too.\n336 I bought several books for cheap that would allow me to study well for an upcoming test.\n347 My happiness had its complement when I was called to congratulate myself for my graduation of an intensive course of programming. I felt expert in technology.\n353 I got the invigilation duty for class X board exams this year. This is the first time get the duty after 19 years of work. This has given me a tremendous joy and satisfaction.\n421 I found out that I passed my qualifying exam at my graduate school, which was a huge hurdle I had to overcome and was very nervous about.\n... ...\n13207 when my test result was published\n13244 I was taking a quiz for my algebra course online, and I scored an 83%. I've never been great at math and my extra reading and practice is starting to pay off. I couldn't stop smiling, and I had to...\n13295 I was happy when I found out I got 88% on my quiz today.\n13540 I just completed my boating licence exam so now I can ride wave runners!\n13595 Passed my CPA Examination\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
106I got done with a test that I had been nervous about taking. I think I did pretty good too.
336I bought several books for cheap that would allow me to study well for an upcoming test.
347My happiness had its complement when I was called to congratulate myself for my graduation of an intensive course of programming. I felt expert in technology.
353I got the invigilation duty for class X board exams this year. This is the first time get the duty after 19 years of work. This has given me a tremendous joy and satisfaction.
421I found out that I passed my qualifying exam at my graduate school, which was a huge hurdle I had to overcome and was very nervous about.
......
13207when my test result was published
13244I was taking a quiz for my algebra course online, and I scored an 83%. I've never been great at math and my extra reading and practice is starting to pay off. I couldn't stop smiling, and I had to...
13295I was happy when I found out I got 88% on my quiz today.
13540I just completed my boating licence exam so now I can ride wave runners!
13595Passed my CPA Examination
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nachievement 221\nenjoy_the_moment 6\naffection 2\nbonding 2\nexercise 1\nleisure 1","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
achievement221
enjoy_the_moment6
affection2
bonding2
exercise1
leisure1
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 15 \tN Total: 1019 (7.2%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n92 My new boss appreciated the work i put in\n124 complete my pending job task today.\n150 I finally figured out how to properly install a program at work. \n159 I finished the work project I was working on today.\n170 I participated in a group task and felt valued in it, as if my skills were needed and appreciated. \n... ...\n13827 I completed a large assignment at work ahead of schedule.\n13844 I made a somewhat significant milestone in my job.\n13859 I finished a project at work that I had been trying to get done for a several months.\n13889 I finished a project at work.\n14051 Every month, I host breakfast with 10 employees from different levels and functions in our company a from creative to business development to data science to marketing; it's always a unique and fu...\n\n[194 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
92My new boss appreciated the work i put in
124complete my pending job task today.
150I finally figured out how to properly install a program at work.
159I finished the work project I was working on today.
170I participated in a group task and felt valued in it, as if my skills were needed and appreciated.
......
13827I completed a large assignment at work ahead of schedule.
13844I made a somewhat significant milestone in my job.
13859I finished a project at work that I had been trying to get done for a several months.
13889I finished a project at work.
14051Every month, I host breakfast with 10 employees from different levels and functions in our company a from creative to business development to data science to marketing; it's always a unique and fu...
\n

194 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nachievement 878\nenjoy_the_moment 64\nbonding 38\naffection 18\nleisure 17\nnature 2\nexercise 2","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
achievement878
enjoy_the_moment64
bonding38
affection18
leisure17
nature2
exercise2
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 16 \tN Total: 686 (4.9%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n323 My youngest son began to stand up holding on to an object. \n338 I was treating my sons family to Sunday lunch and I caught my very intelligent 16 year old grandson off guard and made him laugh.\n362 It made me happy when my infant son used baby sign language for the first time.\n386 My daughter started walking, and has gotten much better in the past few days.\n524 My baby smiled at me\n... ...\n13692 I felt happy when I took my daughter to her drum lesson and saw her smiling when I picked her up. She told me she had a great lesson and learned something new and she thanked me for taking her to ...\n13842 My younger son comforted my older son after he got hurt. He was demonstrating extreme empathy at only 6 years old.\n13965 MY son started taking his first steps\n13986 Two year old Kaarmikha, my daughter started talking some new words in her own language. Kissing me often and demanding her needs. Motherhood is the best thing in world.\n14030 I have a daughter and she is 3 years old. Today she had made some remarks which made feel very happy. Her talks really gives me a sense of joy.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
323My youngest son began to stand up holding on to an object.
338I was treating my sons family to Sunday lunch and I caught my very intelligent 16 year old grandson off guard and made him laugh.
362It made me happy when my infant son used baby sign language for the first time.
386My daughter started walking, and has gotten much better in the past few days.
524My baby smiled at me
......
13692I felt happy when I took my daughter to her drum lesson and saw her smiling when I picked her up. She told me she had a great lesson and learned something new and she thanked me for taking her to ...
13842My younger son comforted my older son after he got hurt. He was demonstrating extreme empathy at only 6 years old.
13965MY son started taking his first steps
13986Two year old Kaarmikha, my daughter started talking some new words in her own language. Kissing me often and demanding her needs. Motherhood is the best thing in world.
14030I have a daughter and she is 3 years old. Today she had made some remarks which made feel very happy. Her talks really gives me a sense of joy.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\naffection 603\nachievement 60\nbonding 13\nenjoy_the_moment 6\nleisure 3\nnature 1","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
affection603
achievement60
bonding13
enjoy_the_moment6
leisure3
nature1
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 17 \tN Total: 717 (5.1%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n10 i finally learned to cook chicken\\r\\n\n46 My job provided lunch and it was really good. \n71 I satisfied my many food cravings for dinner.\n113 I got Chinese food for dinner, it was good.\n127 I had cream of chicken soup for dinner. It made me feel a lot better because I have been sick. \n... ...\n13656 I had a great meal of grilled chicken, soup, and salad that was delicious. \n13741 I ate a nice lunch.\n13979 I eat good food.\n14021 I nan some chicken skewers with a delicious teriyaki sauce. I am always in my happy place when I man the grill.\n14108 I ate some delicious eggrolls that my mom made.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
10i finally learned to cook chicken\\r\\n
46My job provided lunch and it was really good.
71I satisfied my many food cravings for dinner.
113I got Chinese food for dinner, it was good.
127I had cream of chicken soup for dinner. It made me feel a lot better because I have been sick.
......
13656I had a great meal of grilled chicken, soup, and salad that was delicious.
13741I ate a nice lunch.
13979I eat good food.
14021I nan some chicken skewers with a delicious teriyaki sauce. I am always in my happy place when I man the grill.
14108I ate some delicious eggrolls that my mom made.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nenjoy_the_moment 299\nachievement 157\naffection 119\nleisure 101\nbonding 39\nnature 2","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
enjoy_the_moment299
achievement157
affection119
leisure101
bonding39
nature2
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 18 \tN Total: 168 (1.2%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n48 I made vacation plans with my daughter today for Florida in July.\n233 I am planning another trip upcoming in August. This one is a week-long trip in Colorado. Planning makes me so excited. I love seeing everything coming together and falling into place. I will proba...\n340 I traveled to a state I had never been before.\n383 I found out that I had enough money to take a vacation this summer to the Caribbean!\n388 I successfully learned how to hover in a helicopter. \n... ...\n12992 yesterday night i came to trichy to erode is very nice travel and thankful to god nice moment\n13168 I went my friend's with beach and it is very entertaining one.\n13532 We went to a meeting to finalize plans for my daughter to travel to Spain.\n13806 I booked a weekend trip with my friends to the beach.\n13907 LAST SUMMER HOLIDAYS WAS AN UNFORGETTABLE EXPERIENCE. NT FRIEND ALWAYS ENJOYED MANY places. WE ENJOYED OUR EXCURSION WITH ENJOY AND BEAUTIFUL.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
48I made vacation plans with my daughter today for Florida in July.
233I am planning another trip upcoming in August. This one is a week-long trip in Colorado. Planning makes me so excited. I love seeing everything coming together and falling into place. I will proba...
340I traveled to a state I had never been before.
383I found out that I had enough money to take a vacation this summer to the Caribbean!
388I successfully learned how to hover in a helicopter.
......
12992yesterday night i came to trichy to erode is very nice travel and thankful to god nice moment
13168I went my friend's with beach and it is very entertaining one.
13532We went to a meeting to finalize plans for my daughter to travel to Spain.
13806I booked a weekend trip with my friends to the beach.
13907LAST SUMMER HOLIDAYS WAS AN UNFORGETTABLE EXPERIENCE. NT FRIEND ALWAYS ENJOYED MANY places. WE ENJOYED OUR EXCURSION WITH ENJOY AND BEAUTIFUL.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\naffection 57\nachievement 32\nbonding 27\nleisure 26\nenjoy_the_moment 23\nnature 3","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
affection57
achievement32
bonding27
leisure26
enjoy_the_moment23
nature3
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 19 \tN Total: 173 (1.2%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n2 My grandmother start to walk from the bed after a long time.\n66 After a long time, today my cousin came home surprisingly that made my day !\n314 Going home to see my family after being gone for college.\n706 My parents trying to be super supportive even if their ideas weren't always helpful because I could see how much they cared.\n842 YESTERDAY I WAS GONE FOR MY RELATIVE FUNCTION, BECAUSE MEET MY ALL RELATIVES.\n... ...\n13216 I got to see my grandma after 5 months of her vacation. \n13359 I was happy when I talked to my parents earlier this morning. \n13395 Came home to find my parents at my house for a quick visit.\n13798 Yesterday I found out my sister is coming to visit me this weekend, and that made me happy.\n14123 Yesterday my relations came to my house. That time am very happy to saw them\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
2My grandmother start to walk from the bed after a long time.
66After a long time, today my cousin came home surprisingly that made my day !
314Going home to see my family after being gone for college.
706My parents trying to be super supportive even if their ideas weren't always helpful because I could see how much they cared.
842YESTERDAY I WAS GONE FOR MY RELATIVE FUNCTION, BECAUSE MEET MY ALL RELATIVES.
......
13216I got to see my grandma after 5 months of her vacation.
13359I was happy when I talked to my parents earlier this morning.
13395Came home to find my parents at my house for a quick visit.
13798Yesterday I found out my sister is coming to visit me this weekend, and that made me happy.
14123Yesterday my relations came to my house. That time am very happy to saw them
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\naffection 168\nachievement 2\nenjoy_the_moment 2\nbonding 1","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
affection168
achievement2
enjoy_the_moment2
bonding1
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 20 \tN Total: 492 (3.5%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n79 I talked to my girlfriend recently and she told me that she loved me.\n129 Picking up my girlfriend from the airport since I hadn't seen her for two weeks.\n212 I saw my boyfriend again after being apart for a month.\n278 I got my bff to stop yelling at me all the time because her boyfriend is a dick\n502 My lover presented one precious gift to me made very happy.\n... ...\n13671 My boyfriend unexpectedly surprised me by visiting at my parents' house where I am dogsitting. I wasn't expecting to see him last night, but he came by anyway!\n13699 Met my girlfriend after 15 days.\n13874 I got to spend the evening with my boyfriend.\n13893 I came to a ton of conclusions which all amounted to if he loved me, he would show me, consistently, the way I wanted to be shown love. Simple things like love letters, flowers, romantic date nigh...\n14124 Cuddling with my girlfriend last night.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
79I talked to my girlfriend recently and she told me that she loved me.
129Picking up my girlfriend from the airport since I hadn't seen her for two weeks.
212I saw my boyfriend again after being apart for a month.
278I got my bff to stop yelling at me all the time because her boyfriend is a dick
502My lover presented one precious gift to me made very happy.
......
13671My boyfriend unexpectedly surprised me by visiting at my parents' house where I am dogsitting. I wasn't expecting to see him last night, but he came by anyway!
13699Met my girlfriend after 15 days.
13874I got to spend the evening with my boyfriend.
13893I came to a ton of conclusions which all amounted to if he loved me, he would show me, consistently, the way I wanted to be shown love. Simple things like love letters, flowers, romantic date nigh...
14124Cuddling with my girlfriend last night.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\naffection 457\nbonding 21\nachievement 8\nenjoy_the_moment 4\nleisure 2","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
affection457
bonding21
achievement8
enjoy_the_moment4
leisure2
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 21 \tN Total: 163 (1.2%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n26 I finally decorated my son's room for his birthday.\n57 I got to see a very good old friend that came over at my daughter's birthday.\n117 I helped plan a surprise party for my Mom's 70th birthday party coming up. \n328 Yesterday was my birthday and usually I am not honored or get more than a general happy birthday from my family and friends. But my boyfriend stayed up until one minute after midnight the night b...\n350 My husband and me fighting we are not celebrating my birthday \n... ...\n13483 My middle son's birthday was this week and he was so anxious and excited about it.\n13493 It was my son's birthday and we had a party for him.\n13990 when my nephew got celebrate his birthday\n14033 I have celebrated my mom's birthday today with my family and friends and that made me very happy.\n14064 I CELEBRATED MY SON BIRTHDAY.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
26I finally decorated my son's room for his birthday.
57I got to see a very good old friend that came over at my daughter's birthday.
117I helped plan a surprise party for my Mom's 70th birthday party coming up.
328Yesterday was my birthday and usually I am not honored or get more than a general happy birthday from my family and friends. But my boyfriend stayed up until one minute after midnight the night b...
350My husband and me fighting we are not celebrating my birthday
......
13483My middle son's birthday was this week and he was so anxious and excited about it.
13493It was my son's birthday and we had a party for him.
13990when my nephew got celebrate his birthday
14033I have celebrated my mom's birthday today with my family and friends and that made me very happy.
14064I CELEBRATED MY SON BIRTHDAY.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\naffection 105\nbonding 36\nenjoy_the_moment 18\nachievement 2\nleisure 2","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
affection105
bonding36
enjoy_the_moment18
achievement2
leisure2
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\nCluster: 22 \tN Total: 447 (3.2%)\nCluster Exemplars: \n"},{"output_type":"display_data","data":{"text/plain":" Document\n64 i met my old friends after 5 years.we all had a talk for half a day.we played football like my old days.\n93 I saw some friends that I had not seen in a while and it was good to reconnect. \n300 I spent some time with a close friend.\n354 I met with my school friends and enjoyed a lot.\n355 I got to see one of my friends that I havent seen in a long time and we got to catch up.\n... ...\n13718 Today I meet my childhood friends.\n13745 Visit my best friend\n13771 A friend called me and we caught up on a lot of things.\n13839 I got to see my best friend for the first time in over a month. I've really missed her - like missing a part of myself (my better half practically.)\n13881 My friend came over to visit.\n\n[141 rows x 1 columns]","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Document
64i met my old friends after 5 years.we all had a talk for half a day.we played football like my old days.
93I saw some friends that I had not seen in a while and it was good to reconnect.
300I spent some time with a close friend.
354I met with my school friends and enjoyed a lot.
355I got to see one of my friends that I havent seen in a long time and we got to catch up.
......
13718Today I meet my childhood friends.
13745Visit my best friend
13771A friend called me and we caught up on a lot of things.
13839I got to see my best friend for the first time in over a month. I've really missed her - like missing a part of myself (my better half practically.)
13881My friend came over to visit.
\n

141 rows × 1 columns

\n
"},"metadata":{}},{"output_type":"display_data","data":{"text/plain":" Ground Truth\nbonding 415\naffection 12\nachievement 9\nenjoy_the_moment 7\nleisure 4","text/html":"
\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Ground Truth
bonding415
affection12
achievement9
enjoy_the_moment7
leisure4
\n
"},"metadata":{}},{"output_type":"stream","name":"stdout","text":"-------------------------\n"}],"source":["for key, item in grouped_df:\n"," n = len(grouped_df.get_group(key))\n"," if key == -1:\n"," print(f\"No Cluster (outlier) \\tN Total: {n} ({(n/len(embeddings_df)) * 100:.1f}%)\")\n"," print(\"-----\" * 5)\n"," continue\n"," print(f\"Cluster: {key} \\tN Total: {n} ({(n/len(embeddings_df)) * 100:.1f}%)\")\n"," print(\"Cluster Exemplars: \")\n"," display(grouped_df.get_group(key).query(\"Exemplar\")[\"Document\"].to_frame())\n"," display(grouped_df.get_group(key)[\"Ground Truth\"].value_counts().to_frame())\n"," print(\"-----\" * 5)"]},{"cell_type":"code","execution_count":null,"metadata":{},"outputs":[],"source":[]}],"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.5-final"},"orig_nbformat":2,"kernelspec":{"name":"python37564bitanalysisconda0307f525ce98408fa0d9c21d055c6dba","display_name":"Python 3.7.5 64-bit ('analysis': conda)"}},"nbformat":4,"nbformat_minor":2} -------------------------------------------------------------------------------- /pipfreeze.sh: -------------------------------------------------------------------------------- 1 | pip freeze > binder/requirements.txt 2 | grep -v "en-core-web" binder/requirements.txt > requirements; mv requirements binder/requirements.txt 3 | grep -v "certifi" binder/requirements.txt > requirements; mv requirements binder/requirements.txt 4 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Notebooks 2 | 3 | [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/pmbaumgartner/binder-notebooks/master) 4 | 5 | These are notebooks for some of the longer workflows I've developed. You can launch them with [Binder](https://mybinder.org/v2/gh/pmbaumgartner/binder-notebooks/master)! 6 | 7 | If you want to replicate these notebooks locally, there is a `requirements.txt` file is in the `binder` folder. Use this to install the required packages into a virtual environment. 8 | 9 | Note that some notebooks are nondeterministic because I failed to set a random seed at some points. Thus, the exact results you get might differ from what you see in the notebooks if you run them again. -------------------------------------------------------------------------------- /roc_colored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmbaumgartner/binder-notebooks/cfee899187c9ba5e7a11a5b26fb37aa78cbc1201/roc_colored.png --------------------------------------------------------------------------------