PsychiatryNLPKit 0.1.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.
Files changed (43) hide show
  1. psychiatrynlpkit-0.1.0/LICENSE +21 -0
  2. psychiatrynlpkit-0.1.0/PKG-INFO +570 -0
  3. psychiatrynlpkit-0.1.0/README.md +524 -0
  4. psychiatrynlpkit-0.1.0/pyproject.toml +94 -0
  5. psychiatrynlpkit-0.1.0/setup.cfg +4 -0
  6. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/__init__.py +34 -0
  7. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/analysis/Density.py +164 -0
  8. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/analysis/Graph.py +302 -0
  9. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/analysis/ImageSimilarity.py +227 -0
  10. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/analysis/Lexicon.py +116 -0
  11. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/analysis/Perplexity.py +356 -0
  12. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/analysis/Similarity.py +139 -0
  13. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/analysis/Syntax.py +727 -0
  14. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/analysis/__init__.py +108 -0
  15. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/analysis/batch.py +429 -0
  16. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/config.py +76 -0
  17. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/data/Audio.py +7 -0
  18. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/data/Image.py +36 -0
  19. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/data/Text.py +550 -0
  20. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/data/__init__.py +23 -0
  21. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/data/_resources.py +96 -0
  22. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/model/LLM.py +150 -0
  23. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/model/ViT.py +74 -0
  24. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/model/__init__.py +24 -0
  25. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/py.typed +0 -0
  26. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/resources/__init__.py +6 -0
  27. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/resources/filler_words.json +4 -0
  28. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit/resources/word2vec.db +0 -0
  29. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit.egg-info/PKG-INFO +570 -0
  30. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit.egg-info/SOURCES.txt +41 -0
  31. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit.egg-info/dependency_links.txt +1 -0
  32. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit.egg-info/requires.txt +25 -0
  33. psychiatrynlpkit-0.1.0/src/PsychiatryNLPKit.egg-info/top_level.txt +1 -0
  34. psychiatrynlpkit-0.1.0/tests/test_batch.py +215 -0
  35. psychiatrynlpkit-0.1.0/tests/test_data.py +110 -0
  36. psychiatrynlpkit-0.1.0/tests/test_density.py +48 -0
  37. psychiatrynlpkit-0.1.0/tests/test_graph.py +50 -0
  38. psychiatrynlpkit-0.1.0/tests/test_image_similarity.py +12 -0
  39. psychiatrynlpkit-0.1.0/tests/test_lexicon.py +31 -0
  40. psychiatrynlpkit-0.1.0/tests/test_model_wrappers.py +158 -0
  41. psychiatrynlpkit-0.1.0/tests/test_perplexity.py +50 -0
  42. psychiatrynlpkit-0.1.0/tests/test_similarity.py +50 -0
  43. psychiatrynlpkit-0.1.0/tests/test_syntax.py +147 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rukun Dou, Tiana Wei, Alban Elias Voppel
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.
@@ -0,0 +1,570 @@
1
+ Metadata-Version: 2.4
2
+ Name: PsychiatryNLPKit
3
+ Version: 0.1.0
4
+ Summary: Computational linguistics toolkit for psychosis risk assessment and thought disorder analysis
5
+ Author-email: Rukun Dou <rukun.dou2004@gmail.com>, Tiana Wei <hsi.wei@mail.mcgill.ca>, Alban Elias Voppel <alban.voppel@mail.mcgill.ca>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/rukun-dou/PsychiatryNLPKit
8
+ Project-URL: Repository, https://github.com/rukun-dou/PsychiatryNLPKit
9
+ Project-URL: Documentation, https://rukun-dou.github.io/PsychiatryNLPKit/
10
+ Project-URL: Bug Tracker, https://github.com/rukun-dou/PsychiatryNLPKit/issues
11
+ Keywords: nlp,psychiatry,clinical-nlp,thought-disorder,psychosis-risk
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
19
+ Classifier: Topic :: Text Processing :: Linguistic
20
+ Requires-Python: >=3.11
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: benepar>=0.2.0
24
+ Requires-Dist: numpy>=2.0.0
25
+ Requires-Dist: nltk>=3.9.0
26
+ Requires-Dist: pandas>=2.2.0
27
+ Requires-Dist: stanza>=1.8.0
28
+ Requires-Dist: torch>=2.5.0
29
+ Requires-Dist: transformers>=4.40.0
30
+ Requires-Dist: sentence-transformers>=5.0.0
31
+ Requires-Dist: scikit-learn>=1.3.0
32
+ Requires-Dist: scikit-dimension>=0.3.2
33
+ Requires-Dist: matplotlib>=3.8.0
34
+ Requires-Dist: zstandard>=0.22.0
35
+ Provides-Extra: graph
36
+ Requires-Dist: networkx>=3.0; extra == "graph"
37
+ Provides-Extra: image
38
+ Requires-Dist: pillow>=10.0.0; extra == "image"
39
+ Provides-Extra: dev
40
+ Requires-Dist: pytest>=8.0; extra == "dev"
41
+ Requires-Dist: pyright>=1.1; extra == "dev"
42
+ Requires-Dist: ruff>=0.4; extra == "dev"
43
+ Requires-Dist: sphinx>=7.0; extra == "dev"
44
+ Requires-Dist: sphinx-rtd-theme>=2.0; extra == "dev"
45
+ Dynamic: license-file
46
+
47
+ # PsychiatryNLPKit
48
+
49
+ [![CI](https://github.com/rukun-dou/PsychiatryNLPKit/workflows/CI/badge.svg)](https://github.com/rukun-dou/PsychiatryNLPKit/actions)
50
+ [![PyPI version](https://img.shields.io/pypi/v/PsychiatryNLPKit.svg)](https://pypi.org/project/PsychiatryNLPKit/)
51
+ [![Python 3.12+](https://img.shields.io/pypi/pyversions/PsychiatryNLPKit.svg)](https://python.org/downloads/release/python-3120/)
52
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/rukun-dou/PsychiatryNLPKit/blob/main/LICENSE)
53
+ [![Documentation](https://img.shields.io/badge/docs-latest-blue.svg)](https://rukun-dou.github.io/PsychiatryNLPKit/)
54
+
55
+ A scientific Python package for computational linguistics analysis of clinical data in psychiatry. It provides a curated set of linguistic metrics across seven analytical categories, each grounded in peer-reviewed research on psychosis risk assessment and thought disorder characterization.
56
+
57
+ ---
58
+
59
+ ## Overview
60
+
61
+ PsychiatryNLPKit is designed for researchers and clinicians who need to extract validated computational linguistics features from spoken or written clinical text. The package implements analysis functions derived from the scientific literature on language markers of psychosis, including formal thought disorder, disorganization, and cognitive impairment.
62
+
63
+ The toolkit supports **English** and **French** text and provides metrics spanning:
64
+
65
+ | Category | What it measures |
66
+ |---|---|
67
+ | **Syntax** | POS ratios, clause structure, syntax tree depth, sentence complexity |
68
+ | **Similarity** |Semantic coherence via adjacent word/sentence cosine similarity |
69
+ | **Perplexity** | Language model perplexity at paragraph and sentence levels (generative + masked LM) |
70
+ | **Graph** | Network metrics from structural word-transition graphs (nodes, edges, diameter, z-scores) |
71
+ | **Density** | Semantic space dimensionality via PCA explained variance and intrinsic dimension estimation |
72
+ | **Lexicon** | Disfluency and filler word frequency |
73
+ | **ImageSimilarity** | Cross-modal cosine similarity between images and text sections (ViT-based) |
74
+
75
+ Each function accepts pre-computed linguistic data from the `TextData` container and returns a dictionary mapping section names to numeric metric values. This modular design lets you compose analyses flexibly or run them all at once via the batch API.
76
+
77
+ ### Design principles
78
+
79
+ - **Scientific grounding** -- analysis functions are based on the psychiatry research literature. This package implements speech metrics that have been shown to correlate with clinical rating scales (PANSS, TLC, TLI).
80
+ - **Batch efficiency** -- expensive computations (tokenization, embedding, constituency parsing) are lazy-loaded and cached on the `TextData` container. Running multiple analyses over the same text incurs no redundant work.
81
+ - **Hardware acceleration** -- all deep learning pipelines run on CUDA, MPS (Apple Silicon), or Intel XPU when available, with automatic fallback to CPU.
82
+ - **Composable architecture** -- individual analysis functions can be called standalone, or orchestrated together via `BatchAnalyzer`. The same `TextData` object serves all analyses.
83
+
84
+ ---
85
+
86
+ ## Quick Start
87
+
88
+ ### Batch API (recommended for most use cases)
89
+
90
+ The high-level batch API processes an entire corpus in a few lines:
91
+
92
+ ```python
93
+ import logging
94
+ import PsychiatryNLPKit as pnlp
95
+ from PsychiatryNLPKit.data import Section, TextData
96
+ from PsychiatryNLPKit.model import HFEmbeddingLLM, HFGenerativeLLM
97
+
98
+ # 1. Configure logging (optional but recommended)
99
+ pnlp.configure_logging(level=logging.INFO)
100
+
101
+ # 2. Load your text data from a file or database. Organize the dataset into different sections for separate analysis.
102
+ sections = [
103
+ Section(text="I work in a factory that produces humanoid robots.", name="p1"),
104
+ Section(text="I just came back from a vacation in the mountains.", name="p2"),
105
+ ]
106
+ data = TextData(sections=sections, lang="en")
107
+
108
+ # 3. Attach models (lazy-loaded on first use)
109
+ data.embedding_model = HFEmbeddingLLM("unsloth/embeddinggemma-300m")
110
+ data.generative_model = HFGenerativeLLM("unsloth/Llama-3.2-1B")
111
+
112
+ # 4. Run analyses (exclude analyses that require additional models)
113
+ result = pnlp.BatchAnalyzer(
114
+ data,
115
+ excluded_analyses=[
116
+ "paragraph_level_pseudo_perplexity", # requires mask-filling model
117
+ "sentence_level_pseudo_perplexity",
118
+ "structural_graph", # requires networkx extra
119
+ "image_text_similarity", # requires pillow extra and image paths
120
+ ],
121
+ ).run()
122
+
123
+ # 5. Inspect results
124
+ print(result.sections) # ['p1', 'p2']
125
+ print(result.analyses_run) # list of successfully executed function names
126
+ print(result.results["p1"]) # {'sentence_length': 12.5, 'adverb_ratio': 0.08, ...}
127
+
128
+ # 6. Export to CSV for downstream statistical analysis
129
+ import csv
130
+ with open("results.csv", "w", newline="") as f:
131
+ writer = csv.writer(f)
132
+ writer.writerow(["section"] + list(result.results["p1"].keys()))
133
+ for section in result.sections:
134
+ writer.writerow([section] + [result.results[section].get(k, float("nan"))
135
+ for k in result.results["p1"].keys()])
136
+ ```
137
+
138
+ ### Low-level API (fine-grained control)
139
+
140
+ For targeted analysis or custom pipelines, call individual functions directly:
141
+
142
+ ```python
143
+ from PsychiatryNLPKit import analysis as pnlp_a
144
+ from PsychiatryNLPKit.data import Section, TextData
145
+ from PsychiatryNLPKit.model import HFEmbeddingLLM, HFGenerativeLLM
146
+
147
+ sections = [Section(text="The quick brown fox jumps over the lazy dog.", name="p1")]
148
+ data = TextData(sections=sections, lang="en")
149
+
150
+ # Attach models (lazy-loaded on first use)
151
+ data.embedding_model = HFEmbeddingLLM("unsloth/embeddinggemma-300m")
152
+ data.generative_model = HFGenerativeLLM("unsloth/Llama-3.2-1B")
153
+
154
+ # Syntax: sentence length
155
+ lengths = pnlp_a.sentence_length(data.pos_tags)
156
+ # → {"p1": {"sentence_length": 10.0}}
157
+
158
+ # Semantic coherence: adjacent sentence similarity
159
+ coherence = pnlp_a.sentence_level_cosine_similarity(data.sentence_embedding_vectors)
160
+ # → {"p1": {"sentence_level_cosine_similarity": 0.73}}
161
+
162
+ # Perplexity: generative model on paragraphs
163
+ perplexity = pnlp_a.paragraph_level_perplexity(
164
+ data.paragraph_generative_tokens, data.generative_model
165
+ )
166
+ # → {"p1": {"paragraph_level_perplexity": 42.5}}
167
+
168
+ # Graph: structural word-transition network metrics
169
+ graph_metrics = pnlp_a.structural_graph(data.content_words)
170
+ # → {"p1": {"nodes_count": 8.0, "edges_count": 9.0, ...}}
171
+
172
+ # Density: PCA-based semantic space compression (uses token-level embeddings)
173
+ density = pnlp_a.pca_density_metrics(data.token_embedding_vectors)
174
+ # → {"p1": {"Ncomp_90": 3.0, "Pcomp_90": 0.375, "ExVar_2": 0.45}}
175
+
176
+ # Lexicon: filler word disfluency count
177
+ fillers = pnlp_a.filler_words_count(data.pos_tags, language="en")
178
+ # → {"p1": {"filler_words_count": 0, "filler_words_ratio": 0.0}}
179
+ ```
180
+
181
+ ---
182
+
183
+ ## Installation
184
+
185
+ ### From PyPI
186
+
187
+ ```bash
188
+ pip install PsychiatryNLPKit # core package
189
+ pip install PsychiatryNLPKit[graph] # + networkx (for structural_graph)
190
+ pip install PsychiatryNLPKit[image] # + pillow (for image_text_similarity)
191
+ pip install PsychiatryNLPKit[dev] # + pytest, pyright, sphinx (for development)
192
+
193
+ # All extras at once:
194
+ pip install PsychiatryNLPKit[graph,image,dev]
195
+ ```
196
+
197
+ ### From source
198
+
199
+ ```bash
200
+ git clone https://github.com/rukun-dou/PsychiatryNLPKit.git
201
+ cd PsychiatryNLPKit
202
+ pip install -e ".[graph,image,dev]"
203
+ ```
204
+
205
+ **Requirements:** Python 3.12+, [Hugging Face token](https://huggingface.co/settings/tokens) (for gated models). Set the `HF_TOKEN` environment variable before loading any model that requires authentication.
206
+
207
+ ---
208
+
209
+ ## Configuration
210
+
211
+ ### Device detection
212
+
213
+ PsychiatryNLPKit automatically detects and uses the fastest available hardware:
214
+
215
+ ```
216
+ CUDA (NVIDIA) → MPS (Apple Silicon) → Intel XPU → CPU
217
+ ```
218
+
219
+ ```python
220
+ from PsychiatryNLPKit import device, hf_token
221
+
222
+ print(device) # torch.device('cuda') or 'mps' or 'cpu'
223
+ print(hf_token) # str | None (read from HF_TOKEN env var)
224
+ ```
225
+
226
+ Models are loaded with `bfloat16` precision on GPUs for memory efficiency and faster inference. All deep learning computations (tokenization, embedding generation, perplexity scoring, image-text similarity) run on the detected device.
227
+
228
+ ### Logging
229
+
230
+ ```python
231
+ import logging
232
+ import PsychiatryNLPKit as pnlp
233
+
234
+ pnlp.configure_logging(level=logging.DEBUG) # default is INFO
235
+ ```
236
+
237
+ The package uses a dedicated logger (`PsychiatryNLPKit`) with `propagate=False`, so messages won't interfere with your application's root logger. Calling `configure_logging` multiple times is safe (duplicate handlers are guarded against).
238
+
239
+ ---
240
+
241
+ ## Data Model
242
+
243
+ ### TextData
244
+
245
+ The central container for all analysis. It holds raw text sections and computes linguistic properties lazily on first access, caching results to avoid redundant computation:
246
+
247
+ ```python
248
+ from PsychiatryNLPKit.data import Section, TextData
249
+
250
+ sections = [
251
+ Section(text="First paragraph.", name="p1"),
252
+ Section(text="Second paragraph.", name="p2"),
253
+ ]
254
+ data = TextData(sections=sections, lang="en")
255
+ ```
256
+
257
+ | Property | Requires model | Returns | Description |
258
+ |---|---|---|---|
259
+ | `data` | No | `dict[str, str]` | Raw section text keyed by name |
260
+ | `sentences` | No | `dict[str, list[str]]` | Sentences per section (regex-split) |
261
+ | `pos_tags` | No | `dict[str, list[list[tuple[str,str,str]]]]` | POS-tagged sentences: `(word, lemma, tag)` tuples |
262
+ | `syntax_trees` | No | `dict[str, list[benepar.Tree]]` | Constituency parse trees per sentence |
263
+ | `token_embedding_vectors` | `embedding_model` | `dict[str, torch.Tensor]` | Token-level embeddings, shape `(n_tokens, dim)` |
264
+ | `attention_scores` | `embedding_model` | `dict[str, torch.Tensor]` | Aggregated attention scores, shape `(n_tokens, n_tokens)` |
265
+ | `sentence_embedding_vectors` | `embedding_model` | `dict[str, torch.Tensor]` | Sentence-level embeddings, shape `(n_sentences, dim)` |
266
+ | `content_words` | No | `dict[str, list[str]]` | Content words (nouns, verbs, adjectives, adverbs) per section |
267
+ | `content_word_embedding_vectors` | No | `dict[str, torch.Tensor]` | Word2Vec embeddings for content words, shape `(n_words, dim)` |
268
+ | `paragraph_generative_tokens` | `generative_model` | `dict[str, dict[str, torch.Tensor]]` | Tokenized paragraphs (input_ids + attention_mask) |
269
+ | `sentence_generative_tokens` | `generative_model` | `dict[str, dict[str, torch.Tensor]]` | Tokenized sentences |
270
+
271
+ ### Section
272
+
273
+ A named text segment:
274
+
275
+ ```python
276
+ from PsychiatryNLPKit.data import Section
277
+
278
+ section = Section(text="Clinical interview transcript...", name="session_01")
279
+ ```
280
+
281
+ Each section has a `text` attribute (the raw string) and an optional `name` used as the dictionary key in all analysis outputs. If no name is provided, sections are auto-named `section_0`, `section_1`, etc.
282
+
283
+ ### ImageData
284
+
285
+ For image-text similarity analysis:
286
+
287
+ ```python
288
+ from PsychiatryNLPKit.data import ImageData
289
+
290
+ image = ImageData(path="patient_response.jpg", name="p1")
291
+ # Access via image.image → PIL.Image.Image (lazy-loaded)
292
+ ```
293
+
294
+ ---
295
+
296
+ ## Batch Analysis
297
+
298
+ `BatchAnalyzer` is the high-level orchestrator. It runs selected analyses on a `TextData` object and collects all results into a single structured container:
299
+
300
+ ```python
301
+ from PsychiatryNLPKit.analysis import BatchAnalyzer, AnalysisResult
302
+
303
+ # Run every analysis (requires all models)
304
+ result = BatchAnalyzer(
305
+ data,
306
+ mask_filling_model=mask_lm, # for pseudo-perplexity
307
+ vit_model=vit, # for image-text similarity
308
+ image_paths={"p1": "img1.jpg", "p2": "img2.jpg"}, # per-section images
309
+ ).run()
310
+
311
+ # Run a subset
312
+ result = BatchAnalyzer(
313
+ data,
314
+ included_analyses=["sentence_length", "adverb_ratio", "filler_words_count"],
315
+ ).run()
316
+
317
+ # Exclude specific analyses from the full set
318
+ result = BatchAnalyzer(
319
+ data,
320
+ included_analyses="all",
321
+ excluded_analyses=[
322
+ "paragraph_level_pseudo_perplexity", # requires mask-filling model
323
+ "sentence_level_pseudo_perplexity",
324
+ "structural_graph", # requires networkx extra
325
+ "image_text_similarity", # requires pillow extra and image paths
326
+ ],
327
+ ).run()
328
+ ```
329
+
330
+ ### Parameters
331
+
332
+ | Parameter | Type | Description |
333
+ |---|---|---|
334
+ | `text_data` | `TextData` | The data container with sections and optional model references |
335
+ | `included_analyses` | `"all"` or `list[str]` | Default `"all"` runs every registered analysis. Pass an explicit list for a subset |
336
+ | `excluded_analyses` | `list[str] \| None` | Function names to remove from the inclusion set. Every excluded name must be in the resolved inclusion list; otherwise an `AssertionError` is raised |
337
+ | `mask_filling_model` | `HFMaskFillingModel \| None` | Required if any pseudo-perplexity function remains after filtering |
338
+ | `vit_model` | `HuggingFaceViTModel \| None` | Required if `"image_text_similarity"` is in the analysis set |
339
+ | `image_paths` | `dict[str, str] \| None` | Maps section name → image file path. Must cover every section in `text_data.section_names` when image analysis is requested |
340
+
341
+ ### AnalysisResult
342
+
343
+ | Attribute | Type | Description |
344
+ |---|---|---|
345
+ | `results` | `dict[str, dict[str, float]]` | Merged per-section metrics keyed by section name, then metric name |
346
+ | `sections` | `list[str]` | Section names in order (from `TextData.section_names`) |
347
+ | `analyses_run` | `list[str]` | Names of analyses that executed successfully |
348
+ | `errors` | `dict[str, str]` | Per-function failures: `{function_name: error_message}` |
349
+
350
+ ---
351
+
352
+ ## Analysis Functions Reference
353
+
354
+ All functions accept a `sections` parameter (`list[str] \| None`) to restrict processing to specific sections. When `None`, all available sections are processed. Empty or missing sections receive `float("nan")`. Language-dependent functions support `"en"` and `"fr"`.
355
+
356
+ ### Syntax (`pnlp.analysis.Syntax`) — 13 functions
357
+
358
+ Measures of sentence structure, part-of-speech distributions, and syntax tree complexity derived from clinical research on thought disorder.
359
+
360
+ | Function | Required input | Returns | Clinical basis |
361
+ |---|---|---|---|
362
+ | `sentence_length` | `pos_tags` | `{section: {"sentence_length": float}}` | Poverty of content (Bilgrami et al., 2022) |
363
+ | `syntax_depth` | `syntax_trees` | `{section: {"syntax_depth": float}}` | Reduced complexity predicts psychosis onset (Morice & Ingram, 1983) |
364
+ | `unique_pos_tags` | `pos_tags` | `{section: {"unique_pos_tags": int}}` | Linguistic diversity marker |
365
+ | `adverb_ratio` | `pos_tags`, `lang` | `{section: {"adverb_ratio": float, "adverb_count": int}}` | Associated with negative symptoms (Haas et al., 2020) |
366
+ | `coordinating_conjunction_ratio` | `pos_tags`, `lang` | `{section: {"coordinating_conjunction_ratio": float}}` | Negative symptom correlation (Haas et al., 2020) |
367
+ | `adjective_ratio` | `pos_tags`, `lang` | `{section: {"adjective_ratio": float}}` | — |
368
+ | `pronoun_ratio` | `pos_tags`, `lang` | `{section: {"pronoun_ratio": float}}` | Predicts semantic similarity patterns (He et al., 2024) |
369
+ | `determiner_ratio` | `pos_tags`, `lang` | `{section: {"determiner_ratio": float}}` | Negative thought disorder marker (Bilgrami et al., 2022) |
370
+ | `modal_auxiliary_verb_ratio` | `pos_tags`, `lang` | `{section: {"modal_auxiliary_verb_ratio": float}}` | — |
371
+ | `stop_words_ratio` | `pos_tags`, `lang` | `{section: {"stop_words_ratio": float}}` | Baseline lexical measure |
372
+ | `clause_count` | `syntax_trees` | `{section: {"clause_count": int}}` | Psychosis onset prediction (Bilgrami et al., 2022) |
373
+ | `noun_group_count` | `syntax_trees` | `{section: {"noun_group_count": int}}` | — |
374
+ | `adjective_sentence_length` | `syntax_trees` | `{section: {"adjective_sentence_length": float}}` | — |
375
+
376
+ POS tag aliases support both Penn Treebank (`JJ`, `NN`, `RB`) and Universal Dependencies (`ADJ`, `NOUN`, `ADV`) schemes.
377
+
378
+ ### Similarity (`pnlp.analysis.Similarity`) — 2 functions
379
+
380
+ Cosine similarity between adjacent embeddings to quantify semantic coherence:
381
+
382
+ | Function | Required input | Returns | Clinical basis |
383
+ |---|---|---|---|
384
+ | `word_level_cosine_similarity` | `content_word_embedding_vectors` | `{section: {"word_level_cosine_similarity": float}}` | Correlated with tangentiality, circumstantiality, derailment (Bilgrami et al., 2022; Elvevag et al., 2007; He et al., 2024) |
385
+ | `sentence_level_cosine_similarity` | `sentence_embedding_vectors` | `{section: {"sentence_level_cosine_similarity": float}}` | Detects incoherent speech in formal thought disorder (same references) |
386
+
387
+ ### Perplexity (`pnlp.analysis.Perplexity`) — 4 functions
388
+
389
+ Language model perplexity at paragraph and sentence levels using both generative (causal LM) and masked language models:
390
+
391
+ | Function | Model type | Required input | Returns | Clinical basis |
392
+ |---|---|---|---|---|
393
+ | `paragraph_level_perplexity` | Generative (causal LM) | `paragraph_generative_tokens`, `generative_model` | `{section: {"paragraph_level_perplexity": float}}` | High perplexity predicts delusion and unusual thought content (Alqahtani et al., 2022; He et al., 2024) |
394
+ | `sentence_level_perplexity` | Generative (causal LM) | `sentence_generative_tokens`, `generative_model` | `{section: {"sentence_level_perplexity": float}}` | Same references |
395
+ | `paragraph_level_pseudo_perplexity` | Masked LM | `data.data` (raw text), `mask_filling_model` | `{section: {"paragraph_level_pseudo_perplexity": float}}` | Same references |
396
+ | `sentence_level_pseudo_perplexity` | Masked LM | `data.data` (raw text), `mask_filling_model` | `{section: {"sentence_level_pseudo_perplexity": float}}` | Same references |
397
+
398
+ ### Graph (`pnlp.analysis.Graph`) — 1 function
399
+
400
+ Constructs a directed, weighted word-transition graph from lemmatized content words and computes network metrics:
401
+
402
+ | Function | Required input | Returns | Clinical basis |
403
+ |---|---|---|---|
404
+ | `structural_graph` | `content_words` | `{section: {nodes_count, edges_count, average_degree, density, diameter, average_shortest_path_length, largest_connected_component, largest_strongly_connected_component, lcc/n, lsc/n, edge_weight_repetition_index, lcc_z_score, lsc_z_score, aspl_z_score, degree_distribution_z_score}}` | Schizophrenia patients show smaller connected components and lower ASPL (Nikzad et al., 2022) |
405
+
406
+ Parameters: `directed=True`, `weighted=True`, `n_random_graphs=1000` (for z-score computation against a null distribution).
407
+
408
+ ### Density (`pnlp.analysis.Density`) — 2 functions
409
+
410
+ Measures of semantic space dimensionality derived from token embeddings:
411
+
412
+ | Function | Required input | Returns | Clinical basis |
413
+ |---|---|---|---|
414
+ | `pca_density_metrics` | `token_embedding_vectors` | `{section: {Ncomp_90, Pcomp_90, ExVar_2}}` | Schizophrenia patients show altered semantic compressibility (Palominos et al., 2025) |
415
+ | `intrinsic_dimensionality_density` | `token_embedding_vectors` | `{section: {ID_MLE}}` | Lower intrinsic dimensionality indicates more redundant speech (same reference) |
416
+
417
+ PCA is applied in **token space** (features = tokens, i.e. `X.T`) so metrics reflect how many token directions are needed to explain semantic variance. Total paragraph length must be controlled during statistical analysis.
418
+
419
+ ### Lexicon (`pnlp.analysis.Lexicon`) — 1 function
420
+
421
+ | Function | Required input | Returns | Clinical basis |
422
+ |---|---|---|---|
423
+ | `filler_words_count` | `pos_tags`, `lang` | `{section: {filler_words_count, filler_words_ratio}}` | Disfluencies correlate with symptom severity and PANSS negative scores (Vail et al., 2018; Liebenthal et al., 2022) |
424
+
425
+ Filler word lists are loaded from the packaged `resources/filler_words.json` resource. The `averaging_method` parameter controls computation: `"macro"` averages per-sentence filler ratios, `"micro"` computes total fillers / total words across the section (default: `"macro"`).
426
+
427
+ ### ImageSimilarity (`pnlp.analysis.ImageSimilarity`) — 1 function
428
+
429
+ | Function | Required input | Returns | Clinical basis |
430
+ |---|---|---|---|
431
+ | `image_text_similarity` | `image`, `text`, `vit_model` | `{section: {"image_text_similarity": float}}` | Lower CLIP scores predict higher conceptual disorganization (He et al., 2024) |
432
+
433
+ The image argument accepts a PIL Image object or a file path. Text is split into chunks that fit the model's context window, encoded at the token level alongside patch-level visual embeddings, and pairwise cosine similarity is aggregated with mean pooling.
434
+
435
+ ---
436
+
437
+ ## Model Wrappers
438
+
439
+ All models use lazy loading: the underlying Hugging Face model is downloaded and loaded only when first accessed. Models are unloaded after each analysis pass to free GPU memory.
440
+
441
+ | Class | Purpose | Example model ID |
442
+ |---|---|---|
443
+ | `HFEmbeddingLLM` | Sentence/word embedding models | `unsloth/embeddinggemma-300m` |
444
+ | `HFGenerativeLLM` | Autoregressive causal LMs | `unsloth/Llama-3.2-1B` |
445
+ | `HFMaskFillingModel` | Masked language models | `google-bert/bert-base-multilingual-uncased` |
446
+ | `HuggingFaceViTModel` | Vision-language (SigLIP/CLIP-style) | `openai/clip-vit-base-patch16` |
447
+
448
+ ```python
449
+ from PsychiatryNLPKit.model import HFEmbeddingLLM, HFGenerativeLLM, HFMaskFillingModel, HuggingFaceViTModel
450
+
451
+ embedding = HFEmbeddingLLM("unsloth/embeddinggemma-300m")
452
+ embedding.load()
453
+ # embedding.model.encode(...) # use the underlying model directly
454
+ embedding.unload() # frees GPU memory
455
+ ```
456
+
457
+ ---
458
+
459
+ ## Data Formats
460
+
461
+ ### Input: Text sections
462
+
463
+ The primary input is a list of `Section` objects, each containing raw text and an optional name. Sections can represent individual interview responses, paragraphs from clinical notes, or any other text unit.
464
+
465
+ For batch processing from files, a typical workflow looks like:
466
+
467
+ ```python
468
+ import csv
469
+ from PsychiatryNLPKit.data import Section, TextData
470
+
471
+ # Read from CSV: columns "id", "text"
472
+ sections = []
473
+ with open("clinical_corpus.csv", newline="") as f:
474
+ reader = csv.DictReader(f)
475
+ for row in reader:
476
+ sections.append(Section(text=row["text"], name=row["id"]))
477
+
478
+ data = TextData(sections=sections, lang="en")
479
+ ```
480
+
481
+ ### Output: AnalysisResult
482
+
483
+ The `AnalysisResult` container provides three access patterns:
484
+
485
+ ```python
486
+ # By section → metric
487
+ result.results["p1"]["sentence_length"] # 12.5
488
+
489
+ # Export to pandas DataFrame for statistical analysis
490
+ import pandas as pd
491
+ records = []
492
+ for section in result.sections:
493
+ record = {"section": section}
494
+ record.update({k: v for k, v in result.results[section].items()})
495
+ records.append(record)
496
+ df = pd.DataFrame(records)
497
+
498
+ # Check for failures
499
+ if result.errors:
500
+ print("Failed analyses:", result.errors)
501
+ ```
502
+
503
+ ---
504
+
505
+ ## Project Structure
506
+
507
+ ```
508
+ PsychiatryNLPKit/
509
+ ├── config.py # Device detection, logging setup, HF token
510
+ ├── data/
511
+ │ ├── Text.py # Section, TextData (lazy-computed properties)
512
+ │ ├── Image.py # ImageData container
513
+ │ └── _resources.py # Packaged resource paths
514
+ ├── model/
515
+ │ ├── LLM.py # HFEmbeddingLLM, HFGenerativeLLM, HFMaskFillingModel
516
+ │ └── ViT.py # HuggingFaceViTModel (SigLIP/CLIP)
517
+ ├── analysis/
518
+ │ ├── Syntax.py # 13 syntax functions
519
+ │ ├── Similarity.py # 2 similarity functions
520
+ │ ├── Perplexity.py # 4 perplexity functions
521
+ │ ├── Graph.py # structural_graph (network metrics + z-scores)
522
+ │ ├── Density.py # PCA density + intrinsic dimensionality
523
+ │ ├── Lexicon.py # Filler word disfluency analysis
524
+ │ ├── ImageSimilarity.py # ViT-based image-text similarity
525
+ │ └── batch.py # BatchAnalyzer, AnalysisResult
526
+ ├── resources/
527
+ │ ├── filler_words.json # EN/FR filler word lists
528
+ │ └── word2vec.model # Gensim KeyedVectors (pre-trained)
529
+ └── tests/ # Unit and integration tests
530
+ ```
531
+
532
+ ---
533
+
534
+ ## BibTeX Citation
535
+
536
+ If you use PsychiatryNLPKit in your research, please cite:
537
+
538
+ ```bibtex
539
+ @software{psychiatrynlpkit2026,
540
+ author = {Dou, Rukun and Wei, Tiana and Voppel, Alban Elias},
541
+ title = {PsychiatryNLPKit: Computational linguistics toolkit for psychosis risk assessment and thought disorder analysis},
542
+ year = {2026},
543
+ url = {https://github.com/rukun-dou/PsychiatryNLPKit},
544
+ version = {0.1.0},
545
+ license = {MIT}
546
+ }
547
+ ```
548
+
549
+ ---
550
+
551
+ ## References
552
+
553
+ All analysis functions include their theoretical basis and primary references in their docstrings. Key publications underpinning this toolkit:
554
+
555
+ - Alqahtani, A., Kayi, E. S., Hamidian, S., Compton, M., & Diab, M. (2022). A quantitative and qualitative analysis of schizophrenia language. *Proceedings of the 13th International Workshop on Health Text Mining and Information Analysis (LOUHI)*, 173–183.
556
+ - Bilgrami, Z. R., et al. (2022). Construct validity for computational linguistic metrics in individuals at clinical risk for psychosis. *Schizophrenia Research*, 245, 90–96.
557
+ - Elvevag, B., Palmer, B. W., Gold, J. M., & Jeste, D. V. (2007). Semantic coherence of speech in schizophrenia and bipolar disorder. *Schizophrenia Research*, 93(1-3), 304–316.
558
+ - Haas, S. S., et al. (2020). POS ratios and negative symptom correlation in psychosis.
559
+ - He, R., Palominos, C., Zhang, H., Alonso-Sánchez, M. F., Palaniyappan, L., & Hinzen, W. (2024). Navigating the semantic space: Unraveling the structure of meaning in psychosis using different computational language models. *Psychiatry Research*, 333, 115752.
560
+ - Liebenthal, E., et al. (2022). Linguistic and non-linguistic markers of disorganization in psychotic illness. *Schizophrenia Research*, 259, 111–120.
561
+ - Morice, R., & Ingram, J. C. I. (1983). Verbal fluency as a screening test for schizophrenia. *Neuropsychobiology*, 10(3), 158–161.
562
+ - Nikzad, A. H., et al. (2022). Who does what to whom? graph representations of action-predication in speech relate to psychopathological dimensions of psychosis. *Schizophrenia*, 8(1), 58.
563
+ - Palominos, C., et al. (2025). Lexical meaning is lower dimensional in psychosis. *Scientific Reports*, 16(1), 859.
564
+ - Vail, A. K., Liebson, E., Baker, J. T., & Morency, L.-P. (2018). Toward objective, multifaceted characterization of psychotic disorders: Lexical, structural, and disfluency markers of spoken language. *Proceedings of the 20th ACM International Conference on Multimodal Interaction*, 170–178.
565
+
566
+ ---
567
+
568
+ ## License
569
+
570
+ [MIT License](LICENSE) -- Copyright (c) 2026 Rukun Dou, Tiana Wei, Alban Elias Voppel