Skip to main content

Comprehensive Python package providing Stata-equivalent commands for pandas DataFrames

Project description

PyStataR

Python Version PyPI Version License Downloads

The Ultimate Python Toolkit for Academic Research - Bringing Stata & R's Power to Python ๐Ÿš€

๐Ÿšจ IMPORTANT: Version 0.1.0+ Import Changes

PyStataR v0.1.0+ introduces simplified import syntax for better usability:

# โœ… NEW (v0.1.0+) - Direct function imports
from pystatar import tabulate, reghdfe, winsor2
from pystatar import rank, rowmean  # Individual functions

# Use directly
result = tabulate(df['education'])
regression = reghdfe(data, 'y', ['x1', 'x2'])
# โŒ OLD (v0.0.x) - Module-style imports (deprecated)
from pystatar import tabulate
result = tabulate.tabulate(df, 'education')  # No longer works

Migration Guide: Update your import statements to use the new direct import syntax. All examples below use the v0.1.0+ syntax.

Project Vision & Goals

PyStataR aims to recreate and significantly enhance the top 20 most frequently used Stata commands in Python, transforming them into the most powerful and user-friendly statistical tools for academic research. Our goal is to not just replicate Stata's functionality, but to expand and improve upon it, leveraging Python's ecosystem to create superior research tools.

Why This Project Matters

  • Bridge the Gap: Seamless transition from Stata to Python for researchers
  • Enhanced Functionality: Each command will be significantly expanded beyond Stata's original capabilities
  • Modern Research Tools: Built for today's data science and research needs
  • Community-Driven: Open source development with academic researchers in mind

Target Commands (20 Most Used in Academic Research)

โœ… tabulate - Cross-tabulation and frequency analysis
โœ… egen - Extended data generation and manipulation
โœ… reghdfe - High-dimensional fixed effects regression
โœ… winsor2 - Data winsorizing and trimming
๐Ÿ”„ Coming Soon: summarize, describe, merge, reshape, collapse, keep/drop, generate, replace, sort, by, if/in, reg, logit, probit, ivregress, xtreg

Want to see a specific command implemented?

  • Create an issue to request a command
  • Contribute to help us complete this project faster
  • โญ Star this repo to show your support!

Core Modules Overview

tabulate - Advanced Cross-tabulation and Frequency Analysis

  • Beyond Stata: Enhanced statistical tests, multi-dimensional tables, and publication-ready output
  • Key Features: Chi-square tests, Fisher's exact test, Cramรฉr's V, Kendall's tau, gamma coefficients
  • Use Cases: Survey analysis, categorical data exploration, market research

egen - Extended Data Generation and Manipulation

  • Beyond Stata: Advanced ranking algorithms, robust statistical functions, and vectorized operations
  • Key Features: Group operations, ranking with tie-breaking, row statistics, percentile calculations
  • Use Cases: Data preprocessing, feature engineering, panel data construction

reghdfe - High-Dimensional Fixed Effects Regression

  • Beyond Stata: Memory-efficient algorithms, advanced clustering options, and diagnostic tools
  • Key Features: Multiple fixed effects, clustered standard errors, instrumental variables, robust diagnostics
  • Use Cases: Panel data analysis, causal inference, economic research

winsor2 - Advanced Outlier Detection and Treatment

  • Beyond Stata: Multiple detection methods, group-specific treatment, and comprehensive diagnostics
  • Key Features: IQR-based detection, percentile methods, group-wise operations, flexible trimming
  • Use Cases: Data cleaning, outlier analysis, robust statistical modeling

Advanced Features & Performance

Performance Optimizations

  • Vectorized Operations: All functions leverage NumPy and pandas for maximum speed
  • Memory Efficiency: Optimized for large datasets common in academic research
  • Parallel Processing: Multi-core support for computationally intensive operations
  • Lazy Evaluation: Smart caching and delayed computation when beneficial

Research-Grade Features

  • Publication Ready: LaTeX and HTML output for academic papers
  • Reproducible Research: Comprehensive logging and version tracking
  • Missing Data Handling: Multiple imputation and robust missing value treatment
  • Bootstrapping: Built-in bootstrap methods for confidence intervals
  • Cross-Validation: Integrated CV methods for model validation

Quick Installation

pip install pystatar

Comprehensive Usage Examples

tabulate - Advanced Cross-tabulation

The tabulate module provides comprehensive frequency analysis and cross-tabulation capabilities, extending far beyond Stata's original functionality.

Basic One-way Tabulation

import pandas as pd
import numpy as np
# v0.1.0+ Import Syntax - Direct function imports
from pystatar import tabulate

# Create sample dataset
df = pd.DataFrame({
    'gender': ['Male', 'Female', 'Male', 'Female', 'Male', 'Female'] * 100,
    'education': ['High School', 'College', 'Graduate', 'High School', 'College', 'Graduate'] * 100,
    'income': np.random.normal(50000, 15000, 600),
    'age': np.random.randint(22, 65, 600),
    'industry': np.random.choice(['Tech', 'Finance', 'Healthcare', 'Education'], 600)
})

# Simple frequency table - Direct function call (v0.1.0+)
result = tabulate(df['education'])
print(result)

Advanced Two-way Cross-tabulation with Statistics

# Two-way tabulation with comprehensive statistics (v0.1.0+)
result = tabulate(
    df['gender'], df['education'],
    chi2=True,           # Chi-square test
    exact=True,          # Fisher's exact test
    gamma=True,          # Gamma coefficient
    taub=True,           # Kendall's tau-b
    V=True,              # Cramรฉr's V
    missing=True,        # Include missing values
    row=True,            # Row percentages
    col=True,            # Column percentages
    cell=True            # Cell percentages
)

# Access different components
print("Frequency Table:")
print(result.table)
print(f"\nChi-square p-value: {result.chi2_pvalue:.4f}")
print(f"Cramรฉr's V: {result.cramers_v:.4f}")

Multi-way Tabulation

# Three-way tabulation with layering (v0.1.0+)
result = tabulate(
    df['gender'], df['education'],
    by=df['industry'],   # Layer by industry
    chi2=True
)

# Access results by layer
for industry, table_result in result.by_results.items():
    print(f"\n=== {industry} ===")
    print(table_result.table)

egen - Extended Data Generation

The egen module provides powerful data manipulation functions that extend Stata's egen capabilities.

Ranking and Percentile Functions

# v0.1.0+ Import Syntax - Direct function imports
from pystatar import egen, rank, xtile, pctile

# Advanced ranking with tie-breaking options
df['income_rank'] = rank(df['income'], method='average')  # Handle ties
df['income_pctile'] = xtile(df['income'], nquantiles=10)  # Deciles

# Group-specific rankings
df['rank_within_industry'] = rank(df['income'], by=df['industry'])

# Percentile calculations
df['income_90th'] = pctile(df['income'], 90)
df['income_iqr'] = pctile(df['income'], 75) - pctile(df['income'], 25)

Row Operations

# v0.1.0+ Import Syntax - Direct function imports
from pystatar import rowtotal, rowmean, rowmin, rowmax, rowsd, rownonmiss

# Create test scores dataset
scores_df = pd.DataFrame({
    'student': range(1, 101),
    'math': np.random.normal(75, 10, 100),
    'english': np.random.normal(80, 12, 100),
    'science': np.random.normal(78, 11, 100),
    'history': np.random.normal(82, 9, 100)
})

# Row statistics (v0.1.0+)
scores_df['total_score'] = rowtotal(scores_df, ['math', 'english', 'science', 'history'])
scores_df['avg_score'] = rowmean(scores_df, ['math', 'english', 'science', 'history'])
scores_df['min_score'] = rowmin(scores_df, ['math', 'english', 'science', 'history'])
scores_df['max_score'] = rowmax(scores_df, ['math', 'english', 'science', 'history'])
scores_df['score_sd'] = rowsd(scores_df, ['math', 'english', 'science', 'history'])

# Count non-missing values per row
scores_df['subjects_taken'] = rownonmiss(scores_df, ['math', 'english', 'science', 'history'])

Group Statistics and Operations

# v0.1.0+ Import Syntax - Group functions
from pystatar import mean, median, sd, count, tag, seq

# Group summary statistics
df['mean_income_by_education'] = mean(df['income'], by=df['education'])
df['median_income_by_industry'] = median(df['income'], by=df['industry'])
df['sd_income_by_gender'] = sd(df['income'], by=df['gender'])

# Group identification and counting
df['education_group_size'] = count(df, by=df['education'])
df['first_in_group'] = tag(df, [df['education'], df['gender']])  # First observation in group
df['group_sequence'] = seq(df, by=df['education'])              # Sequence within group

# Advanced group operations
df['income_rank_in_education'] = rank(df['income'], by=df['education'])
df['above_group_median'] = (df['income'] > median(df['income'], by=df['education'])).astype(int)

reghdfe - Advanced Fixed Effects Regression

The reghdfe module provides state-of-the-art estimation for linear models with high-dimensional fixed effects.

Basic Fixed Effects Regression

# v0.1.0+ Import Syntax
from pystatar import reghdfe

# Create panel dataset
np.random.seed(42)
n_firms, n_years = 100, 10
n_obs = n_firms * n_years

panel_df = pd.DataFrame({
    'firm_id': np.repeat(range(n_firms), n_years),
    'year': np.tile(range(2010, 2020), n_firms),
    'log_sales': np.random.normal(10, 1, n_obs),
    'log_employment': np.random.normal(4, 0.5, n_obs),
    'log_capital': np.random.normal(8, 0.8, n_obs),
    'industry': np.repeat(np.random.choice(['Tech', 'Manufacturing', 'Services'], n_firms), n_years)
})

# Basic regression with firm and year fixed effects (v0.1.0+)
result = reghdfe(
    data=panel_df,
    depvar='log_sales',
    regressors=['log_employment', 'log_capital'],
    absorb=['firm_id', 'year']
)

print(result.summary())
print(f"R-squared: {result.r2:.4f}")
print(f"Number of observations: {result.N}")

Advanced Regression with Clustering and Instruments

# Add instrumental variables
panel_df['instrument1'] = np.random.normal(0, 1, n_obs)
panel_df['instrument2'] = np.random.normal(0, 1, n_obs)

# Regression with clustering and multiple fixed effects (v0.1.0+)
result = reghdfe(
    data=panel_df,
    depvar='log_sales',
    regressors=['log_employment', 'log_capital'],
    absorb=['firm_id', 'year', 'industry'],  # Multiple fixed effects
    cluster='firm_id',                        # Clustered standard errors
    weights='employment',                     # Weighted regression
    subset=(panel_df['year'] >= 2012)        # Conditional estimation
)

# Access detailed results
print("Coefficient Table:")
print(result.coef_table)
print(f"\nFixed Effects absorbed: {result.absorbed_fe}")
print(f"Clusters: {result.n_clusters}")

Instrumental Variables with High-Dimensional FE

# IV regression with fixed effects (v0.1.0+)
iv_result = reghdfe(
    data=panel_df,
    depvar='log_sales',
    endogenous=['log_employment'],           # Endogenous variable
    instruments=['instrument1', 'instrument2'],  # Instruments
    exogenous=['log_capital'],               # Exogenous controls
    absorb=['firm_id', 'year'],
    cluster='firm_id',
    iv=True                                  # Enable IV estimation
)

print("First Stage Results:")
print(iv_result.first_stage)
print(f"\nWeak instruments test (F-stat): {iv_result.first_stage_fstat:.2f}")
print(f"Overidentification test (Hansen J): {iv_result.hansen_j:.4f}")

winsor2 - Advanced Outlier Treatment

The winsor2 module provides comprehensive outlier detection and treatment methods.

Basic Winsorizing

# v0.1.0+ Import Syntax
from pystatar import winsor2

# Create dataset with outliers
outlier_df = pd.DataFrame({
    'income': np.concatenate([
        np.random.normal(50000, 10000, 950),  # Normal observations
        np.random.uniform(200000, 500000, 50)  # Outliers
    ]),
    'age': np.random.randint(18, 70, 1000),
    'industry': np.random.choice(['Tech', 'Finance', 'Retail', 'Healthcare'], 1000)
})

# Basic winsorizing at 1st and 99th percentiles (v0.1.0+)
result = winsor2(outlier_df, ['income'])
print("Original vs Winsorized:")
print(f"Original: min={outlier_df['income'].min():.0f}, max={outlier_df['income'].max():.0f}")
print(f"Winsorized: min={result['income_w'].min():.0f}, max={result['income_w'].max():.0f}")

Group-wise Winsorizing

# Winsorize within groups (v0.1.0+)
result = winsor2(
    outlier_df, 
    ['income'],
    by=outlier_df['industry'], # Winsorize within each industry
    cuts=(5, 95),              # Use 5th and 95th percentiles
    suffix='_clean'            # Custom suffix
)

# Compare distributions by group
for industry in outlier_df['industry'].unique():
    mask = outlier_df['industry'] == industry
    original = outlier_df.loc[mask, 'income']
    winsorized = result.loc[mask, 'income_clean']
    print(f"\n{industry}:")
    print(f"  Original: {original.describe()}")
    print(f"  Winsorized: {winsorized.describe()}")

Trimming vs Winsorizing Comparison

# Compare different outlier treatment methods (v0.1.0+)
trim_result = winsor2(
    outlier_df, 
    ['income'],
    trim=True,              # Trim (remove) instead of winsorize
    cuts=(2.5, 97.5)       # Trim 2.5% from each tail
)

winsor_result = winsor2(
    outlier_df, 
    ['income'],
    trim=False,             # Winsorize (cap) outliers
    cuts=(2.5, 97.5)
)

print("Treatment Comparison:")
print(f"Original N: {len(outlier_df)}")
print(f"After trimming N: {trim_result['income_tr'].notna().sum()}")
print(f"After winsorizing N: {len(winsor_result)}")
print(f"Trimmed mean: {trim_result['income_tr'].mean():.0f}")
print(f"Winsorized mean: {winsor_result['income_w'].mean():.0f}")

Advanced Outlier Detection

# Multiple variable winsorizing with custom thresholds (v0.1.0+)
multi_result = winsor2(
    outlier_df,
    ['income', 'age'],
    cuts=(1, 99),           # Different cuts for different variables
    by=outlier_df['industry'], # Group-specific treatment
    replace=True,           # Replace original variables
    label=True              # Add descriptive labels
)

# Generate outlier indicators (v0.1.0+)
from pystatar import outlier_indicator

outlier_df['income_outlier'] = outlier_indicator(
    outlier_df['income'], 
    method='iqr',           # Use IQR method
    factor=1.5              # 1.5 * IQR threshold
)

outlier_df['extreme_outlier'] = outlier_indicator(
    outlier_df['income'],
    method='percentile',    # Use percentile method
    cuts=(1, 99)
)

print("Outlier Detection Results:")
print(f"IQR method detected {outlier_df['income_outlier'].sum()} outliers")
print(f"Percentile method detected {outlier_df['extreme_outlier'].sum()} outliers")

Project Structure

pystatar/
โ”œโ”€โ”€ __init__.py              # Main package initialization
โ”œโ”€โ”€ tabulate/               # Cross-tabulation module
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ core.py
โ”‚   โ”œโ”€โ”€ results.py
โ”‚   โ””โ”€โ”€ stats.py
โ”œโ”€โ”€ egen/                   # Extended generation module
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ core.py
โ”œโ”€โ”€ reghdfe/               # High-dimensional FE regression
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ core.py
โ”‚   โ”œโ”€โ”€ estimation.py
โ”‚   โ””โ”€โ”€ utils.py
โ”œโ”€โ”€ winsor2/               # Winsorizing module
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ core.py
โ”‚   โ””โ”€โ”€ utils.py
โ”œโ”€โ”€ utils/                 # Shared utilities
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ common.py
โ””โ”€โ”€ tests/                 # Test suite
    โ”œโ”€โ”€ test_tabulate.py
    โ”œโ”€โ”€ test_egen.py
    โ”œโ”€โ”€ test_reghdfe.py
    โ””โ”€โ”€ test_winsor2.py

Key Features

  • Familiar Syntax: Stata-like command structure and parameters
  • Pandas Integration: Seamless integration with pandas DataFrames
  • High Performance: Optimized implementations using pandas and NumPy
  • Comprehensive Coverage: Most commonly used Stata commands
  • Statistical Rigor: Proper statistical tests and robust standard errors
  • Flexible Output: Multiple output formats and customization options
  • Missing Value Handling: Configurable treatment of missing data

Documentation

Each module comes with comprehensive documentation and examples:

Contributing to the Project

We're building the future of academic research tools in Python! Here's how you can help:

Priority Commands Needed

Help us implement the remaining 16 high-priority commands:

Data Management: summarize, describe, merge, reshape, collapse, keep, drop, generate, replace, sort

Statistical Analysis: reg, logit, probit, ivregress, xtreg, anova

How to Contribute

  1. Request a Command: Open an issue with the command you need
  2. ** Implement a Command**: Check our contribution guidelines and submit a PR
  3. ** Report Bugs**: Help us improve existing functionality
  4. ** Improve Documentation**: Add examples, tutorials, or clarifications
  5. ** Spread the Word**: Star the repo and share with fellow researchers

Recognition

All contributors will be recognized in our documentation and release notes. Major contributors will be listed as co-authors on any academic publications about this project.

Academic Collaboration

We welcome partnerships with universities and research institutions. If you're interested in using this project in your coursework or research, please reach out!

Community & Support

Comparison with Stata

Feature Stata PyStataR Advantage
Speed Base performance 2-10x faster* Vectorized operations
Memory Limited by system Efficient pandas backend Better large dataset handling
Extensibility Ado files Python ecosystem Unlimited customization
Cost $$$$ Free & Open Source Accessible to all researchers
Integration Standalone Python data science stack Seamless workflow
Output Limited formats Multiple (LaTeX, HTML, etc.) Publication ready

*Performance comparison based on typical academic datasets (1M+ observations)

๐Ÿ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

๐Ÿ™ Acknowledgments

This package builds upon the excellent work of:

  • pandas - The backbone of our data manipulation
  • numpy - Powering our numerical computations
  • scipy - Statistical functions and algorithms
  • statsmodels - Statistical modeling foundations
  • pyhdfe - High-dimensional fixed effects algorithms
  • The entire Stata community - For decades of statistical innovation that inspired this project

Future Roadmap

Version 1.0 Goals (Target: End of 2025)

  • Core 4 commands implemented
  • Additional 16 high-priority commands
  • Comprehensive test suite (>95% coverage)
  • Complete documentation with tutorials
  • Performance benchmarks vs Stata

Version 2.0 Vision (2026)

  • Machine learning integration
  • R integration for cross-platform compatibility
  • Web interface for non-programmers
  • Jupyter notebook extensions

๐Ÿ“ˆ Project Statistics

GitHub stars GitHub forks GitHub issues GitHub pull requests

Contact & Collaboration

Created by Bryce Wang - Stanford University

Academic Partnerships Welcome!

  • Course integration and teaching materials
  • Research collaborations and citations
  • Institutional licensing and support
  • Student contributor programs

โญ Love this project? Give it a star and help us reach more researchers! โญ

Together, we're building the future of academic research in Python

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pystatar-0.1.1.tar.gz (51.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pystatar-0.1.1-py3-none-any.whl (43.4 kB view details)

Uploaded Python 3

File details

Details for the file pystatar-0.1.1.tar.gz.

File metadata

  • Download URL: pystatar-0.1.1.tar.gz
  • Upload date:
  • Size: 51.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for pystatar-0.1.1.tar.gz
Algorithm Hash digest
SHA256 048d92d882c88db75c567a0401ccd541eb9458fbc0cdb38a344f391e7f0ddb64
MD5 29b8d40124e6900402dede84939cfc03
BLAKE2b-256 de907e5644f31a21cdef76bf4f85733fc9bc4ba78dc5fb65d2c1450621cc4e08

See more details on using hashes here.

File details

Details for the file pystatar-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: pystatar-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 43.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.5

File hashes

Hashes for pystatar-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 eba2f84a31d60ac9793854308e0a9c5bb1ef98e6ec0398864fb036700b5395e7
MD5 1a496a06c7e0f10e30e12b5134c8bb64
BLAKE2b-256 c0e7c718850db16e7f9c9aad35afad574c44d1b4ed619353f856ea31bd13cf0e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page