tmplot 0.1.3__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tmplot-0.1.3/src/tmplot.egg-info → tmplot-0.3.0}/PKG-INFO +88 -54
- tmplot-0.3.0/README.md +131 -0
- {tmplot-0.1.3 → tmplot-0.3.0}/src/tmplot/__init__.py +1 -1
- {tmplot-0.1.3 → tmplot-0.3.0}/src/tmplot/_distance.py +71 -54
- {tmplot-0.1.3 → tmplot-0.3.0}/src/tmplot/_helpers.py +56 -24
- {tmplot-0.1.3 → tmplot-0.3.0}/src/tmplot/_report.py +7 -2
- {tmplot-0.1.3 → tmplot-0.3.0}/src/tmplot/_stability.py +32 -21
- {tmplot-0.1.3 → tmplot-0.3.0}/src/tmplot/_vis.py +120 -103
- {tmplot-0.1.3 → tmplot-0.3.0/src/tmplot.egg-info}/PKG-INFO +88 -54
- tmplot-0.1.3/README.md +0 -98
- {tmplot-0.1.3 → tmplot-0.3.0}/LICENSE +0 -0
- {tmplot-0.1.3 → tmplot-0.3.0}/MANIFEST.in +0 -0
- {tmplot-0.1.3 → tmplot-0.3.0}/pyproject.toml +0 -0
- {tmplot-0.1.3 → tmplot-0.3.0}/setup.cfg +0 -0
- {tmplot-0.1.3 → tmplot-0.3.0}/src/tmplot/_metrics.py +0 -0
- {tmplot-0.1.3 → tmplot-0.3.0}/src/tmplot.egg-info/SOURCES.txt +0 -0
- {tmplot-0.1.3 → tmplot-0.3.0}/src/tmplot.egg-info/dependency_links.txt +0 -0
- {tmplot-0.1.3 → tmplot-0.3.0}/src/tmplot.egg-info/requires.txt +0 -0
- {tmplot-0.1.3 → tmplot-0.3.0}/src/tmplot.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: tmplot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Visualization of Topic Modeling Results
|
|
5
5
|
Author-email: Maksim Terpilovskii <maximtrp@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -55,6 +55,7 @@ Provides-Extra: models
|
|
|
55
55
|
Requires-Dist: tomotopy>=0.8.0; extra == "models"
|
|
56
56
|
Requires-Dist: gensim; extra == "models"
|
|
57
57
|
Requires-Dist: bitermplus; extra == "models"
|
|
58
|
+
Dynamic: license-file
|
|
58
59
|
|
|
59
60
|
# tmplot
|
|
60
61
|
|
|
@@ -66,35 +67,46 @@ Requires-Dist: bitermplus; extra == "models"
|
|
|
66
67
|
[](https://pypi.org/project/tmplot)
|
|
67
68
|
[](https://github.com/maximtrp/tmplot/issues)
|
|
68
69
|
|
|
69
|
-
**tmplot** is a Python package for
|
|
70
|
+
**tmplot** is a comprehensive Python package for **topic modeling analysis and visualization**. Built for data scientists and researchers, it provides powerful interactive reports and advanced analytics that extend beyond traditional LDAvis/pyLDAvis capabilities.
|
|
71
|
+
|
|
72
|
+
**Analyze** • **Visualize** • **Compare** multiple topic models with ease
|
|
70
73
|
|
|
71
74
|

|
|
72
75
|
|
|
73
|
-
## Features
|
|
76
|
+
## Key Features
|
|
77
|
+
|
|
78
|
+
### Interactive Visualization
|
|
79
|
+
|
|
80
|
+
- **Topic scatter plots** with customizable coordinates and sizing
|
|
81
|
+
- **Term probability charts** with relevance weighting
|
|
82
|
+
- **Document analysis** showing top documents per topic
|
|
83
|
+
- **Interactive reports** with real-time parameter adjustment
|
|
84
|
+
|
|
85
|
+
### Advanced Analytics
|
|
74
86
|
|
|
75
|
-
-
|
|
87
|
+
- **Topic stability analysis** across multiple model runs
|
|
88
|
+
- **Model comparison** with sophisticated distance metrics
|
|
89
|
+
- **Saliency calculations** for term importance
|
|
90
|
+
- **Entropy metrics** for model optimization
|
|
76
91
|
|
|
77
|
-
|
|
78
|
-
- [gensim](https://radimrehurek.com/gensim/): `LdaModel`, `LdaMulticore`
|
|
79
|
-
- [bitermplus](https://github.com/maximtrp/bitermplus): `BTM`
|
|
92
|
+
### Model Support
|
|
80
93
|
|
|
81
|
-
-
|
|
94
|
+
- **[tomotopy](https://bab2min.github.io/tomotopy/)**: `LDAModel`, `LLDAModel`, `CTModel`, `DMRModel`, `HDPModel`, `PTModel`, `SLDAModel`, `GDMRModel`
|
|
95
|
+
- **[gensim](https://radimrehurek.com/gensim/)**: `LdaModel`, `LdaMulticore`
|
|
96
|
+
- **[bitermplus](https://github.com/maximtrp/bitermplus)**: `BTM`
|
|
82
97
|
|
|
83
|
-
|
|
84
|
-
- Jenson-Shannon divergence
|
|
85
|
-
- Jeffrey's divergence
|
|
86
|
-
- Hellinger distance
|
|
87
|
-
- Bhattacharyya distance
|
|
88
|
-
- Total variation distance
|
|
89
|
-
- Jaccard inversed index
|
|
98
|
+
### Distance Metrics
|
|
90
99
|
|
|
91
|
-
-
|
|
100
|
+
- Kullback-Leibler (symmetric & non-symmetric)
|
|
101
|
+
- Jensen-Shannon divergence
|
|
102
|
+
- Jeffrey's divergence
|
|
103
|
+
- Hellinger & Bhattacharyya distances
|
|
104
|
+
- Total variation distance
|
|
105
|
+
- Jaccard index
|
|
92
106
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
- LocallyLinearEmbedding
|
|
97
|
-
- Isomap
|
|
107
|
+
### Dimensionality Reduction
|
|
108
|
+
|
|
109
|
+
t-SNE, SpectralEmbedding, MDS, LocallyLinearEmbedding, Isomap
|
|
98
110
|
|
|
99
111
|
## Donate
|
|
100
112
|
|
|
@@ -102,55 +114,77 @@ If you find this package useful, please consider donating any amount of money. T
|
|
|
102
114
|
|
|
103
115
|
<a href="https://www.buymeacoffee.com/maximtrp" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
|
|
104
116
|
|
|
105
|
-
##
|
|
117
|
+
## Quick Start
|
|
106
118
|
|
|
107
|
-
|
|
119
|
+
### Installation
|
|
108
120
|
|
|
109
121
|
```bash
|
|
122
|
+
# From PyPI (recommended)
|
|
110
123
|
pip install tmplot
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
Or directly from this repository:
|
|
114
124
|
|
|
115
|
-
|
|
125
|
+
# Development version
|
|
116
126
|
pip install git+https://github.com/maximtrp/tmplot.git
|
|
117
127
|
```
|
|
118
128
|
|
|
119
|
-
|
|
129
|
+
### Basic Usage
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
import tmplot as tmp
|
|
133
|
+
|
|
134
|
+
# Load your topic model and documents
|
|
135
|
+
model = your_fitted_model # tomotopy, gensim, or bitermplus
|
|
136
|
+
docs = your_documents
|
|
120
137
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
- `scikit-learn`
|
|
124
|
-
- `pandas`
|
|
125
|
-
- `altair`
|
|
126
|
-
- `ipywidgets`
|
|
127
|
-
- `tomotopy`, `gensim`, and `bitermplus` (optional)
|
|
138
|
+
# Create interactive report
|
|
139
|
+
tmp.report(model, docs=docs)
|
|
128
140
|
|
|
129
|
-
|
|
141
|
+
# Or create individual visualizations
|
|
142
|
+
coords = tmp.prepare_coords(model)
|
|
143
|
+
tmp.plot_scatter_topics(coords, size_col='size')
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Advanced Examples
|
|
147
|
+
|
|
148
|
+
### Get Stable Topics
|
|
130
149
|
|
|
131
150
|
```python
|
|
132
|
-
# Importing packages
|
|
133
151
|
import tmplot as tmp
|
|
134
|
-
import pickle as pkl
|
|
135
|
-
import pandas as pd
|
|
136
152
|
|
|
137
|
-
#
|
|
138
|
-
|
|
139
|
-
|
|
153
|
+
# Find stable topics across multiple models
|
|
154
|
+
models = [model1, model2, model3, model4]
|
|
155
|
+
closest_topics, distances = tmp.get_closest_topics(models)
|
|
156
|
+
stable_topics, stable_distances = tmp.get_stable_topics(closest_topics, distances)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Analyze Model
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
# Calculate entropy for model selection
|
|
163
|
+
entropy_score = tmp.entropy(phi_matrix)
|
|
140
164
|
|
|
141
|
-
#
|
|
142
|
-
|
|
165
|
+
# Analyze topic stability
|
|
166
|
+
saliency = tmp.get_salient_terms(phi, theta)
|
|
167
|
+
```
|
|
143
168
|
|
|
144
|
-
|
|
145
|
-
topics_coords = tmp.prepare_coords(model)
|
|
146
|
-
tmp.plot_scatter_topics(topics_coords, size_col='size', label_col='label')
|
|
169
|
+
### Visualize
|
|
147
170
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
tmp.
|
|
171
|
+
```python
|
|
172
|
+
# Create topic distance matrix with different metrics
|
|
173
|
+
topic_dists = tmp.get_topics_dist(phi, method='jensen-shannon')
|
|
151
174
|
|
|
152
|
-
#
|
|
153
|
-
tmp.
|
|
175
|
+
# Generate coordinates with custom algorithm
|
|
176
|
+
coords = tmp.get_topics_scatter(topic_dists, theta, method='tsne')
|
|
177
|
+
tmp.plot_scatter_topics(coords, topic=3) # Highlight topic 3
|
|
154
178
|
```
|
|
155
179
|
|
|
156
|
-
|
|
180
|
+
## Documentation & Examples
|
|
181
|
+
|
|
182
|
+
- [Complete Tutorial](https://tmplot.readthedocs.io/en/latest/tutorial.html) - Step-by-step guide
|
|
183
|
+
- [API Reference](https://tmplot.readthedocs.io/) - Full documentation
|
|
184
|
+
- [Example Notebooks](https://github.com/maximtrp/tmplot/tree/main/examples) - Jupyter examples
|
|
185
|
+
|
|
186
|
+
## Requirements
|
|
187
|
+
|
|
188
|
+
**Core dependencies:** `numpy`, `scipy`, `scikit-learn`, `pandas`, `altair`, `ipywidgets`
|
|
189
|
+
|
|
190
|
+
**Optional models:** `tomotopy`, `gensim`, `bitermplus`
|
tmplot-0.3.0/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# tmplot
|
|
2
|
+
|
|
3
|
+
[](https://app.codacy.com/gh/maximtrp/tmplot/coverage)
|
|
4
|
+
[](https://app.codacy.com/gh/maximtrp/tmplot)
|
|
5
|
+
[](https://github.com/maximtrp/tmplot/actions/workflows/python-package.yml)
|
|
6
|
+
[](https://tmplot.readthedocs.io/en/latest/?badge=latest)
|
|
7
|
+
[](https://pepy.tech/project/tmplot)
|
|
8
|
+
[](https://pypi.org/project/tmplot)
|
|
9
|
+
[](https://github.com/maximtrp/tmplot/issues)
|
|
10
|
+
|
|
11
|
+
**tmplot** is a comprehensive Python package for **topic modeling analysis and visualization**. Built for data scientists and researchers, it provides powerful interactive reports and advanced analytics that extend beyond traditional LDAvis/pyLDAvis capabilities.
|
|
12
|
+
|
|
13
|
+
**Analyze** • **Visualize** • **Compare** multiple topic models with ease
|
|
14
|
+
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
## Key Features
|
|
18
|
+
|
|
19
|
+
### Interactive Visualization
|
|
20
|
+
|
|
21
|
+
- **Topic scatter plots** with customizable coordinates and sizing
|
|
22
|
+
- **Term probability charts** with relevance weighting
|
|
23
|
+
- **Document analysis** showing top documents per topic
|
|
24
|
+
- **Interactive reports** with real-time parameter adjustment
|
|
25
|
+
|
|
26
|
+
### Advanced Analytics
|
|
27
|
+
|
|
28
|
+
- **Topic stability analysis** across multiple model runs
|
|
29
|
+
- **Model comparison** with sophisticated distance metrics
|
|
30
|
+
- **Saliency calculations** for term importance
|
|
31
|
+
- **Entropy metrics** for model optimization
|
|
32
|
+
|
|
33
|
+
### Model Support
|
|
34
|
+
|
|
35
|
+
- **[tomotopy](https://bab2min.github.io/tomotopy/)**: `LDAModel`, `LLDAModel`, `CTModel`, `DMRModel`, `HDPModel`, `PTModel`, `SLDAModel`, `GDMRModel`
|
|
36
|
+
- **[gensim](https://radimrehurek.com/gensim/)**: `LdaModel`, `LdaMulticore`
|
|
37
|
+
- **[bitermplus](https://github.com/maximtrp/bitermplus)**: `BTM`
|
|
38
|
+
|
|
39
|
+
### Distance Metrics
|
|
40
|
+
|
|
41
|
+
- Kullback-Leibler (symmetric & non-symmetric)
|
|
42
|
+
- Jensen-Shannon divergence
|
|
43
|
+
- Jeffrey's divergence
|
|
44
|
+
- Hellinger & Bhattacharyya distances
|
|
45
|
+
- Total variation distance
|
|
46
|
+
- Jaccard index
|
|
47
|
+
|
|
48
|
+
### Dimensionality Reduction
|
|
49
|
+
|
|
50
|
+
t-SNE, SpectralEmbedding, MDS, LocallyLinearEmbedding, Isomap
|
|
51
|
+
|
|
52
|
+
## Donate
|
|
53
|
+
|
|
54
|
+
If you find this package useful, please consider donating any amount of money. This will help me spend more time on supporting open-source software.
|
|
55
|
+
|
|
56
|
+
<a href="https://www.buymeacoffee.com/maximtrp" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
|
|
57
|
+
|
|
58
|
+
## Quick Start
|
|
59
|
+
|
|
60
|
+
### Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# From PyPI (recommended)
|
|
64
|
+
pip install tmplot
|
|
65
|
+
|
|
66
|
+
# Development version
|
|
67
|
+
pip install git+https://github.com/maximtrp/tmplot.git
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Basic Usage
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import tmplot as tmp
|
|
74
|
+
|
|
75
|
+
# Load your topic model and documents
|
|
76
|
+
model = your_fitted_model # tomotopy, gensim, or bitermplus
|
|
77
|
+
docs = your_documents
|
|
78
|
+
|
|
79
|
+
# Create interactive report
|
|
80
|
+
tmp.report(model, docs=docs)
|
|
81
|
+
|
|
82
|
+
# Or create individual visualizations
|
|
83
|
+
coords = tmp.prepare_coords(model)
|
|
84
|
+
tmp.plot_scatter_topics(coords, size_col='size')
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Advanced Examples
|
|
88
|
+
|
|
89
|
+
### Get Stable Topics
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
import tmplot as tmp
|
|
93
|
+
|
|
94
|
+
# Find stable topics across multiple models
|
|
95
|
+
models = [model1, model2, model3, model4]
|
|
96
|
+
closest_topics, distances = tmp.get_closest_topics(models)
|
|
97
|
+
stable_topics, stable_distances = tmp.get_stable_topics(closest_topics, distances)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Analyze Model
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
# Calculate entropy for model selection
|
|
104
|
+
entropy_score = tmp.entropy(phi_matrix)
|
|
105
|
+
|
|
106
|
+
# Analyze topic stability
|
|
107
|
+
saliency = tmp.get_salient_terms(phi, theta)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Visualize
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
# Create topic distance matrix with different metrics
|
|
114
|
+
topic_dists = tmp.get_topics_dist(phi, method='jensen-shannon')
|
|
115
|
+
|
|
116
|
+
# Generate coordinates with custom algorithm
|
|
117
|
+
coords = tmp.get_topics_scatter(topic_dists, theta, method='tsne')
|
|
118
|
+
tmp.plot_scatter_topics(coords, topic=3) # Highlight topic 3
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Documentation & Examples
|
|
122
|
+
|
|
123
|
+
- [Complete Tutorial](https://tmplot.readthedocs.io/en/latest/tutorial.html) - Step-by-step guide
|
|
124
|
+
- [API Reference](https://tmplot.readthedocs.io/) - Full documentation
|
|
125
|
+
- [Example Notebooks](https://github.com/maximtrp/tmplot/tree/main/examples) - Jupyter examples
|
|
126
|
+
|
|
127
|
+
## Requirements
|
|
128
|
+
|
|
129
|
+
**Core dependencies:** `numpy`, `scipy`, `scikit-learn`, `pandas`, `altair`, `ipywidgets`
|
|
130
|
+
|
|
131
|
+
**Optional models:** `tomotopy`, `gensim`, `bitermplus`
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
__all__ = [
|
|
2
|
-
|
|
3
|
-
from typing import Union, List
|
|
1
|
+
__all__ = ["get_topics_dist", "get_topics_scatter", "get_top_topic_words"]
|
|
2
|
+
from typing import Optional, Union, List
|
|
4
3
|
from itertools import combinations
|
|
5
|
-
from pandas import DataFrame
|
|
4
|
+
from pandas import DataFrame, Index
|
|
6
5
|
import numpy as np
|
|
7
6
|
from scipy.special import kl_div
|
|
8
7
|
from scipy.spatial import distance
|
|
9
8
|
from sklearn.manifold import (
|
|
10
|
-
TSNE,
|
|
9
|
+
TSNE,
|
|
10
|
+
Isomap,
|
|
11
|
+
LocallyLinearEmbedding,
|
|
12
|
+
MDS,
|
|
13
|
+
SpectralEmbedding,
|
|
14
|
+
)
|
|
11
15
|
from ._helpers import calc_topics_marg_probs
|
|
12
16
|
|
|
13
17
|
|
|
@@ -17,32 +21,38 @@ def _dist_klb(a1: np.ndarray, a2: np.ndarray):
|
|
|
17
21
|
|
|
18
22
|
|
|
19
23
|
def _dist_sklb(a1: np.ndarray, a2: np.ndarray):
|
|
20
|
-
dist = kl_div(a1, a2) + kl_div(
|
|
24
|
+
dist = kl_div(a1, a2) + kl_div(a2, a1)
|
|
21
25
|
return dist[np.isfinite(dist)].sum()
|
|
22
26
|
|
|
23
27
|
|
|
24
28
|
def _dist_jsd(a1: np.ndarray, a2: np.ndarray):
|
|
25
|
-
|
|
29
|
+
m = 0.5 * (a1 + a2)
|
|
30
|
+
dist = 0.5 * kl_div(a1, m) + 0.5 * kl_div(a2, m)
|
|
26
31
|
return dist[np.isfinite(dist)].sum()
|
|
27
32
|
|
|
28
33
|
|
|
29
34
|
def _dist_jef(a1: np.ndarray, a2: np.ndarray):
|
|
30
35
|
vals = (a1 - a2) * (np.log(a1) - np.log(a2))
|
|
31
|
-
vals[(vals <= 0) | ~np.isfinite(vals)] = 0.
|
|
36
|
+
vals[(vals <= 0) | ~np.isfinite(vals)] = 0.0
|
|
32
37
|
return vals.sum()
|
|
33
38
|
|
|
34
39
|
|
|
40
|
+
# Small value for numerical stability
|
|
41
|
+
EPSILON = 1e-64
|
|
42
|
+
|
|
43
|
+
|
|
35
44
|
def _dist_hel(a1: np.ndarray, a2: np.ndarray):
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
45
|
+
a1_safe = a1.copy()
|
|
46
|
+
a2_safe = a2.copy()
|
|
47
|
+
a1_safe[(a1_safe <= 0) | ~np.isfinite(a1_safe)] = EPSILON
|
|
48
|
+
a2_safe[(a2_safe <= 0) | ~np.isfinite(a2_safe)] = EPSILON
|
|
49
|
+
hel_val = distance.euclidean(np.sqrt(a1_safe), np.sqrt(a2_safe)) / np.sqrt(2)
|
|
40
50
|
return hel_val
|
|
41
51
|
|
|
42
52
|
|
|
43
53
|
def _dist_bhat(a1: np.ndarray, a2: np.ndarray):
|
|
44
54
|
pq = a1 * a2
|
|
45
|
-
pq[(pq <= 0) | ~np.isfinite(pq)] =
|
|
55
|
+
pq[(pq <= 0) | ~np.isfinite(pq)] = EPSILON
|
|
46
56
|
dist = -np.log(np.sum(np.sqrt(pq)))
|
|
47
57
|
return dist
|
|
48
58
|
|
|
@@ -52,9 +62,9 @@ def _dist_tv(a1: np.ndarray, a2: np.ndarray):
|
|
|
52
62
|
return dist
|
|
53
63
|
|
|
54
64
|
|
|
55
|
-
def _dist_jac(a1: np.ndarray, a2: np.ndarray,
|
|
56
|
-
a = np.argsort(a1)[
|
|
57
|
-
b = np.argsort(a2)[
|
|
65
|
+
def _dist_jac(a1: np.ndarray, a2: np.ndarray, top_words=100):
|
|
66
|
+
a = np.argsort(a1)[: -top_words - 1 : -1]
|
|
67
|
+
b = np.argsort(a2)[: -top_words - 1 : -1]
|
|
58
68
|
j_num = np.intersect1d(a, b, assume_unique=False).size
|
|
59
69
|
j_den = np.union1d(a, b).size
|
|
60
70
|
jac_val = 1 - j_num / j_den
|
|
@@ -62,9 +72,8 @@ def _dist_jac(a1: np.ndarray, a2: np.ndarray, top_words=100):
|
|
|
62
72
|
|
|
63
73
|
|
|
64
74
|
def get_topics_dist(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
**kwargs) -> np.ndarray:
|
|
75
|
+
phi: Union[np.ndarray, DataFrame], method: str = "sklb", **kwargs
|
|
76
|
+
) -> np.ndarray:
|
|
68
77
|
"""Finding closest topics in models.
|
|
69
78
|
|
|
70
79
|
Parameters
|
|
@@ -90,6 +99,14 @@ def get_topics_dist(
|
|
|
90
99
|
Topics distances matrix.
|
|
91
100
|
"""
|
|
92
101
|
phi_copy = np.array(phi)
|
|
102
|
+
|
|
103
|
+
if phi_copy.ndim != 2:
|
|
104
|
+
raise ValueError("phi must be a 2D array (words x topics)")
|
|
105
|
+
if np.any(phi_copy < 0):
|
|
106
|
+
raise ValueError("phi must contain non-negative probability values")
|
|
107
|
+
if not np.allclose(phi_copy.sum(axis=0), 1.0, atol=1e-6):
|
|
108
|
+
raise ValueError("phi columns must sum to 1 (probability distributions)")
|
|
109
|
+
|
|
93
110
|
topics_num = phi_copy.shape[1]
|
|
94
111
|
topics_pairs = combinations(range(topics_num), 2)
|
|
95
112
|
|
|
@@ -110,16 +127,18 @@ def get_topics_dist(
|
|
|
110
127
|
for i, j in topics_pairs:
|
|
111
128
|
_dist_func = dist_funcs.get(method, "sklb")
|
|
112
129
|
topics_dists[((i, j), (j, i))] = _dist_func(
|
|
113
|
-
phi_copy[:, i], phi_copy[:, j], **kwargs
|
|
130
|
+
phi_copy[:, i], phi_copy[:, j], **kwargs
|
|
131
|
+
)
|
|
114
132
|
|
|
115
133
|
return topics_dists
|
|
116
134
|
|
|
117
135
|
|
|
118
136
|
def get_topics_scatter(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
137
|
+
topic_dists: np.ndarray,
|
|
138
|
+
theta: np.ndarray,
|
|
139
|
+
method: str = "tsne",
|
|
140
|
+
method_kws: Optional[dict] = None,
|
|
141
|
+
) -> DataFrame:
|
|
123
142
|
"""Calculate topics coordinates for a scatter plot.
|
|
124
143
|
|
|
125
144
|
Parameters
|
|
@@ -146,52 +165,53 @@ def get_topics_scatter(
|
|
|
146
165
|
Topics scatter coordinates.
|
|
147
166
|
"""
|
|
148
167
|
if not method_kws:
|
|
149
|
-
method_kws = {
|
|
168
|
+
method_kws = {"n_components": 2}
|
|
150
169
|
|
|
151
|
-
if method ==
|
|
152
|
-
method_kws.setdefault(
|
|
153
|
-
method_kws.setdefault(
|
|
154
|
-
method_kws.setdefault(
|
|
155
|
-
'perplexity', min(50, max(topic_dists.shape[0] // 2, 1)))
|
|
170
|
+
if method == "tsne":
|
|
171
|
+
method_kws.setdefault("init", "pca")
|
|
172
|
+
method_kws.setdefault("learning_rate", "auto")
|
|
173
|
+
method_kws.setdefault("perplexity", min(50, max(topic_dists.shape[0] // 2, 1)))
|
|
156
174
|
transformer = TSNE(**method_kws)
|
|
157
175
|
|
|
158
|
-
elif method ==
|
|
159
|
-
method_kws.setdefault(
|
|
176
|
+
elif method == "sem":
|
|
177
|
+
method_kws.setdefault("affinity", "precomputed")
|
|
160
178
|
transformer = SpectralEmbedding(**method_kws)
|
|
161
179
|
|
|
162
|
-
elif method ==
|
|
163
|
-
method_kws.setdefault(
|
|
164
|
-
method_kws.setdefault(
|
|
180
|
+
elif method == "mds":
|
|
181
|
+
method_kws.setdefault("dissimilarity", "precomputed")
|
|
182
|
+
method_kws.setdefault("normalized_stress", "auto")
|
|
183
|
+
method_kws.setdefault("n_init", 1)
|
|
165
184
|
transformer = MDS(**method_kws)
|
|
166
185
|
|
|
167
|
-
elif method ==
|
|
168
|
-
method_kws[
|
|
186
|
+
elif method == "lle":
|
|
187
|
+
method_kws["method"] = "standard"
|
|
169
188
|
transformer = LocallyLinearEmbedding(**method_kws)
|
|
170
189
|
|
|
171
|
-
elif method ==
|
|
172
|
-
method_kws[
|
|
190
|
+
elif method == "ltsa":
|
|
191
|
+
method_kws["method"] = "ltsa"
|
|
173
192
|
transformer = LocallyLinearEmbedding(**method_kws)
|
|
174
193
|
|
|
175
|
-
elif method ==
|
|
194
|
+
elif method == "isomap":
|
|
176
195
|
transformer = Isomap(**method_kws)
|
|
177
196
|
|
|
178
197
|
coords = transformer.fit_transform(topic_dists)
|
|
179
198
|
|
|
180
|
-
topics_xy = DataFrame(coords, columns=[
|
|
181
|
-
topics_xy[
|
|
182
|
-
topics_xy[
|
|
183
|
-
size_sum = topics_xy[
|
|
199
|
+
topics_xy = DataFrame(coords, columns=Index(["x", "y"]))
|
|
200
|
+
topics_xy["topic"] = topics_xy.index.astype(int)
|
|
201
|
+
topics_xy["size"] = calc_topics_marg_probs(theta)
|
|
202
|
+
size_sum = topics_xy["size"].sum()
|
|
184
203
|
if size_sum > 0:
|
|
185
|
-
topics_xy[
|
|
204
|
+
topics_xy["size"] *= 100 / topics_xy["size"].sum()
|
|
186
205
|
else:
|
|
187
|
-
topics_xy[
|
|
206
|
+
topics_xy["size"] = np.nan
|
|
188
207
|
return topics_xy
|
|
189
208
|
|
|
190
209
|
|
|
191
210
|
def get_top_topic_words(
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
211
|
+
phi: DataFrame,
|
|
212
|
+
words_num: int = 20,
|
|
213
|
+
topics_idx: Optional[Union[List[int], np.ndarray]] = None,
|
|
214
|
+
) -> DataFrame:
|
|
195
215
|
"""Select top topic words from a fitted model.
|
|
196
216
|
|
|
197
217
|
Parameters
|
|
@@ -209,9 +229,6 @@ def get_top_topic_words(
|
|
|
209
229
|
DataFrame
|
|
210
230
|
Words with highest probabilities in all (or selected) topics.
|
|
211
231
|
"""
|
|
212
|
-
return phi.loc[:, topics_idx or phi.columns]
|
|
213
|
-
.
|
|
214
|
-
lambda x: x
|
|
215
|
-
.sort_values(ascending=False)
|
|
216
|
-
.head(words_num).index, axis=0
|
|
232
|
+
return phi.loc[:, topics_idx or phi.columns].apply(
|
|
233
|
+
lambda x: x.sort_values(ascending=False).head(words_num).index, axis=0
|
|
217
234
|
)
|