toponymy 0.2.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.
- toponymy-0.2.0/LICENSE +21 -0
- toponymy-0.2.0/PKG-INFO +242 -0
- toponymy-0.2.0/README.rst +222 -0
- toponymy-0.2.0/setup.cfg +56 -0
- toponymy-0.2.0/setup.py +4 -0
- toponymy-0.2.0/toponymy/__init__.py +11 -0
- toponymy-0.2.0/toponymy/cluster_layer.py +436 -0
- toponymy-0.2.0/toponymy/clustering.py +588 -0
- toponymy-0.2.0/toponymy/embedding_wrappers.py +172 -0
- toponymy-0.2.0/toponymy/exemplar_texts.py +193 -0
- toponymy-0.2.0/toponymy/keyphrases.py +747 -0
- toponymy-0.2.0/toponymy/llm_wrappers.py +682 -0
- toponymy-0.2.0/toponymy/prompt_construction.py +337 -0
- toponymy-0.2.0/toponymy/subtopics.py +230 -0
- toponymy-0.2.0/toponymy/templates.py +125 -0
- toponymy-0.2.0/toponymy/toponymy.py +268 -0
- toponymy-0.2.0/toponymy/utility_functions.py +56 -0
- toponymy-0.2.0/toponymy.egg-info/PKG-INFO +242 -0
- toponymy-0.2.0/toponymy.egg-info/SOURCES.txt +22 -0
- toponymy-0.2.0/toponymy.egg-info/dependency_links.txt +1 -0
- toponymy-0.2.0/toponymy.egg-info/not-zip-safe +1 -0
- toponymy-0.2.0/toponymy.egg-info/requires.txt +25 -0
- toponymy-0.2.0/toponymy.egg-info/top_level.txt +1 -0
toponymy-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Tutte Institute for Mathematics and Computing
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
toponymy-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: toponymy
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: A library for using large language models to name topics
|
|
5
|
+
Home-page: https://github.com/TutteInstitute/toponymy
|
|
6
|
+
Author: John Healy, Leland McInnes
|
|
7
|
+
Author-email: jchealy@gmail.com, leland.mcinnes@gmail.com
|
|
8
|
+
Maintainer: John Healy, Leland McInnes
|
|
9
|
+
Maintainer-email: jchealy@gmail.com, leland.mcinnes@gmail.com
|
|
10
|
+
License: MIT License
|
|
11
|
+
Keywords: topic modeing,representation,cluster,clustering,large language models,LLM,topic naming
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Requires-Python: >=3.9
|
|
18
|
+
Provides-Extra: dev
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
|
|
21
|
+
===========
|
|
22
|
+
Toponymy
|
|
23
|
+
===========
|
|
24
|
+
|
|
25
|
+
.. image:: doc/toponymy_text_horizontal.png
|
|
26
|
+
:width: 600
|
|
27
|
+
:align: center
|
|
28
|
+
:alt: Toponymy
|
|
29
|
+
|
|
30
|
+
The package name Toponymy is derived from the Greek topos ‘place’ + onuma ‘name’. Thus, the naming of places.
|
|
31
|
+
The goal of Toponymy is to put names to places in the space of information. This could be a corpus of documents,
|
|
32
|
+
in which case Toponymy can be viewed as a topic naming library. It could also be a collection of images, in which case
|
|
33
|
+
Toponymy could be used to name the themes of the images. The goal is to provide a names that can allow a user to
|
|
34
|
+
navigate through the space of information in a meaningful way.
|
|
35
|
+
|
|
36
|
+
Toponymy is designed to scale to very large corpora and collections, providing meaningful names on multiple scales,
|
|
37
|
+
from broad themes to fine-grained topics. We make use a custom clustering methods, information extraction,
|
|
38
|
+
and large language models to power this. The library is designed to be flexible and easy to use.
|
|
39
|
+
|
|
40
|
+
As of now this is an beta version of the library. Things can and will break right now.
|
|
41
|
+
We welcome feedback, use cases and feature suggestions.
|
|
42
|
+
|
|
43
|
+
------------------
|
|
44
|
+
Basic Installation
|
|
45
|
+
------------------
|
|
46
|
+
|
|
47
|
+
For now install the latest version of Toponymy from source you can do so by cloning the repository and running:
|
|
48
|
+
|
|
49
|
+
.. code-block:: bash
|
|
50
|
+
|
|
51
|
+
git clone https://github.com/TutteInstitute/toponymy
|
|
52
|
+
cd toponymy
|
|
53
|
+
pip install .
|
|
54
|
+
|
|
55
|
+
-----------
|
|
56
|
+
Basic Usage
|
|
57
|
+
-----------
|
|
58
|
+
|
|
59
|
+
We will need documents, document vectors and a low dimensional representation of these document vector to construct
|
|
60
|
+
a representation. This can be very expensive without a GPU so we recommend storing and reloading these vectors as
|
|
61
|
+
needed. For ease of experimentation we have precomputed and stored such vectors for the `20-Newsgroups dataset <http://qwone.com/~jason/20Newsgroups/>`_
|
|
62
|
+
on hugging face. Code to retrieve these vectors is below.
|
|
63
|
+
|
|
64
|
+
.. code-block:: python
|
|
65
|
+
|
|
66
|
+
pip install pandas
|
|
67
|
+
|
|
68
|
+
import numpy as np
|
|
69
|
+
import pandas as pd
|
|
70
|
+
newsgroups_df = pd.read_parquet("hf://datasets/lmcinnes/20newsgroups_embedded/data/train-00000-of-00001.parquet")
|
|
71
|
+
text = newsgroups_df["post"].str.strip().values
|
|
72
|
+
document_vectors = np.stack(newsgroups_df["embedding"].values)
|
|
73
|
+
document_map = np.stack(newsgroups_df["map"].values)
|
|
74
|
+
|
|
75
|
+
Toponymy also requires an embedding model for determining which of the documents will be most relevant to each
|
|
76
|
+
of our clusters. This doesn't have to be the embedding model that our documents were embedded with but it
|
|
77
|
+
should be similar.
|
|
78
|
+
|
|
79
|
+
.. code-block:: python
|
|
80
|
+
|
|
81
|
+
pip install sentence_transformers
|
|
82
|
+
|
|
83
|
+
from sentence_transformers import SentenceTransformer
|
|
84
|
+
embedding_model = SentenceTransformer("all-MiniLM-L6-v2")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
Once the low-dimensional representation is available (``document_map`` in this case), we can do the topic naming.
|
|
88
|
+
Toponymy will make use of a clusterer (such as ``ToponymyClusterer``) to create a balanced hierarchical layered
|
|
89
|
+
clustering of our documents. It will then use a variety of sampling and summarization techniques to construct prompts
|
|
90
|
+
describing each cluster to pass to a large language model (LLM). If you would like to experiment with testing
|
|
91
|
+
various cluster parameters in order construct cluster layers appropriate to your data feel free to cluster
|
|
92
|
+
your data ahead of time via:
|
|
93
|
+
|
|
94
|
+
.. code-block:: python
|
|
95
|
+
|
|
96
|
+
from toponymy import ToponymyClusterer
|
|
97
|
+
clusterer = ToponymyClusterer(min_clusters=4)
|
|
98
|
+
clusterer.fit(clusterable_vectors=document_map, embedding_vectors=document_vectors)
|
|
99
|
+
for i, layer in enumerate(clusterer.cluster_layers_):
|
|
100
|
+
print(f'{len(np.unique(layer.cluster_labels))-1} clusters in layer {i}')
|
|
101
|
+
|
|
102
|
+
428 clusters in layer 0
|
|
103
|
+
136 clusters in layer 1
|
|
104
|
+
42 clusters in layer 2
|
|
105
|
+
14 clusters in layer 3
|
|
106
|
+
5 clusters in layer 4
|
|
107
|
+
|
|
108
|
+
Toponymy supports multiple LLMs, including Cohere, OpenAI, and Anthropic via service calls, and local models via
|
|
109
|
+
Huggingface and LlamaCpp. Here we show an example using OpenAI. The following code will generate a topic naming
|
|
110
|
+
for the documents in the data set using an ``embedding_model``, ``document_vectors`` and ``document_map`` created above.
|
|
111
|
+
|
|
112
|
+
.. code-block:: python
|
|
113
|
+
|
|
114
|
+
from toponymy import Toponymy, KeyphraseBuilder
|
|
115
|
+
from toponymy.llm_wrappers import OpenAI
|
|
116
|
+
|
|
117
|
+
openai_api_key = open("openai_key.txt").read().strip()
|
|
118
|
+
llm = OpenAI('openai_api_key')
|
|
119
|
+
|
|
120
|
+
topic_model = Toponymy(
|
|
121
|
+
llm=llm,
|
|
122
|
+
embedding_model=embedding_model,
|
|
123
|
+
clusterer=clusterer,
|
|
124
|
+
object_description="newsgroup posts",
|
|
125
|
+
corpus_description="20-newsgroups dataset",
|
|
126
|
+
exemplar_delimiters=["<EXAMPLE_POST>\n","\n</EXAMPLE_POST>\n\n"],
|
|
127
|
+
)
|
|
128
|
+
topic_model.fit(text, document_vectors, document_map)
|
|
129
|
+
|
|
130
|
+
topic_names = topic_model.topic_names_
|
|
131
|
+
topics_per_document = topic_model.cluster_layers_
|
|
132
|
+
|
|
133
|
+
``topic_names`` is a list of lists which can be used to explore the unique topic names in each layer or resolution.
|
|
134
|
+
Let's examine the last two layers of topics.
|
|
135
|
+
|
|
136
|
+
.. code-block:: python
|
|
137
|
+
|
|
138
|
+
topic_names[-2:]
|
|
139
|
+
|
|
140
|
+
[['NHL Playoffs and Player Analysis',
|
|
141
|
+
'Major League Baseball Analysis',
|
|
142
|
+
'Space Exploration and Technology Innovations',
|
|
143
|
+
'Encryption Policy and Government Surveillance',
|
|
144
|
+
'Health and Alternative Treatments',
|
|
145
|
+
'Israeli-Palestinian and Lebanese Conflicts',
|
|
146
|
+
'Automotive Performance and Safety',
|
|
147
|
+
'Christian Theology and Debates',
|
|
148
|
+
'Waco Siege and Government Accountability',
|
|
149
|
+
'Debates on Morality and Free Speech',
|
|
150
|
+
'Gun Rights and Legislation',
|
|
151
|
+
'X Window System and Graphics Software',
|
|
152
|
+
'Hard Drive Technologies and Troubleshooting',
|
|
153
|
+
'Vintage Computer Hardware and Upgrades'],
|
|
154
|
+
['Sports Analysis',
|
|
155
|
+
'Religion and Government Accountability',
|
|
156
|
+
'Automotive Performance and Safety',
|
|
157
|
+
'X Window System and Graphics Software',
|
|
158
|
+
'Computer Hardware']]
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
``topics_per_document`` contains topic labels for each document, with one list for each level of resultion in our
|
|
162
|
+
cluster layers. In our above case this will be a list of 5 layers each containing a list of 18,170 topic names.
|
|
163
|
+
Documents that aren't contained within a cluster at a given layer are given the topic ``Unlabelled``.
|
|
164
|
+
|
|
165
|
+
.. code-block:: python
|
|
166
|
+
|
|
167
|
+
topics_per_document
|
|
168
|
+
|
|
169
|
+
[array(['Unlabelled',
|
|
170
|
+
'Discussion on VESA Local Bus Video Cards and Performance',
|
|
171
|
+
'Unlabelled', ...,
|
|
172
|
+
'Cooling Solutions and Components for CPUs and Power Supplies',
|
|
173
|
+
'Algorithms for Finding Sphere from Four Points in 3D',
|
|
174
|
+
'Automotive Discussions on Performance Cars and Specifications'], dtype=object),
|
|
175
|
+
array(['NHL Playoff Analysis and Predictions',
|
|
176
|
+
'Graphics Card Performance and Benchmark Discussions',
|
|
177
|
+
'Armenian Genocide and Turkish Atrocities Discourse', ...,
|
|
178
|
+
'Cooling Solutions and Components for CPUs and Power Supplies',
|
|
179
|
+
'Algorithms for 3D Polygon Processing and Geometry',
|
|
180
|
+
'Discussions on SUVs and Performance Cars'], dtype=object),
|
|
181
|
+
array(['NHL Playoff Analysis and Predictions',
|
|
182
|
+
'Video Card Drivers and Performance',
|
|
183
|
+
'Armenian Genocide and Turkish Atrocities', ..., 'Unlabelled',
|
|
184
|
+
'Unlabelled', 'Automotive Performance and Used Cars'], dtype=object),
|
|
185
|
+
array(['NHL Playoffs and Player Analysis',
|
|
186
|
+
'Vintage Computer Hardware and Upgrades', 'Unlabelled', ...,
|
|
187
|
+
'Unlabelled', 'X Window System and Graphics Software',
|
|
188
|
+
'Automotive Performance and Safety'], dtype=object),
|
|
189
|
+
array(['Sports Analysis', 'Computer Hardware', 'Unlabelled', ...,
|
|
190
|
+
'Unlabelled', 'X Window System and Graphics Software',
|
|
191
|
+
'Automotive Performance and Safety'], dtype=object)]
|
|
192
|
+
|
|
193
|
+
At this point we recommend that you explore your data and topic names with an interactive visualization library.
|
|
194
|
+
Our `DataMapPlot <https://github.com/TutteInstitute/datamapplot>`_ library is particularly well suited to exploring
|
|
195
|
+
data maps along with layers of topic names. It takes requires our ``document_map``, ``document_vectors`` and newly created ``topics_per_document``.
|
|
196
|
+
|
|
197
|
+
-------------------
|
|
198
|
+
Vector Construction
|
|
199
|
+
-------------------
|
|
200
|
+
|
|
201
|
+
If you do not have ready made document vectors and low dimensional representations of your data you will need to compute
|
|
202
|
+
your own. For faster encoding change device to: "cuda", "mps", "npu" or "cpu" depending on hardware availability. Alternatively,
|
|
203
|
+
one could make use of an API call to embedding service. Embedding wrappers can be found in:
|
|
204
|
+
|
|
205
|
+
.. code-block:: python
|
|
206
|
+
|
|
207
|
+
from toponymy.embedding_wrappers import OpenAIEmbedder
|
|
208
|
+
|
|
209
|
+
or the embedding wrapper of your choice. Once we generate document vectors we will need to construct a low dimensional representation.
|
|
210
|
+
Here we do that via our UMAP library.
|
|
211
|
+
|
|
212
|
+
.. code-block:: python
|
|
213
|
+
|
|
214
|
+
pip install umap-learn
|
|
215
|
+
pip install pandas
|
|
216
|
+
pip install sentence_transformers
|
|
217
|
+
|
|
218
|
+
import pandas as pd
|
|
219
|
+
from sentence_transformers import SentenceTransformer
|
|
220
|
+
import umap
|
|
221
|
+
|
|
222
|
+
newsgroups_df = pd.read_parquet("hf://datasets/lmcinnes/20newsgroups_embedded/data/train-00000-of-00001.parquet")
|
|
223
|
+
text = newsgroups_df["post"].str.strip().values
|
|
224
|
+
embedding_model = SentenceTransformer("all-MiniLM-L6-v2", device="cpu")
|
|
225
|
+
|
|
226
|
+
document_vectors = embedding_model.encode(text, show_progress_bar=True)
|
|
227
|
+
document_map = umap.UMAP(metric='cosine').fit_transform(document_vectors)
|
|
228
|
+
|
|
229
|
+
-------
|
|
230
|
+
License
|
|
231
|
+
-------
|
|
232
|
+
|
|
233
|
+
Toponymy is MIT licensed. See the LICENSE file for details.
|
|
234
|
+
|
|
235
|
+
------------
|
|
236
|
+
Contributing
|
|
237
|
+
------------
|
|
238
|
+
|
|
239
|
+
Contributions are more than welcome! If you have ideas for features of projects please get in touch. Everything from
|
|
240
|
+
code to notebooks to examples and documentation are all *equally valuable* so please don't feel you can't contribute.
|
|
241
|
+
To contribute please `fork the project <https://github.com/TutteInstitute/toponymy/fork>`_ make your
|
|
242
|
+
changes and submit a pull request. We will do our best to work through any issues with you and get your code merged in.
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
===========
|
|
2
|
+
Toponymy
|
|
3
|
+
===========
|
|
4
|
+
|
|
5
|
+
.. image:: doc/toponymy_text_horizontal.png
|
|
6
|
+
:width: 600
|
|
7
|
+
:align: center
|
|
8
|
+
:alt: Toponymy
|
|
9
|
+
|
|
10
|
+
The package name Toponymy is derived from the Greek topos ‘place’ + onuma ‘name’. Thus, the naming of places.
|
|
11
|
+
The goal of Toponymy is to put names to places in the space of information. This could be a corpus of documents,
|
|
12
|
+
in which case Toponymy can be viewed as a topic naming library. It could also be a collection of images, in which case
|
|
13
|
+
Toponymy could be used to name the themes of the images. The goal is to provide a names that can allow a user to
|
|
14
|
+
navigate through the space of information in a meaningful way.
|
|
15
|
+
|
|
16
|
+
Toponymy is designed to scale to very large corpora and collections, providing meaningful names on multiple scales,
|
|
17
|
+
from broad themes to fine-grained topics. We make use a custom clustering methods, information extraction,
|
|
18
|
+
and large language models to power this. The library is designed to be flexible and easy to use.
|
|
19
|
+
|
|
20
|
+
As of now this is an beta version of the library. Things can and will break right now.
|
|
21
|
+
We welcome feedback, use cases and feature suggestions.
|
|
22
|
+
|
|
23
|
+
------------------
|
|
24
|
+
Basic Installation
|
|
25
|
+
------------------
|
|
26
|
+
|
|
27
|
+
For now install the latest version of Toponymy from source you can do so by cloning the repository and running:
|
|
28
|
+
|
|
29
|
+
.. code-block:: bash
|
|
30
|
+
|
|
31
|
+
git clone https://github.com/TutteInstitute/toponymy
|
|
32
|
+
cd toponymy
|
|
33
|
+
pip install .
|
|
34
|
+
|
|
35
|
+
-----------
|
|
36
|
+
Basic Usage
|
|
37
|
+
-----------
|
|
38
|
+
|
|
39
|
+
We will need documents, document vectors and a low dimensional representation of these document vector to construct
|
|
40
|
+
a representation. This can be very expensive without a GPU so we recommend storing and reloading these vectors as
|
|
41
|
+
needed. For ease of experimentation we have precomputed and stored such vectors for the `20-Newsgroups dataset <http://qwone.com/~jason/20Newsgroups/>`_
|
|
42
|
+
on hugging face. Code to retrieve these vectors is below.
|
|
43
|
+
|
|
44
|
+
.. code-block:: python
|
|
45
|
+
|
|
46
|
+
pip install pandas
|
|
47
|
+
|
|
48
|
+
import numpy as np
|
|
49
|
+
import pandas as pd
|
|
50
|
+
newsgroups_df = pd.read_parquet("hf://datasets/lmcinnes/20newsgroups_embedded/data/train-00000-of-00001.parquet")
|
|
51
|
+
text = newsgroups_df["post"].str.strip().values
|
|
52
|
+
document_vectors = np.stack(newsgroups_df["embedding"].values)
|
|
53
|
+
document_map = np.stack(newsgroups_df["map"].values)
|
|
54
|
+
|
|
55
|
+
Toponymy also requires an embedding model for determining which of the documents will be most relevant to each
|
|
56
|
+
of our clusters. This doesn't have to be the embedding model that our documents were embedded with but it
|
|
57
|
+
should be similar.
|
|
58
|
+
|
|
59
|
+
.. code-block:: python
|
|
60
|
+
|
|
61
|
+
pip install sentence_transformers
|
|
62
|
+
|
|
63
|
+
from sentence_transformers import SentenceTransformer
|
|
64
|
+
embedding_model = SentenceTransformer("all-MiniLM-L6-v2")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
Once the low-dimensional representation is available (``document_map`` in this case), we can do the topic naming.
|
|
68
|
+
Toponymy will make use of a clusterer (such as ``ToponymyClusterer``) to create a balanced hierarchical layered
|
|
69
|
+
clustering of our documents. It will then use a variety of sampling and summarization techniques to construct prompts
|
|
70
|
+
describing each cluster to pass to a large language model (LLM). If you would like to experiment with testing
|
|
71
|
+
various cluster parameters in order construct cluster layers appropriate to your data feel free to cluster
|
|
72
|
+
your data ahead of time via:
|
|
73
|
+
|
|
74
|
+
.. code-block:: python
|
|
75
|
+
|
|
76
|
+
from toponymy import ToponymyClusterer
|
|
77
|
+
clusterer = ToponymyClusterer(min_clusters=4)
|
|
78
|
+
clusterer.fit(clusterable_vectors=document_map, embedding_vectors=document_vectors)
|
|
79
|
+
for i, layer in enumerate(clusterer.cluster_layers_):
|
|
80
|
+
print(f'{len(np.unique(layer.cluster_labels))-1} clusters in layer {i}')
|
|
81
|
+
|
|
82
|
+
428 clusters in layer 0
|
|
83
|
+
136 clusters in layer 1
|
|
84
|
+
42 clusters in layer 2
|
|
85
|
+
14 clusters in layer 3
|
|
86
|
+
5 clusters in layer 4
|
|
87
|
+
|
|
88
|
+
Toponymy supports multiple LLMs, including Cohere, OpenAI, and Anthropic via service calls, and local models via
|
|
89
|
+
Huggingface and LlamaCpp. Here we show an example using OpenAI. The following code will generate a topic naming
|
|
90
|
+
for the documents in the data set using an ``embedding_model``, ``document_vectors`` and ``document_map`` created above.
|
|
91
|
+
|
|
92
|
+
.. code-block:: python
|
|
93
|
+
|
|
94
|
+
from toponymy import Toponymy, KeyphraseBuilder
|
|
95
|
+
from toponymy.llm_wrappers import OpenAI
|
|
96
|
+
|
|
97
|
+
openai_api_key = open("openai_key.txt").read().strip()
|
|
98
|
+
llm = OpenAI('openai_api_key')
|
|
99
|
+
|
|
100
|
+
topic_model = Toponymy(
|
|
101
|
+
llm=llm,
|
|
102
|
+
embedding_model=embedding_model,
|
|
103
|
+
clusterer=clusterer,
|
|
104
|
+
object_description="newsgroup posts",
|
|
105
|
+
corpus_description="20-newsgroups dataset",
|
|
106
|
+
exemplar_delimiters=["<EXAMPLE_POST>\n","\n</EXAMPLE_POST>\n\n"],
|
|
107
|
+
)
|
|
108
|
+
topic_model.fit(text, document_vectors, document_map)
|
|
109
|
+
|
|
110
|
+
topic_names = topic_model.topic_names_
|
|
111
|
+
topics_per_document = topic_model.cluster_layers_
|
|
112
|
+
|
|
113
|
+
``topic_names`` is a list of lists which can be used to explore the unique topic names in each layer or resolution.
|
|
114
|
+
Let's examine the last two layers of topics.
|
|
115
|
+
|
|
116
|
+
.. code-block:: python
|
|
117
|
+
|
|
118
|
+
topic_names[-2:]
|
|
119
|
+
|
|
120
|
+
[['NHL Playoffs and Player Analysis',
|
|
121
|
+
'Major League Baseball Analysis',
|
|
122
|
+
'Space Exploration and Technology Innovations',
|
|
123
|
+
'Encryption Policy and Government Surveillance',
|
|
124
|
+
'Health and Alternative Treatments',
|
|
125
|
+
'Israeli-Palestinian and Lebanese Conflicts',
|
|
126
|
+
'Automotive Performance and Safety',
|
|
127
|
+
'Christian Theology and Debates',
|
|
128
|
+
'Waco Siege and Government Accountability',
|
|
129
|
+
'Debates on Morality and Free Speech',
|
|
130
|
+
'Gun Rights and Legislation',
|
|
131
|
+
'X Window System and Graphics Software',
|
|
132
|
+
'Hard Drive Technologies and Troubleshooting',
|
|
133
|
+
'Vintage Computer Hardware and Upgrades'],
|
|
134
|
+
['Sports Analysis',
|
|
135
|
+
'Religion and Government Accountability',
|
|
136
|
+
'Automotive Performance and Safety',
|
|
137
|
+
'X Window System and Graphics Software',
|
|
138
|
+
'Computer Hardware']]
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
``topics_per_document`` contains topic labels for each document, with one list for each level of resultion in our
|
|
142
|
+
cluster layers. In our above case this will be a list of 5 layers each containing a list of 18,170 topic names.
|
|
143
|
+
Documents that aren't contained within a cluster at a given layer are given the topic ``Unlabelled``.
|
|
144
|
+
|
|
145
|
+
.. code-block:: python
|
|
146
|
+
|
|
147
|
+
topics_per_document
|
|
148
|
+
|
|
149
|
+
[array(['Unlabelled',
|
|
150
|
+
'Discussion on VESA Local Bus Video Cards and Performance',
|
|
151
|
+
'Unlabelled', ...,
|
|
152
|
+
'Cooling Solutions and Components for CPUs and Power Supplies',
|
|
153
|
+
'Algorithms for Finding Sphere from Four Points in 3D',
|
|
154
|
+
'Automotive Discussions on Performance Cars and Specifications'], dtype=object),
|
|
155
|
+
array(['NHL Playoff Analysis and Predictions',
|
|
156
|
+
'Graphics Card Performance and Benchmark Discussions',
|
|
157
|
+
'Armenian Genocide and Turkish Atrocities Discourse', ...,
|
|
158
|
+
'Cooling Solutions and Components for CPUs and Power Supplies',
|
|
159
|
+
'Algorithms for 3D Polygon Processing and Geometry',
|
|
160
|
+
'Discussions on SUVs and Performance Cars'], dtype=object),
|
|
161
|
+
array(['NHL Playoff Analysis and Predictions',
|
|
162
|
+
'Video Card Drivers and Performance',
|
|
163
|
+
'Armenian Genocide and Turkish Atrocities', ..., 'Unlabelled',
|
|
164
|
+
'Unlabelled', 'Automotive Performance and Used Cars'], dtype=object),
|
|
165
|
+
array(['NHL Playoffs and Player Analysis',
|
|
166
|
+
'Vintage Computer Hardware and Upgrades', 'Unlabelled', ...,
|
|
167
|
+
'Unlabelled', 'X Window System and Graphics Software',
|
|
168
|
+
'Automotive Performance and Safety'], dtype=object),
|
|
169
|
+
array(['Sports Analysis', 'Computer Hardware', 'Unlabelled', ...,
|
|
170
|
+
'Unlabelled', 'X Window System and Graphics Software',
|
|
171
|
+
'Automotive Performance and Safety'], dtype=object)]
|
|
172
|
+
|
|
173
|
+
At this point we recommend that you explore your data and topic names with an interactive visualization library.
|
|
174
|
+
Our `DataMapPlot <https://github.com/TutteInstitute/datamapplot>`_ library is particularly well suited to exploring
|
|
175
|
+
data maps along with layers of topic names. It takes requires our ``document_map``, ``document_vectors`` and newly created ``topics_per_document``.
|
|
176
|
+
|
|
177
|
+
-------------------
|
|
178
|
+
Vector Construction
|
|
179
|
+
-------------------
|
|
180
|
+
|
|
181
|
+
If you do not have ready made document vectors and low dimensional representations of your data you will need to compute
|
|
182
|
+
your own. For faster encoding change device to: "cuda", "mps", "npu" or "cpu" depending on hardware availability. Alternatively,
|
|
183
|
+
one could make use of an API call to embedding service. Embedding wrappers can be found in:
|
|
184
|
+
|
|
185
|
+
.. code-block:: python
|
|
186
|
+
|
|
187
|
+
from toponymy.embedding_wrappers import OpenAIEmbedder
|
|
188
|
+
|
|
189
|
+
or the embedding wrapper of your choice. Once we generate document vectors we will need to construct a low dimensional representation.
|
|
190
|
+
Here we do that via our UMAP library.
|
|
191
|
+
|
|
192
|
+
.. code-block:: python
|
|
193
|
+
|
|
194
|
+
pip install umap-learn
|
|
195
|
+
pip install pandas
|
|
196
|
+
pip install sentence_transformers
|
|
197
|
+
|
|
198
|
+
import pandas as pd
|
|
199
|
+
from sentence_transformers import SentenceTransformer
|
|
200
|
+
import umap
|
|
201
|
+
|
|
202
|
+
newsgroups_df = pd.read_parquet("hf://datasets/lmcinnes/20newsgroups_embedded/data/train-00000-of-00001.parquet")
|
|
203
|
+
text = newsgroups_df["post"].str.strip().values
|
|
204
|
+
embedding_model = SentenceTransformer("all-MiniLM-L6-v2", device="cpu")
|
|
205
|
+
|
|
206
|
+
document_vectors = embedding_model.encode(text, show_progress_bar=True)
|
|
207
|
+
document_map = umap.UMAP(metric='cosine').fit_transform(document_vectors)
|
|
208
|
+
|
|
209
|
+
-------
|
|
210
|
+
License
|
|
211
|
+
-------
|
|
212
|
+
|
|
213
|
+
Toponymy is MIT licensed. See the LICENSE file for details.
|
|
214
|
+
|
|
215
|
+
------------
|
|
216
|
+
Contributing
|
|
217
|
+
------------
|
|
218
|
+
|
|
219
|
+
Contributions are more than welcome! If you have ideas for features of projects please get in touch. Everything from
|
|
220
|
+
code to notebooks to examples and documentation are all *equally valuable* so please don't feel you can't contribute.
|
|
221
|
+
To contribute please `fork the project <https://github.com/TutteInstitute/toponymy/fork>`_ make your
|
|
222
|
+
changes and submit a pull request. We will do our best to work through any issues with you and get your code merged in.
|
toponymy-0.2.0/setup.cfg
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
[metadata]
|
|
2
|
+
name = toponymy
|
|
3
|
+
version = 0.2.0
|
|
4
|
+
author = John Healy, Leland McInnes
|
|
5
|
+
author_email = jchealy@gmail.com, leland.mcinnes@gmail.com
|
|
6
|
+
maintainer = John Healy, Leland McInnes
|
|
7
|
+
maintainer_email = jchealy@gmail.com, leland.mcinnes@gmail.com
|
|
8
|
+
description = A library for using large language models to name topics
|
|
9
|
+
long_description = file: README.rst
|
|
10
|
+
keywords = topic modeing, representation, cluster, clustering, large language models, LLM, topic naming
|
|
11
|
+
url = https://github.com/TutteInstitute/toponymy
|
|
12
|
+
license = MIT License
|
|
13
|
+
license_files = LICENSE
|
|
14
|
+
classifiers =
|
|
15
|
+
License :: OSI Approved :: MIT License
|
|
16
|
+
Programming Language :: Python :: 3.9
|
|
17
|
+
Programming Language :: Python :: 3.10
|
|
18
|
+
Development Status :: 4 - Beta
|
|
19
|
+
Operating System :: OS Independent
|
|
20
|
+
|
|
21
|
+
[options]
|
|
22
|
+
zip_safe = False
|
|
23
|
+
packages = toponymy
|
|
24
|
+
python_requires = >=3.9
|
|
25
|
+
install_requires =
|
|
26
|
+
numpy>=1.21
|
|
27
|
+
pandas>=1.0
|
|
28
|
+
numba>=0.56
|
|
29
|
+
datasets
|
|
30
|
+
scikit-learn>=1.6
|
|
31
|
+
vectorizers
|
|
32
|
+
scipy
|
|
33
|
+
fast_hdbscan>=0.2.2
|
|
34
|
+
sentence_transformers
|
|
35
|
+
dataclasses
|
|
36
|
+
tqdm
|
|
37
|
+
tenacity
|
|
38
|
+
|
|
39
|
+
[options.extras_require]
|
|
40
|
+
dev =
|
|
41
|
+
black
|
|
42
|
+
isort
|
|
43
|
+
pylint
|
|
44
|
+
pytest
|
|
45
|
+
anthropic
|
|
46
|
+
cohere
|
|
47
|
+
azure-ai-inference
|
|
48
|
+
llama-cpp-python
|
|
49
|
+
openai
|
|
50
|
+
transformers
|
|
51
|
+
bm25s
|
|
52
|
+
|
|
53
|
+
[egg_info]
|
|
54
|
+
tag_build =
|
|
55
|
+
tag_date = 0
|
|
56
|
+
|
toponymy-0.2.0/setup.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
from .toponymy import Toponymy
|
|
2
|
+
from .clustering import ToponymyClusterer
|
|
3
|
+
from .keyphrases import KeyphraseBuilder
|
|
4
|
+
from .cluster_layer import ClusterLayerText
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"Toponymy",
|
|
8
|
+
"ToponymyClusterer",
|
|
9
|
+
"KeyphraseBuilder",
|
|
10
|
+
"ClusterLayerText",
|
|
11
|
+
]
|