Careless
A Python package for detecting careless responding in survey data using various statistical indices and methods.
Overview
When taking online surveys, participants sometimes respond to items without regard to their content. These types of responses, referred to as careless or insufficient effort responding, constitute significant problems for data quality, leading to distortions in data analysis and hypothesis testing, such as spurious correlations.
The careless package provides solutions designed to detect such careless/insufficient effort responses by allowing easy calculation of indices proposed in the literature. For a comprehensive review of these methods, see Curran (2016).
Features
- Multiple Detection Methods: Supports various indices for detecting careless responding
- Flexible Input: Works with lists, numpy arrays, and pandas DataFrames
- Robust Implementation: Handles missing data, edge cases, and provides comprehensive error handling
- Performance Optimized: Efficient algorithms for large datasets
- Comprehensive Documentation: Detailed docstrings with examples for all functions
Installation
From PyPI (when available)
pip install careless-py
From Source
git clone https://github.com/Cameron-Lyons/careless-py.git
cd careless-py
pip install -e .
Optional Dependencies
For enhanced functionality (e.g., advanced Mahalanobis distance methods), install with full dependencies:
pip install careless-py[full]
Using uv (Recommended for Development)
This project uses uv for fast, reproducible dependency management. Install uv first:
curl -LsSf https://astral.sh/uv/install.sh | sh
Then clone and install:
git clone https://github.com/Cameron-Lyons/careless-py.git
cd careless-py
uv sync --extra full # Install with all optional dependencies
For development with all dev tools:
uv sync --extra dev
Run commands in the virtual environment:
uv run pytest # Run tests
uv run ruff check . # Run linter
uv run mypy src/ # Run type checker
Quick Start
import numpy as np
from careless import evenodd, irv, longstring, mahad, psychsyn
# Sample survey data (rows = participants, columns = items)
data = np.array([
[1, 2, 3, 4, 5, 6, 7, 8], # Participant 1
[2, 2, 2, 2, 5, 5, 5, 5], # Participant 2 (suspicious pattern)
[3, 4, 3, 4, 6, 7, 6, 7], # Participant 3
])
# Check even-odd consistency
factors = [4, 4] # Two factors with 4 items each
consistency_scores = evenodd(data, factors)
print("Even-odd consistency scores:", consistency_scores)
# Check intra-individual response variability
irv_scores = irv(data)
print("IRV scores:", irv_scores)
# Check for long strings of identical responses
longest_strings = longstring(data)
print("Longest strings:", longest_strings)
Available Functions
Consistency Indices
evenodd(x, factors, diag=False)
Computes the Even-Odd Consistency Index by dividing unidimensional scales using an even-odd split.
Parameters:
x: Input data (2D array/list) where rows are individuals and columns are responsesfactors: List of integers specifying the length of each factordiag: Boolean to return diagnostic values (number of valid correlations per individual)
Returns:
- Array of even-odd consistency scores (average correlations per individual)
- If
diag=True: Tuple of (scores, diagnostic_values)
Example:
data = [[1, 2, 3, 4, 5, 6], [2, 3, 4, 5, 6, 7]]
factors = [4, 2] # First factor has 4 items, second has 2
scores = evenodd(data, factors)
psychsyn(x, pairs, method='synonyms', seed=None)
Computes the Psychometric Synonyms/Antonyms Index based on correlated item pairs.
Parameters:
x: Input data (2D array/list)pairs: List of item pairs [(item1, item2), ...]method: 'synonyms' or 'antonyms'seed: Random seed for reproducibility
Returns:
- Array of psychometric synonym/antonym scores
Example:
data = [[1, 2, 3, 4], [2, 3, 4, 5]]
pairs = [(0, 1), (2, 3)] # Item pairs to correlate
scores = psychsyn(data, pairs, method='synonyms')
psychant(x, pairs, seed=None)
Convenience wrapper for psychsyn that computes psychological antonyms.
Response Pattern Functions
longstring(x, avg=False)
Computes the longest (and optionally, average) length of consecutive identical responses.
Parameters:
x: Input data (2D array/list)avg: Boolean to also return average string length
Returns:
- Array of longest string lengths per individual
- If
avg=True: Tuple of (longest_strings, average_strings)
Example:
data = [[1, 1, 1, 2, 3], [1, 2, 3, 4, 5]]
longest, avg = longstring(data, avg=True)
irv(x, consecutive=None)
Computes the Intra-individual Response Variability (IRV), the standard deviation of responses across consecutive items.
Parameters:
x: Input data (2D array/list)consecutive: Number of consecutive items to analyze (default: all items)
Returns:
- Array of IRV scores per individual
Example:
data = [[1, 2, 3, 4, 5], [1, 1, 1, 1, 1]]
irv_scores = irv(data)
Statistical Outlier Functions
mahad(x, method='classic', threshold=None, **kwargs)
Computes Mahalanobis Distance to identify multivariate outliers.
Parameters:
x: Input data (2D array/list)method: Detection method ('classic', 'robust', 'mcd', 'mve')threshold: Custom threshold for outlier detection**kwargs: Additional method-specific parameters
Returns:
- Array of Mahalanobis distances per individual
- If
thresholdprovided: Tuple of (distances, outlier_flags)
Example:
data = [[1, 2, 3], [4, 5, 6], [1, 1, 1]]
distances, outliers = mahad(data, method='robust', threshold=0.95)
Advanced Usage
Working with Different Data Types
The package supports various input formats:
import numpy as np
import pandas as pd
# Numpy arrays
data_np = np.array([[1, 2, 3], [4, 5, 6]])
# Lists
data_list = [[1, 2, 3], [4, 5, 6]]
# Pandas DataFrames
df = pd.DataFrame([[1, 2, 3], [4, 5, 6]])
data_df = df.values
# All work the same way
scores = evenodd(data_np, [3])
Handling Missing Data
The functions handle missing data (NaN values) appropriately:
import numpy as np
data_with_nans = np.array([
[1, 2, np.nan, 4],
[np.nan, 2, 3, 4],
[1, 2, 3, 4]
])
# Functions will handle NaN values appropriately
scores = evenodd(data_with_nans, [4])
Custom Thresholds and Parameters
# Custom Mahalanobis distance threshold
distances, outliers = mahad(data, threshold=0.99)
# Custom IRV analysis on consecutive items
irv_scores = irv(data, consecutive=5)
# Psychometric synonyms with custom pairs
pairs = [(0, 1), (2, 3), (4, 5)]
syn_scores = psychsyn(data, pairs, method='synonyms')
Performance Considerations
- Large Datasets: For datasets with >10,000 participants, consider processing in chunks
- Memory Usage: Functions create copies of input data for processing
- Parallel Processing: Consider using multiprocessing for very large datasets
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Citation
If you use this package in your research, please cite:
@software{careless2024,
title={Careless: Python package for detecting careless responding},
author={Lyons, Cameron},
year={2024},
url={https://github.com/Cameron-Lyons/careless}
}
References
- Curran, P. G. (2016). Methods for the detection of carelessly invalid responses in survey data. Journal of Experimental Social Psychology, 66, 4-19.
- Dunn, A. M., Heggestad, E. D., Shanock, L. R., & Theilgard, N. (2018). Intra-individual response variability as an indicator of insufficient effort responding: Comparison to other indicators and relationships with individual differences. Journal of Business and Psychology, 33(1), 105-121.
Metadata
Release files for careless-py 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| careless_py-1.1.0.tar.gz | 28.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| careless_py-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 55.1 kB
Release files / careless_py-1.1.0.tar.gz
| Download URL | careless_py-1.1.0.tar.gz |
|---|---|
| Size | 28.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7c5456026b71cfdcf9ca530b6d99732be523b9b4e6bc887ff90afb35c2d146de
|
|
BLAKE2b-256 checksum How to use checksums |
27093f5cd50b98e0e7e91cce6aec8d7de9a13b01d4019415ff4809a54f279db2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 2, 2026.
Transparency logRelease files / careless_py-1.1.0-py3-none-any.whl
| Download URL | careless_py-1.1.0-py3-none-any.whl |
|---|---|
| Size | 27.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e4d570d1bfac3e826324c5c5d40b269555b2a712617afe1ffa4493c0b4c89fc2
|
|
BLAKE2b-256 checksum How to use checksums |
e3ea94fee7a8427bea12bd7b10e3ed14d9c25ef4645824264885d25ca492e8d5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jan 2, 2026.
Transparency log