personality-questionnaire 2.0.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.
- personality_questionnaire-2.0.0/.gitignore +150 -0
- personality_questionnaire-2.0.0/LICENSE +21 -0
- personality_questionnaire-2.0.0/PKG-INFO +185 -0
- personality_questionnaire-2.0.0/README.md +145 -0
- personality_questionnaire-2.0.0/personality_questionnaire/__init__.py +113 -0
- personality_questionnaire-2.0.0/personality_questionnaire/api.py +16 -0
- personality_questionnaire-2.0.0/personality_questionnaire/assets/bfi-2_questionnaire.tsv +61 -0
- personality_questionnaire-2.0.0/personality_questionnaire/bfi2.py +200 -0
- personality_questionnaire-2.0.0/personality_questionnaire/cli/__init__.py +7 -0
- personality_questionnaire-2.0.0/personality_questionnaire/cli/main.py +407 -0
- personality_questionnaire-2.0.0/personality_questionnaire/cli/prompt.py +123 -0
- personality_questionnaire-2.0.0/personality_questionnaire/cli/render.py +99 -0
- personality_questionnaire-2.0.0/personality_questionnaire/core/__init__.py +1 -0
- personality_questionnaire-2.0.0/personality_questionnaire/core/theme.py +172 -0
- personality_questionnaire-2.0.0/personality_questionnaire/instruments/__init__.py +14 -0
- personality_questionnaire-2.0.0/personality_questionnaire/instruments/bfi2.py +322 -0
- personality_questionnaire-2.0.0/personality_questionnaire/instruments/vasf.py +169 -0
- personality_questionnaire-2.0.0/personality_questionnaire/io.py +185 -0
- personality_questionnaire-2.0.0/personality_questionnaire/provenance.py +148 -0
- personality_questionnaire-2.0.0/personality_questionnaire/py.typed +0 -0
- personality_questionnaire-2.0.0/personality_questionnaire/registry.py +334 -0
- personality_questionnaire-2.0.0/personality_questionnaire/scoring.py +380 -0
- personality_questionnaire-2.0.0/personality_questionnaire/vasf.py +42 -0
- personality_questionnaire-2.0.0/pyproject.toml +139 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Project
|
|
2
|
+
.vscode
|
|
3
|
+
|
|
4
|
+
# Byte-compiled / optimized / DLL files
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*$py.class
|
|
8
|
+
|
|
9
|
+
# C extensions
|
|
10
|
+
*.so
|
|
11
|
+
|
|
12
|
+
# Distribution / packaging
|
|
13
|
+
.Python
|
|
14
|
+
build/
|
|
15
|
+
develop-eggs/
|
|
16
|
+
dist/
|
|
17
|
+
downloads/
|
|
18
|
+
eggs/
|
|
19
|
+
.eggs/
|
|
20
|
+
lib/
|
|
21
|
+
lib64/
|
|
22
|
+
parts/
|
|
23
|
+
sdist/
|
|
24
|
+
var/
|
|
25
|
+
wheels/
|
|
26
|
+
pip-wheel-metadata/
|
|
27
|
+
share/python-wheels/
|
|
28
|
+
*.egg-info/
|
|
29
|
+
.installed.cfg
|
|
30
|
+
*.egg
|
|
31
|
+
MANIFEST
|
|
32
|
+
|
|
33
|
+
# PyInstaller
|
|
34
|
+
# Usually these files are written by a python script from a template
|
|
35
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
36
|
+
*.manifest
|
|
37
|
+
*.spec
|
|
38
|
+
|
|
39
|
+
# Installer logs
|
|
40
|
+
pip-log.txt
|
|
41
|
+
pip-delete-this-directory.txt
|
|
42
|
+
|
|
43
|
+
# Unit test / coverage reports
|
|
44
|
+
htmlcov/
|
|
45
|
+
.tox/
|
|
46
|
+
.nox/
|
|
47
|
+
.coverage
|
|
48
|
+
.coverage.*
|
|
49
|
+
.cache
|
|
50
|
+
nosetests.xml
|
|
51
|
+
coverage.xml
|
|
52
|
+
*.cover
|
|
53
|
+
*.py,cover
|
|
54
|
+
.hypothesis/
|
|
55
|
+
.pytest_cache/
|
|
56
|
+
|
|
57
|
+
# Translations
|
|
58
|
+
*.mo
|
|
59
|
+
*.pot
|
|
60
|
+
|
|
61
|
+
# Django stuff:
|
|
62
|
+
*.log
|
|
63
|
+
local_settings.py
|
|
64
|
+
db.sqlite3
|
|
65
|
+
db.sqlite3-journal
|
|
66
|
+
|
|
67
|
+
# Flask stuff:
|
|
68
|
+
instance/
|
|
69
|
+
.webassets-cache
|
|
70
|
+
|
|
71
|
+
# Scrapy stuff:
|
|
72
|
+
.scrapy
|
|
73
|
+
|
|
74
|
+
# Sphinx documentation
|
|
75
|
+
docs/_build/
|
|
76
|
+
|
|
77
|
+
# PyBuilder
|
|
78
|
+
target/
|
|
79
|
+
|
|
80
|
+
# Jupyter Notebook
|
|
81
|
+
.ipynb_checkpoints
|
|
82
|
+
|
|
83
|
+
# IPython
|
|
84
|
+
profile_default/
|
|
85
|
+
ipython_config.py
|
|
86
|
+
|
|
87
|
+
# pyenv
|
|
88
|
+
.python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
#Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
98
|
+
__pypackages__/
|
|
99
|
+
|
|
100
|
+
# Celery stuff
|
|
101
|
+
celerybeat-schedule
|
|
102
|
+
celerybeat.pid
|
|
103
|
+
|
|
104
|
+
# SageMath parsed files
|
|
105
|
+
*.sage.py
|
|
106
|
+
|
|
107
|
+
# Environments
|
|
108
|
+
.env
|
|
109
|
+
.venv
|
|
110
|
+
env/
|
|
111
|
+
venv/
|
|
112
|
+
ENV/
|
|
113
|
+
env.bak/
|
|
114
|
+
venv.bak/
|
|
115
|
+
|
|
116
|
+
# Spyder project settings
|
|
117
|
+
.spyderproject
|
|
118
|
+
.spyproject
|
|
119
|
+
|
|
120
|
+
# Rope project settings
|
|
121
|
+
.ropeproject
|
|
122
|
+
|
|
123
|
+
# mkdocs documentation
|
|
124
|
+
/site
|
|
125
|
+
|
|
126
|
+
# mypy
|
|
127
|
+
.mypy_cache/
|
|
128
|
+
.dmypy.json
|
|
129
|
+
dmypy.json
|
|
130
|
+
|
|
131
|
+
# Pyre type checker
|
|
132
|
+
.pyre/
|
|
133
|
+
|
|
134
|
+
# project specific
|
|
135
|
+
dist/
|
|
136
|
+
site/
|
|
137
|
+
coverage_html/
|
|
138
|
+
coverage.xml
|
|
139
|
+
.coverage
|
|
140
|
+
.venv/
|
|
141
|
+
.venv-ci/
|
|
142
|
+
.ruff_cache/
|
|
143
|
+
|
|
144
|
+
# macOS
|
|
145
|
+
.DS_Store
|
|
146
|
+
|
|
147
|
+
# Participant data. Records are the operator's to keep and never enter git.
|
|
148
|
+
data/
|
|
149
|
+
*_answers_int.csv
|
|
150
|
+
*_scores.csv
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Fodor Ádám
|
|
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,185 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: personality_questionnaire
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Administer, score and record validated personality and affect questionnaires.
|
|
5
|
+
Project-URL: Documentation, https://fodorad.github.io/personality_questionnaire/
|
|
6
|
+
Project-URL: Issues, https://github.com/fodorad/personality_questionnaire/issues
|
|
7
|
+
Project-URL: Source, https://github.com/fodorad/personality_questionnaire
|
|
8
|
+
Author-email: fodorad <fodorad201@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: bfi-2,big five,personality,psychometrics,questionnaire,vas-f
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering
|
|
18
|
+
Requires-Python: >=3.12
|
|
19
|
+
Requires-Dist: numpy
|
|
20
|
+
Provides-Extra: analysis
|
|
21
|
+
Requires-Dist: matplotlib; extra == 'analysis'
|
|
22
|
+
Requires-Dist: scipy>=1.11; extra == 'analysis'
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: coverage; extra == 'dev'
|
|
25
|
+
Requires-Dist: pre-commit; extra == 'dev'
|
|
26
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
27
|
+
Requires-Dist: ty; extra == 'dev'
|
|
28
|
+
Provides-Extra: docs
|
|
29
|
+
Requires-Dist: furo; extra == 'docs'
|
|
30
|
+
Requires-Dist: myst-parser; extra == 'docs'
|
|
31
|
+
Requires-Dist: sphinx-autoapi; extra == 'docs'
|
|
32
|
+
Requires-Dist: sphinx-autobuild; extra == 'docs'
|
|
33
|
+
Requires-Dist: sphinx>=8.0; extra == 'docs'
|
|
34
|
+
Provides-Extra: mysql
|
|
35
|
+
Requires-Dist: pymysql>=1.1; extra == 'mysql'
|
|
36
|
+
Provides-Extra: ui
|
|
37
|
+
Requires-Dist: nicegui>=2.0; extra == 'ui'
|
|
38
|
+
Requires-Dist: sqlalchemy>=2.0; extra == 'ui'
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
41
|
+
<div align="center">
|
|
42
|
+
|
|
43
|
+
<!-- PNG, not the SVG: PyPI strips SVG from project descriptions, so an SVG
|
|
44
|
+
logo silently vanishes there while rendering fine on GitHub. The SVG is
|
|
45
|
+
the source of truth and is used by the docs site and the application. -->
|
|
46
|
+
<img src="https://raw.githubusercontent.com/fodorad/personality_questionnaire/main/docs/assets/logo.png" alt="personality_questionnaire" width="112"/>
|
|
47
|
+
|
|
48
|
+
**Administer, score and record validated personality and affect questionnaires.**
|
|
49
|
+
|
|
50
|
+
[](https://github.com/fodorad/personality_questionnaire/releases)
|
|
51
|
+
[](https://pypi.org/project/personality_questionnaire/)
|
|
52
|
+
[](https://github.com/fodorad/personality_questionnaire/actions)
|
|
53
|
+
[](https://codecov.io/gh/fodorad/personality_questionnaire)
|
|
54
|
+
[](https://fodorad.github.io/personality_questionnaire/)
|
|
55
|
+
<br/>
|
|
56
|
+
[](https://www.python.org)
|
|
57
|
+
[](https://github.com/astral-sh/ruff)
|
|
58
|
+
[](LICENSE)
|
|
59
|
+
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
# What this is
|
|
65
|
+
|
|
66
|
+
Collecting validated self-reports is the unglamorous half of an affective-computing
|
|
67
|
+
pipeline. This package administers published psychometric instruments, scores them
|
|
68
|
+
correctly, and records every response with the provenance needed to reproduce the
|
|
69
|
+
score months later.
|
|
70
|
+
|
|
71
|
+
It is built around one idea: **an instrument is data, not code.** Items, response
|
|
72
|
+
ranges, subscale membership and reverse keys are declared as values; a single
|
|
73
|
+
vectorised scorer turns responses into scores without knowing which questionnaire it
|
|
74
|
+
is holding. Adding an instrument adds no arithmetic.
|
|
75
|
+
|
|
76
|
+
# Instruments
|
|
77
|
+
|
|
78
|
+
| Key | Instrument | Items | Scale | Scores |
|
|
79
|
+
| --- | --- | --- | --- | --- |
|
|
80
|
+
| `bfi2` | Big Five Inventory-2 | 60 | 1–5 | 5 domains, 15 facets |
|
|
81
|
+
| `vasf` | Visual Analogue Scale to Evaluate Fatigue Severity | 18 | 0–10 | Fatigue, Energy, composite |
|
|
82
|
+
|
|
83
|
+
<sub>BFI-2: Soto & John (2017). VAS-F: Lee, Hicks & Nino-Murcia (1991). See
|
|
84
|
+
[docs/instruments.md](docs/instruments.md) for full citations and licence notes.</sub>
|
|
85
|
+
|
|
86
|
+
# Quickstart
|
|
87
|
+
|
|
88
|
+
Score responses you already have:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install personality_questionnaire
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
import personality_questionnaire as pq
|
|
96
|
+
|
|
97
|
+
result = pq.score(pq.get("bfi2"), answers) # answers: (n_participants, 60)
|
|
98
|
+
result.by_level("domain") # {"openness": array([...]), ...}
|
|
99
|
+
result.as_dict() # one participant, every subscale
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Administer one at the terminal:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pq list # what is available
|
|
106
|
+
pq info bfi2 # items, subscales, citation
|
|
107
|
+
pq run bfi2 --participant P01 # ask the questions, score the answers
|
|
108
|
+
pq score bfi2 --input answers.csv # score a file
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
# How it works
|
|
112
|
+
|
|
113
|
+
```mermaid
|
|
114
|
+
flowchart LR
|
|
115
|
+
I["instruments/<br/><i>pure data</i>"] --> R[registry]
|
|
116
|
+
R --> S["scoring<br/><i>one vectorised scorer</i>"]
|
|
117
|
+
S --> C[cli]
|
|
118
|
+
S --> D[db]
|
|
119
|
+
S --> U[ui]
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
| Module | Responsibility |
|
|
123
|
+
| --- | --- |
|
|
124
|
+
| `registry.py` | `Item`, `Subscale`, `Questionnaire` — what an instrument *is*, plus validation |
|
|
125
|
+
| `instruments/` | One module per questionnaire. Data only, no arithmetic |
|
|
126
|
+
| `scoring.py` | The single scorer: reverse-keying, subscale means, normalisation, pre/post deltas |
|
|
127
|
+
| `io.py` | Reading and writing responses and scores |
|
|
128
|
+
| `provenance.py` | Package version, git SHA, instrument hash for each record |
|
|
129
|
+
| `cli/` | `pq list \| info \| run \| score` |
|
|
130
|
+
|
|
131
|
+
# Design decisions
|
|
132
|
+
|
|
133
|
+
**Instruments are Python literals, not data files.** A literal is checked by the type
|
|
134
|
+
checker, validated at import, and present in the wheel by construction. A shipped CSV
|
|
135
|
+
is checked by nothing until a participant has already answered every item — and the
|
|
136
|
+
two scale files this repo used to carry were never read by any code path *and*
|
|
137
|
+
misspelled `neuroticism`, which is exactly how unread data drifts.
|
|
138
|
+
|
|
139
|
+
**Reverse-keying belongs to the subscale, not the item.** The VAS-F scores its five
|
|
140
|
+
energy items forward in `Energy` and reversed in `Fatigue (composite)`, so a per-item
|
|
141
|
+
mask cannot express both. The reflection is folded into a signed weight matrix, which
|
|
142
|
+
also means every subscale at every level is computed by one matrix multiplication.
|
|
143
|
+
|
|
144
|
+
**Both hierarchy levels are declared flat.** The BFI-2's five domains and fifteen
|
|
145
|
+
facets are siblings, each listing its own item numbers, rather than domains being
|
|
146
|
+
composed from facets. The arithmetic is identical and the flat form scores both
|
|
147
|
+
levels in a single pass.
|
|
148
|
+
|
|
149
|
+
**Polarity is recorded as data.** Every subscale carries a `higher_is` string, so no
|
|
150
|
+
consumer has to infer direction from a name — the inference that produced the bug
|
|
151
|
+
below.
|
|
152
|
+
|
|
153
|
+
# Development
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
make dev # install everything
|
|
157
|
+
make fix # format and autofix
|
|
158
|
+
make check # lint, type-check, test, docs -- mirrors CI
|
|
159
|
+
make check-ci # the same, in a throwaway venv built like CI's
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Tests are `unittest` under `coverage`, mirroring the package layout in `tests/`.
|
|
163
|
+
|
|
164
|
+
# Related work
|
|
165
|
+
|
|
166
|
+
[PersonalityLinMulT](https://github.com/fodorad/PersonalityLinMulT) predicts perceived
|
|
167
|
+
Big Five traits from video. This package sits on the other side of that problem: it
|
|
168
|
+
collects *self-reported* ground truth, on the same `[0, 1]` scale and in the same
|
|
169
|
+
`openness, conscientiousness, extraversion, agreeableness, neuroticism` column order,
|
|
170
|
+
so an exported BFI-2 record drops into a self-report-versus-perception comparison.
|
|
171
|
+
The two are deliberately uncoupled in code — this package has no ML dependencies.
|
|
172
|
+
|
|
173
|
+
# Citation
|
|
174
|
+
|
|
175
|
+
```bibtex
|
|
176
|
+
@software{fodor_personality_questionnaire,
|
|
177
|
+
author = {Fodor, Ádám},
|
|
178
|
+
title = {personality_questionnaire: administering and scoring validated psychometric instruments},
|
|
179
|
+
url = {https://github.com/fodorad/personality_questionnaire},
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
# Contact
|
|
184
|
+
|
|
185
|
+
* Ádám Fodor (fodorad201@gmail.com) — [adamfodor.com](https://adamfodor.com)
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<!-- PNG, not the SVG: PyPI strips SVG from project descriptions, so an SVG
|
|
4
|
+
logo silently vanishes there while rendering fine on GitHub. The SVG is
|
|
5
|
+
the source of truth and is used by the docs site and the application. -->
|
|
6
|
+
<img src="https://raw.githubusercontent.com/fodorad/personality_questionnaire/main/docs/assets/logo.png" alt="personality_questionnaire" width="112"/>
|
|
7
|
+
|
|
8
|
+
**Administer, score and record validated personality and affect questionnaires.**
|
|
9
|
+
|
|
10
|
+
[](https://github.com/fodorad/personality_questionnaire/releases)
|
|
11
|
+
[](https://pypi.org/project/personality_questionnaire/)
|
|
12
|
+
[](https://github.com/fodorad/personality_questionnaire/actions)
|
|
13
|
+
[](https://codecov.io/gh/fodorad/personality_questionnaire)
|
|
14
|
+
[](https://fodorad.github.io/personality_questionnaire/)
|
|
15
|
+
<br/>
|
|
16
|
+
[](https://www.python.org)
|
|
17
|
+
[](https://github.com/astral-sh/ruff)
|
|
18
|
+
[](LICENSE)
|
|
19
|
+
|
|
20
|
+
</div>
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# What this is
|
|
25
|
+
|
|
26
|
+
Collecting validated self-reports is the unglamorous half of an affective-computing
|
|
27
|
+
pipeline. This package administers published psychometric instruments, scores them
|
|
28
|
+
correctly, and records every response with the provenance needed to reproduce the
|
|
29
|
+
score months later.
|
|
30
|
+
|
|
31
|
+
It is built around one idea: **an instrument is data, not code.** Items, response
|
|
32
|
+
ranges, subscale membership and reverse keys are declared as values; a single
|
|
33
|
+
vectorised scorer turns responses into scores without knowing which questionnaire it
|
|
34
|
+
is holding. Adding an instrument adds no arithmetic.
|
|
35
|
+
|
|
36
|
+
# Instruments
|
|
37
|
+
|
|
38
|
+
| Key | Instrument | Items | Scale | Scores |
|
|
39
|
+
| --- | --- | --- | --- | --- |
|
|
40
|
+
| `bfi2` | Big Five Inventory-2 | 60 | 1–5 | 5 domains, 15 facets |
|
|
41
|
+
| `vasf` | Visual Analogue Scale to Evaluate Fatigue Severity | 18 | 0–10 | Fatigue, Energy, composite |
|
|
42
|
+
|
|
43
|
+
<sub>BFI-2: Soto & John (2017). VAS-F: Lee, Hicks & Nino-Murcia (1991). See
|
|
44
|
+
[docs/instruments.md](docs/instruments.md) for full citations and licence notes.</sub>
|
|
45
|
+
|
|
46
|
+
# Quickstart
|
|
47
|
+
|
|
48
|
+
Score responses you already have:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install personality_questionnaire
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
import personality_questionnaire as pq
|
|
56
|
+
|
|
57
|
+
result = pq.score(pq.get("bfi2"), answers) # answers: (n_participants, 60)
|
|
58
|
+
result.by_level("domain") # {"openness": array([...]), ...}
|
|
59
|
+
result.as_dict() # one participant, every subscale
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Administer one at the terminal:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pq list # what is available
|
|
66
|
+
pq info bfi2 # items, subscales, citation
|
|
67
|
+
pq run bfi2 --participant P01 # ask the questions, score the answers
|
|
68
|
+
pq score bfi2 --input answers.csv # score a file
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
# How it works
|
|
72
|
+
|
|
73
|
+
```mermaid
|
|
74
|
+
flowchart LR
|
|
75
|
+
I["instruments/<br/><i>pure data</i>"] --> R[registry]
|
|
76
|
+
R --> S["scoring<br/><i>one vectorised scorer</i>"]
|
|
77
|
+
S --> C[cli]
|
|
78
|
+
S --> D[db]
|
|
79
|
+
S --> U[ui]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
| Module | Responsibility |
|
|
83
|
+
| --- | --- |
|
|
84
|
+
| `registry.py` | `Item`, `Subscale`, `Questionnaire` — what an instrument *is*, plus validation |
|
|
85
|
+
| `instruments/` | One module per questionnaire. Data only, no arithmetic |
|
|
86
|
+
| `scoring.py` | The single scorer: reverse-keying, subscale means, normalisation, pre/post deltas |
|
|
87
|
+
| `io.py` | Reading and writing responses and scores |
|
|
88
|
+
| `provenance.py` | Package version, git SHA, instrument hash for each record |
|
|
89
|
+
| `cli/` | `pq list \| info \| run \| score` |
|
|
90
|
+
|
|
91
|
+
# Design decisions
|
|
92
|
+
|
|
93
|
+
**Instruments are Python literals, not data files.** A literal is checked by the type
|
|
94
|
+
checker, validated at import, and present in the wheel by construction. A shipped CSV
|
|
95
|
+
is checked by nothing until a participant has already answered every item — and the
|
|
96
|
+
two scale files this repo used to carry were never read by any code path *and*
|
|
97
|
+
misspelled `neuroticism`, which is exactly how unread data drifts.
|
|
98
|
+
|
|
99
|
+
**Reverse-keying belongs to the subscale, not the item.** The VAS-F scores its five
|
|
100
|
+
energy items forward in `Energy` and reversed in `Fatigue (composite)`, so a per-item
|
|
101
|
+
mask cannot express both. The reflection is folded into a signed weight matrix, which
|
|
102
|
+
also means every subscale at every level is computed by one matrix multiplication.
|
|
103
|
+
|
|
104
|
+
**Both hierarchy levels are declared flat.** The BFI-2's five domains and fifteen
|
|
105
|
+
facets are siblings, each listing its own item numbers, rather than domains being
|
|
106
|
+
composed from facets. The arithmetic is identical and the flat form scores both
|
|
107
|
+
levels in a single pass.
|
|
108
|
+
|
|
109
|
+
**Polarity is recorded as data.** Every subscale carries a `higher_is` string, so no
|
|
110
|
+
consumer has to infer direction from a name — the inference that produced the bug
|
|
111
|
+
below.
|
|
112
|
+
|
|
113
|
+
# Development
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
make dev # install everything
|
|
117
|
+
make fix # format and autofix
|
|
118
|
+
make check # lint, type-check, test, docs -- mirrors CI
|
|
119
|
+
make check-ci # the same, in a throwaway venv built like CI's
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Tests are `unittest` under `coverage`, mirroring the package layout in `tests/`.
|
|
123
|
+
|
|
124
|
+
# Related work
|
|
125
|
+
|
|
126
|
+
[PersonalityLinMulT](https://github.com/fodorad/PersonalityLinMulT) predicts perceived
|
|
127
|
+
Big Five traits from video. This package sits on the other side of that problem: it
|
|
128
|
+
collects *self-reported* ground truth, on the same `[0, 1]` scale and in the same
|
|
129
|
+
`openness, conscientiousness, extraversion, agreeableness, neuroticism` column order,
|
|
130
|
+
so an exported BFI-2 record drops into a self-report-versus-perception comparison.
|
|
131
|
+
The two are deliberately uncoupled in code — this package has no ML dependencies.
|
|
132
|
+
|
|
133
|
+
# Citation
|
|
134
|
+
|
|
135
|
+
```bibtex
|
|
136
|
+
@software{fodor_personality_questionnaire,
|
|
137
|
+
author = {Fodor, Ádám},
|
|
138
|
+
title = {personality_questionnaire: administering and scoring validated psychometric instruments},
|
|
139
|
+
url = {https://github.com/fodorad/personality_questionnaire},
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
# Contact
|
|
144
|
+
|
|
145
|
+
* Ádám Fodor (fodorad201@gmail.com) — [adamfodor.com](https://adamfodor.com)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Administer, score and record validated personality and affect questionnaires.
|
|
2
|
+
|
|
3
|
+
The package is organised around a registry of instruments. Each instrument is data
|
|
4
|
+
-- items, response range, subscale membership, reverse keys -- and a single
|
|
5
|
+
vectorised scorer turns responses into scores:
|
|
6
|
+
|
|
7
|
+
>>> import personality_questionnaire as pq
|
|
8
|
+
>>> bfi2 = pq.get("bfi2")
|
|
9
|
+
>>> result = pq.score(bfi2, [[3] * 60])
|
|
10
|
+
>>> round(result.as_dict()["extraversion"], 3)
|
|
11
|
+
0.5
|
|
12
|
+
|
|
13
|
+
The pre-2.0 functional API (:func:`personality_questionnaire.bfi2.bfi2` and
|
|
14
|
+
:func:`personality_questionnaire.vasf.vasf`) is still supported; see those modules.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
from importlib.resources import files
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import TYPE_CHECKING, Any
|
|
22
|
+
|
|
23
|
+
from personality_questionnaire import instruments as instruments
|
|
24
|
+
from personality_questionnaire.registry import (
|
|
25
|
+
REGISTRY,
|
|
26
|
+
Item,
|
|
27
|
+
Questionnaire,
|
|
28
|
+
ScaleType,
|
|
29
|
+
Subscale,
|
|
30
|
+
get,
|
|
31
|
+
keys,
|
|
32
|
+
register,
|
|
33
|
+
)
|
|
34
|
+
from personality_questionnaire.scoring import (
|
|
35
|
+
PairedScoreResult,
|
|
36
|
+
ScoreResult,
|
|
37
|
+
delta,
|
|
38
|
+
score,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
if TYPE_CHECKING:
|
|
42
|
+
from importlib.resources.abc import Traversable
|
|
43
|
+
|
|
44
|
+
__version__ = "2.0.0"
|
|
45
|
+
"""The installed package version.
|
|
46
|
+
|
|
47
|
+
Managed by release-please; do not edit by hand.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
__all__ = [
|
|
51
|
+
"REGISTRY",
|
|
52
|
+
"Item",
|
|
53
|
+
"PairedScoreResult",
|
|
54
|
+
"Questionnaire",
|
|
55
|
+
"ScaleType",
|
|
56
|
+
"ScoreResult",
|
|
57
|
+
"Subscale",
|
|
58
|
+
"__version__",
|
|
59
|
+
"asset",
|
|
60
|
+
"delta",
|
|
61
|
+
"get",
|
|
62
|
+
"keys",
|
|
63
|
+
"register",
|
|
64
|
+
"score",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
_DEPRECATED_PATHS = frozenset({"PROJECT_DIR", "DATA_DIR"})
|
|
68
|
+
"""Module attributes kept only for pre-2.0 compatibility."""
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def asset(name: str) -> Traversable:
|
|
72
|
+
"""Return a data file shipped inside the package.
|
|
73
|
+
|
|
74
|
+
Works from a wheel, an sdist and a source checkout alike, which the pre-2.0
|
|
75
|
+
``DATA_DIR`` did not: it resolved relative to the repository root, so an
|
|
76
|
+
installed wheel pointed at a ``data`` directory beside ``site-packages`` that
|
|
77
|
+
had never been shipped.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
name: File name relative to the package's ``assets`` directory.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
A traversable handle supporting ``.read_text()`` and ``.open()``.
|
|
84
|
+
"""
|
|
85
|
+
return files("personality_questionnaire") / "assets" / name
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def __getattr__(name: str) -> Any:
|
|
89
|
+
"""Serve the deprecated path constants with a warning.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
name: The attribute being looked up.
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
The requested path.
|
|
96
|
+
|
|
97
|
+
Raises:
|
|
98
|
+
AttributeError: If ``name`` is not a module attribute.
|
|
99
|
+
"""
|
|
100
|
+
if name in _DEPRECATED_PATHS:
|
|
101
|
+
import warnings
|
|
102
|
+
|
|
103
|
+
warnings.warn(
|
|
104
|
+
f"personality_questionnaire.{name} is deprecated and does not resolve "
|
|
105
|
+
"from an installed wheel; use personality_questionnaire.asset() to read "
|
|
106
|
+
"shipped data files.",
|
|
107
|
+
DeprecationWarning,
|
|
108
|
+
stacklevel=2,
|
|
109
|
+
)
|
|
110
|
+
project_dir = Path(__file__).resolve().parents[1]
|
|
111
|
+
return project_dir if name == "PROJECT_DIR" else project_dir / "data"
|
|
112
|
+
|
|
113
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""Backwards-compatible entry point for the pre-2.0 console script.
|
|
2
|
+
|
|
3
|
+
The ``personality-questionnaire`` script has pointed at :func:`main` since 1.1.0.
|
|
4
|
+
It now forwards to :mod:`personality_questionnaire.cli.main`, which accepts both the
|
|
5
|
+
subcommand form and the old flat flags.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from personality_questionnaire.cli.main import main, run
|
|
11
|
+
|
|
12
|
+
__all__ = ["main", "run"]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
if __name__ == "__main__":
|
|
16
|
+
run()
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
ID ITEM
|
|
2
|
+
1 Is outgoing, sociable.
|
|
3
|
+
2 Is compassionate, has a soft heart.
|
|
4
|
+
3 Tends to be disorganized.
|
|
5
|
+
4 Is relaxed, handles stress well.
|
|
6
|
+
5 Has few artistic interests.
|
|
7
|
+
6 Has an assertive personality.
|
|
8
|
+
7 Is respectful, treats others with respect.
|
|
9
|
+
8 Tends to be lazy.
|
|
10
|
+
9 Stays optimistic after experiencing a setback.
|
|
11
|
+
10 Is curious about many different things.
|
|
12
|
+
11 Rarely feels excited or eager.
|
|
13
|
+
12 Tends to find fault with others.
|
|
14
|
+
13 Is dependable, steady.
|
|
15
|
+
14 Is moody, has up and down mood swings.
|
|
16
|
+
15 Is inventive, finds clever ways to do things.
|
|
17
|
+
16 Tends to be quiet.
|
|
18
|
+
17 Feels little sympathy for others.
|
|
19
|
+
18 Is systematic, likes to keep things in order.
|
|
20
|
+
19 Can be tense.
|
|
21
|
+
20 Is fascinated by art, music, or literature.
|
|
22
|
+
21 Is dominant, acts as a leader.
|
|
23
|
+
22 Starts arguments with others.
|
|
24
|
+
23 Has difficulty getting started on tasks.
|
|
25
|
+
24 Feels secure, comfortable with self.
|
|
26
|
+
25 Avoids intellectual, philosophical discussions.
|
|
27
|
+
26 Is less active than other people.
|
|
28
|
+
27 Has a forgiving nature.
|
|
29
|
+
28 Can be somewhat careless.
|
|
30
|
+
29 Is emotionally stable, not easily upset.
|
|
31
|
+
30 Has little creativity.
|
|
32
|
+
31 Is sometimes shy, introverted.
|
|
33
|
+
32 Is helpful and unselfish with others.
|
|
34
|
+
33 Keeps things neat and tidy.
|
|
35
|
+
34 Worries a lot.
|
|
36
|
+
35 Values art and beauty.
|
|
37
|
+
36 Finds it hard to influence people.
|
|
38
|
+
37 Is sometimes rude to others.
|
|
39
|
+
38 Is efficient, gets things done.
|
|
40
|
+
39 Often feels sad.
|
|
41
|
+
40 Is complex, a deep thinker.
|
|
42
|
+
41 Is full of energy.
|
|
43
|
+
42 Is suspicious of others' intentions.
|
|
44
|
+
43 Is reliable, can always be counted on.
|
|
45
|
+
44 Keeps their emotions under control.
|
|
46
|
+
45 Has difficulty imagining things.
|
|
47
|
+
46 Is talkative.
|
|
48
|
+
47 Can be cold and uncaring.
|
|
49
|
+
48 Leaves a mess, doesn't clean up.
|
|
50
|
+
49 Rarely feels anxious or afraid.
|
|
51
|
+
50 Thinks poetry and plays are boring.
|
|
52
|
+
51 Prefers to have others take charge.
|
|
53
|
+
52 Is polite, courteous to others.
|
|
54
|
+
53 Is persistent, works until the task is finished.
|
|
55
|
+
54 Tends to feel depressed, blue.
|
|
56
|
+
55 Has little interest in abstract ideas.
|
|
57
|
+
56 Shows a lot of enthusiasm.
|
|
58
|
+
57 Assumes the best about people.
|
|
59
|
+
58 Sometimes behaves irresponsibly.
|
|
60
|
+
59 Is temperamental, gets emotional easily.
|
|
61
|
+
60 Is original, comes up with new ideas.
|