lemo-vocabulate 0.1.4__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.
@@ -0,0 +1,29 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Steven Mesquiti
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.
22
+
23
+ ---
24
+
25
+ This software is a Python port of Vocabulate, originally developed by:
26
+ Vine, V., Boyd, R. L., & Pennebaker, J. W. (2020).
27
+ Natural emotion vocabularies as windows on distress and well-being.
28
+ Nature Communications, 11(1), 4525.
29
+ https://doi.org/10.1038/s41467-020-18349-0
@@ -0,0 +1,5 @@
1
+ include README.md
2
+ include LICENSE
3
+ include requirements.txt
4
+ recursive-include lemo_vocabulate/data *.csv
5
+ recursive-include lemo_vocabulate/data *.txt
@@ -0,0 +1,415 @@
1
+ Metadata-Version: 2.4
2
+ Name: lemo-vocabulate
3
+ Version: 0.1.4
4
+ Summary: Dictionary-based text analysis tool for emotion and sentiment analysis. Python port of Vocabulate (Vine et al., 2020).
5
+ Author-email: Steven Mesquiti <sm9518@princeton.edu>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Steven Mesquiti
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ ---
29
+
30
+ This software is a Python port of Vocabulate, originally developed by:
31
+ Vine, V., Boyd, R. L., & Pennebaker, J. W. (2020).
32
+ Natural emotion vocabularies as windows on distress and well-being.
33
+ Nature Communications, 11(1), 4525.
34
+ https://doi.org/10.1038/s41467-020-18349-0
35
+ Project-URL: Homepage, https://github.com/Bushel-of-Lemons/LEMO_Vocabulate
36
+ Project-URL: Issues, https://github.com/Bushel-of-Lemons/LEMO_Vocabulate/issues
37
+ Classifier: Programming Language :: Python :: 3
38
+ Classifier: Programming Language :: Python :: 3.8
39
+ Classifier: License :: OSI Approved :: MIT License
40
+ Classifier: Operating System :: OS Independent
41
+ Requires-Python: >=3.8
42
+ Description-Content-Type: text/markdown
43
+ License-File: LICENSE
44
+ Requires-Dist: pandas>=1.3.0
45
+ Requires-Dist: tqdm>=4.62.0
46
+ Dynamic: license-file
47
+
48
+ # Vocabulate Python Edition
49
+
50
+ **Vocabulate** is a dictionary-based text analysis tool originally converted from C#.
51
+ This Python package allows you to tokenize, clean, and analyze texts based on custom dictionaries.
52
+
53
+ **DISCLAIMER:** I do not take credit for this software. I simply reconfigured it to run using a higher-level programming language (i.e., python instead of C#). All credit goes to the original authors: [Vine et al. (2020)](https://www.nature.com/articles/s41467-020-18349-0)
54
+
55
+ ```bib
56
+ @article{vine2020natural,
57
+ title={Natural emotion vocabularies as windows on distress and well-being},
58
+ author={Vine, Vera, Boyd, Ryan L. and Pennebaker, James W.},
59
+ journal={Nature Communications},
60
+ volume={11},
61
+ number={1},
62
+ pages={4525},
63
+ year={2020},
64
+ doi={10.1038/s41467-020-18349-0}
65
+ }
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Installation
71
+
72
+ Clone this repository and navigate to the project directory:
73
+
74
+ ```bash
75
+ git clone https://github.com/Bushel-of-Lemons/LEMO_Vocabulate.git
76
+ cd LEMO_Vocabulate
77
+ ```
78
+
79
+ ### Option 1: Install with pip
80
+
81
+ ```bash
82
+ pip install -r requirements.txt
83
+ ```
84
+
85
+ ### Option 2: Create a Conda environment (recommended)
86
+
87
+ ```bash
88
+ # Create conda environment with Python 3.8
89
+ conda create -n lemons python=3.8 pandas>=2.0 numpy>=1.24 pip -y
90
+
91
+ # Activate the environment
92
+ conda activate lemons
93
+
94
+ # Install remaining dependencies
95
+ pip install tqdm>=4.65
96
+ ```
97
+
98
+ ### Option 3: Install from TestPyPI
99
+
100
+ ```bash
101
+ pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ lemo-vocabulate
102
+ ```
103
+
104
+ **Note:** This package requires Python >= 3.8 and assumes you have python and pip already installed.
105
+
106
+ ---
107
+
108
+ ## Quick Start
109
+
110
+ ```python
111
+ import pandas as pd
112
+ from lemo_vocabulate import run_vocabulate_analysis, get_data_path
113
+
114
+ # Example using a DataFrame with included data files
115
+ df = pd.DataFrame({
116
+ "user_id": ["user_1", "user_2"],
117
+ "text": ["This is a sample text.", "Another example text."]
118
+ })
119
+
120
+ # Use the included dictionary and stopwords
121
+ results = run_vocabulate_analysis(
122
+ dict_file=get_data_path("AEV_Dict.csv"),
123
+ input_data=df,
124
+ text_column="text",
125
+ stopwords_file=get_data_path("stopwords.txt"),
126
+ raw_counts=True
127
+ )
128
+
129
+ print(results.head())
130
+ ```
131
+
132
+ ### Using Custom Files
133
+
134
+ You can still use your own dictionary and stopwords files:
135
+
136
+ ```python
137
+ # Use custom files
138
+ results = run_vocabulate_analysis(
139
+ dict_file="path/to/your/custom_dict.csv",
140
+ input_data=df,
141
+ text_column="text",
142
+ stopwords_file="path/to/your/custom_stopwords.txt",
143
+ raw_counts=True
144
+ )
145
+ ```
146
+
147
+ For more examples, see the `lemo_vocabulate_example.ipynb` notebook.
148
+
149
+ ---
150
+
151
+ ## Features
152
+
153
+ - **Tokenization designed for social media text**
154
+ - Twitter-aware tokenizer that handles:
155
+ - Usernames (@user)
156
+ - Hashtags (#happy)
157
+ - Emojis and emoticons
158
+ - URLs
159
+ - Repeated characters (soooo good)
160
+ - Punctuation-heavy social media text
161
+
162
+ - **Stopword removal**
163
+ - Flexible stopword handling via file or string input
164
+
165
+ - **Dictionary matching with multi-word wildcards**
166
+ - Compatible with custom dictionaries in CSV format
167
+ - Example dictionary provided: `Dictionary/AEV_Dict.csv`
168
+
169
+ **Dictionary breakdown:**
170
+ ```
171
+ Neg 94
172
+ Pos 53
173
+ AnxFear 20
174
+ Anger 16
175
+ Sadness 36
176
+ NegUndiff 15
177
+ Total words in dictionary: 162
178
+ ```
179
+
180
+ - **Comprehensive text metrics**
181
+ - Word count, type-token ratio, dictionary coverage
182
+ - Category-level statistics (CWR, CCR, counts, unique counts)
183
+
184
+ - **Flexible output**
185
+ - Returns Pandas DataFrame
186
+ - Optional CSV export
187
+
188
+ ---
189
+
190
+ ## Usage Examples
191
+
192
+ ### Analyzing a DataFrame
193
+
194
+ ```python
195
+ import pandas as pd
196
+ from lemo_vocabulate import run_vocabulate_analysis
197
+
198
+ # Create sample data
199
+ df = pd.DataFrame({
200
+ "text_id": [1, 2, 3],
201
+ "text": [
202
+ "I am so agitated and aggravated!",
203
+ "He was afraid of the dark.",
204
+ "I am so happy happy happy! And sad."
205
+ ]
206
+ })
207
+
208
+ # Run analysis
209
+ results = run_vocabulate_analysis(
210
+ dict_file="Dictionary/AEV_Dict.csv",
211
+ input_data=df,
212
+ text_column="text",
213
+ stopwords_file="stopwords.txt",
214
+ raw_counts=True,
215
+ output_csv="results.csv"
216
+ )
217
+
218
+ print(results.head())
219
+ ```
220
+
221
+ ### Analyzing Text Files
222
+
223
+ ```python
224
+ # Analyze a single text file
225
+ results = run_vocabulate_analysis(
226
+ dict_file="Dictionary/AEV_Dict.csv",
227
+ input_data="path/to/file.txt",
228
+ stopwords_file="stopwords.txt",
229
+ raw_counts=True
230
+ )
231
+
232
+ # Analyze all .txt files in a folder
233
+ results = run_vocabulate_analysis(
234
+ dict_file="Dictionary/AEV_Dict.csv",
235
+ input_data="path/to/folder",
236
+ stopwords_file="stopwords.txt",
237
+ raw_counts=False
238
+ )
239
+ ```
240
+
241
+ ### Merging Results with Original Data
242
+
243
+ ```python
244
+ # Run analysis
245
+ df_results = run_vocabulate_analysis(
246
+ dict_file="Dictionary/AEV_Dict.csv",
247
+ input_data=df,
248
+ text_column="text",
249
+ stopwords_file="stopwords.txt",
250
+ raw_counts=True
251
+ )
252
+
253
+ # Create text_id for merging
254
+ df_results['text_id'] = df_results.index
255
+
256
+ # Merge with original data
257
+ df_complete = df_results.drop(['text', 'Filename'], axis=1).merge(
258
+ df,
259
+ on='text_id',
260
+ how='left'
261
+ )
262
+
263
+ # Reorder columns
264
+ cols = ['text_id', 'text'] + [col for col in df_complete.columns if col not in ['text_id', 'text']]
265
+ df_complete = df_complete[cols]
266
+ ```
267
+
268
+ ---
269
+
270
+ ## Stopwords
271
+
272
+ Stopword removal allows you to exclude very common function words (e.g., `the`, `and`, `is`, `I`, `you`) that typically do not carry psychological or semantic content. In Vocabulate, stopwords are removed **after tokenization** and **before dictionary matching**, which improves the interpretability of dictionary categories.
273
+
274
+ ### Using a Stopwords File (Recommended)
275
+
276
+ Create a `.txt` file with one word per line:
277
+
278
+ ```txt
279
+ the
280
+ and
281
+ is
282
+ i
283
+ you
284
+ to
285
+ ```
286
+
287
+ Use it in your analysis:
288
+
289
+ ```python
290
+ results = run_vocabulate_analysis(
291
+ dict_file="Dictionary/AEV_Dict.csv",
292
+ input_data=df,
293
+ text_column="text",
294
+ stopwords_file="stopwords.txt"
295
+ )
296
+ ```
297
+
298
+ ### Using a Stopwords String
299
+
300
+ ```python
301
+ stopwords = "the\nand\nis\nbe\nnot\n"
302
+ results = run_vocabulate_analysis(
303
+ dict_file="Dictionary/AEV_Dict.csv",
304
+ input_data=df,
305
+ text_column="text",
306
+ stopwords_text=stopwords
307
+ )
308
+ ```
309
+
310
+ ### How Stopwords Affect Output Metrics
311
+
312
+ **Stopword removal does NOT affect:**
313
+ - `WC` (whitespace word count)
314
+ - `TC_Raw` (raw token count)
315
+ - `TTR_Raw` (raw type-token ratio)
316
+
317
+ **Stopword removal DOES affect:**
318
+
319
+ | Column | Effect |
320
+ |--------|--------|
321
+ | `TC_Clean` | Tokens after stopword removal |
322
+ | `TTR_Clean` | Based on clean tokens |
323
+ | `TC_NonDict` | Non-dictionary tokens after cleaning |
324
+ | `DictPercent` | Higher if stopwords filtered out |
325
+ | Category metrics | Only meaningful content words remain |
326
+
327
+ ---
328
+
329
+ ## Understanding the Output
330
+
331
+ The `run_vocabulate_analysis` function returns a Pandas DataFrame where each row corresponds to a single input text. Below is a detailed explanation of all output columns.
332
+
333
+ ### General Text Metrics
334
+
335
+ | Column Name | Description |
336
+ | -------------- | -------------------------------------------------------------------------------------- |
337
+ | `Filename` | Name of the file or index of the row from the input DataFrame |
338
+ | `text` | The full original text that was analyzed |
339
+ | `WC` | Word count: total number of whitespace-separated tokens in the original text |
340
+ | `TC_Raw` | Token count after tokenizer processing (including punctuation, emoticons, etc.) |
341
+ | `TTR_Raw` | Type-Token Ratio for raw tokens: `#unique tokens / TC_Raw * 100` |
342
+ | `TC_Clean` | Token count after removing stopwords |
343
+ | `TTR_Clean` | Type-Token Ratio for cleaned tokens: `#unique tokens / TC_Clean * 100` |
344
+ | `TC_NonDict` | Number of tokens not matched to any dictionary concept |
345
+ | `TTR_NonDict` | Type-Token Ratio of non-dictionary tokens |
346
+ | `DictPercent` | Percent of tokens matched to dictionary concepts: `num_matched_tokens / TC_Raw * 100` |
347
+ | `CapturedText` | Concatenated string of all dictionary-matched words from the text |
348
+
349
+ ### Category-Specific Metrics
350
+
351
+ For each category in the loaded dictionary (e.g., `Neg`, `Pos`, `AnxFear`, `Anger`, `Sadness`, `NegUndiff`), four metrics are provided:
352
+
353
+ | Column Suffix | Description |
354
+ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
355
+ | `_CWR` | **Category Word Ratio**: percentage of unique words in the category relative to total words in text: `unique_count / WC * 100` |
356
+ | `_CCR` | **Category Concept Ratio**: percentage of unique words in the category relative to all matched tokens in that category: `unique_count / total_count * 100` |
357
+ | `_Count` | **Raw Count**: total number of occurrences of words from this category in the text (only if `raw_counts=True`) |
358
+ | `_Unique` | **Unique Count**: number of unique words in the text that matched this category (only if `raw_counts=True`) |
359
+
360
+ #### Example: Category "Neg"
361
+
362
+ - `Neg_CWR` → % of total words in the text that were unique Neg words
363
+ - `Neg_CCR` → % of category words that were unique
364
+ - `Neg_Count` → Total Neg words matched
365
+ - `Neg_Unique` → Number of unique Neg words matched
366
+
367
+ ---
368
+
369
+ ## Example Output
370
+
371
+ | Filename | text | WC | TC_Raw | TTR_Raw | TC_Clean | TTR_Clean | TC_NonDict | TTR_NonDict | DictPercent | CapturedText | Neg_CWR | Neg_CCR | Neg_Count | Neg_Unique | Pos_CWR | Pos_CCR | Pos_Count | Pos_Unique | AnxFear_CWR | AnxFear_CCR | AnxFear_Count | AnxFear_Unique |
372
+ |----------|------|-----|--------|---------|----------|-----------|------------|-------------|-------------|--------------|---------|---------|-----------|------------|---------|---------|-----------|------------|-------------|-------------|---------------|----------------|
373
+ | 0 | I am so agitated and aggravated! | 6 | 7 | 100.0 | 2 | 100.0 | 0 | 0.0 | 28.57 | agitated aggravated | 33.33 | 100.0 | 2 | 2 | 0.0 | 0.0 | 0 | 0 | 0.0 | 0.0 | 0 | 0 |
374
+ | 1 | He was afraid of the dark.... | 6 | 8 | 100.0 | 3 | 100.0 | 2 | 100.0 | 12.5 | afraid | 16.67 | 100.0 | 1 | 1 | 0.0 | 0.0 | 0 | 0 | 16.67 | 100.0 | 1 | 1 |
375
+ | 2 | Nothing to be afraid or agitated about. Yet I'm afraid, and it makes me want to agitate!! | 17 | 21 | 85.71 | 6 | 83.33 | 2 | 100.0 | 19.05 | afraid agitated afraid agitate | 11.76 | 50.0 | 4 | 2 | 0.0 | 0.0 | 0 | 0 | 5.88 | 50.0 | 2 | 1 |
376
+ | 3 | I am so happy happy happy! And sad. | 8 | 10 | 80.0 | 4 | 50.0 | 0 | 0.0 | 40.0 | happy happy happy sad | 12.5 | 100.0 | 1 | 1 | 12.5 | 33.33 | 3 | 1 | 0.0 | 0.0 | 0 | 0 |
377
+ | 4 | dislike disliked dislikes disliking/doo | 5 | 6 | 100.0 | 5 | 100.0 | 1 | 100.0 | 66.67 | dislike disliked dislikes disliking | 20.0 | 25.0 | 4 | 1 | 0.0 | 0.0 | 0 | 0 | 0.0 | 0.0 | 0 | 0 |
378
+
379
+ ---
380
+
381
+ ## Function Parameters
382
+
383
+ ```python
384
+ run_vocabulate_analysis(
385
+ dict_file: str = None, # Path to dictionary CSV file (required)
386
+ input_data = None, # DataFrame, file path, or folder path (required)
387
+ text_column: str = None, # Column name for text (required for DataFrame)
388
+ stopwords_text: str = None, # Stopwords as newline-separated string
389
+ stopwords_file: str = None, # Path to stopwords file
390
+ raw_counts: bool = True, # Include raw counts in output
391
+ encoding: str = "utf-8", # File encoding
392
+ csv_delimiter: str = ",", # CSV delimiter
393
+ csv_quote: str = '"', # CSV quote character
394
+ output_csv: str = None, # Optional output CSV path
395
+ whitespace_method: str = 'new' # Whitespace tokenization method
396
+ )
397
+ ```
398
+ ---
399
+
400
+ ## Citation
401
+
402
+ If you use this software in your research, please cite the original paper:
403
+
404
+ ```bib
405
+ @article{vine2020natural,
406
+ title={Natural emotion vocabularies as windows on distress and well-being},
407
+ author={Vine, Vera, Boyd, Ryan L. and Pennebaker, James W.},
408
+ journal={Nature Communications},
409
+ volume={11},
410
+ number={1},
411
+ pages={4525},
412
+ year={2020},
413
+ doi={10.1038/s41467-020-18349-0}
414
+ }
415
+ ```