PyProcessMacro 1.0.14__tar.gz → 2.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 (23) hide show
  1. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/PKG-INFO +134 -6
  2. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/PyProcessMacro.egg-info/PKG-INFO +134 -6
  3. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/PyProcessMacro.egg-info/SOURCES.txt +5 -4
  4. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/PyProcessMacro.egg-info/requires.txt +4 -0
  5. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/README.md +130 -5
  6. pyprocessmacro-2.1.0/pyprocessmacro/__init__.py +10 -0
  7. pyprocessmacro-2.1.0/pyprocessmacro/bootstrap.py +242 -0
  8. pyprocessmacro-2.1.0/pyprocessmacro/effsize.py +77 -0
  9. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/pyprocessmacro/models.py +165 -118
  10. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/pyprocessmacro/process.py +202 -83
  11. pyprocessmacro-2.1.0/pyprocessmacro/serial.py +218 -0
  12. pyprocessmacro-2.1.0/pyprocessmacro/tidy.py +219 -0
  13. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/pyprocessmacro/utils.py +32 -13
  14. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/pyproject.toml +2 -1
  15. pyprocessmacro-1.0.14/pyprocessmacro/__init__.py +0 -9
  16. pyprocessmacro-1.0.14/pyprocessmacro/models.pyi +0 -228
  17. pyprocessmacro-1.0.14/pyprocessmacro/process.pyi +0 -163
  18. pyprocessmacro-1.0.14/pyprocessmacro/utils.pyi +0 -92
  19. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/LICENSE.txt +0 -0
  20. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/MANIFEST.in +0 -0
  21. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/PyProcessMacro.egg-info/dependency_links.txt +0 -0
  22. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/PyProcessMacro.egg-info/top_level.txt +0 -0
  23. {pyprocessmacro-1.0.14 → pyprocessmacro-2.1.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyProcessMacro
3
- Version: 1.0.14
3
+ Version: 2.1.0
4
4
  Summary: A Python library for moderation, mediation and conditional process analysis. Based on Andrew F. Hayes' Process Macro.
5
5
  Author-email: Quentin André <quentin.andre@insead.edu>
6
6
  License-Expression: MIT
@@ -27,8 +27,11 @@ Requires-Dist: pandas>=2.0
27
27
  Requires-Dist: scipy>=1.10
28
28
  Requires-Dist: matplotlib>=3.7
29
29
  Requires-Dist: seaborn>=0.13
30
+ Provides-Extra: statsmodels
31
+ Requires-Dist: statsmodels>=0.14; extra == "statsmodels"
30
32
  Provides-Extra: test
31
33
  Requires-Dist: pytest>=8; extra == "test"
34
+ Requires-Dist: statsmodels>=0.14; extra == "test"
32
35
  Dynamic: license-file
33
36
 
34
37
  PyProcessMacro: A Python Implementation of Andrew F. Hayes' 'Process' Macro
@@ -61,14 +64,16 @@ softwaress. PyProcessMacro is released under a MIT license.
61
64
  # Features
62
65
 
63
66
  In the current version, PyProcessMacro replicates the following features from the original Process Macro v2.16:
64
- * All models (1 to 76), with the exception of Model 6 (serial mediation) are supported, and have been numerically
65
- tested for accuracy against the output of the original Process macro (see the `test_models_accuracy.py`)
67
+ * All models (1 to 76) are supported. Models 1 to 5 and 7 to 76 are tested for accuracy against the output of the
68
+ original Process macro (see `tests/test_models_accuracy.py`); Model 6 (serial mediation, added in 2.1) is tested
69
+ against statsmodels-based reference computations.
66
70
  * Estimation of binary/continuous outcome variables. The binary outcomes are estimated in Logit using the
67
71
  Newton-Raphson convergence algorithm, the continuous variables are estimated using OLS.
68
72
  * All statistics reported by Process:
69
73
  * Variable parameters for outcome models
70
74
  * (Conditional) direct and indirect effects
71
- * Indices for Partial/Conditional/Moderated Moderated Mediation are always reported if the model supports them.
75
+ * The index of moderated mediation and, following PROCESS 3, the indices of partial, conditional and
76
+ moderated moderated mediation, whenever the indirect effect is linear in the moderator(s).
72
77
  * Automatic generation of spotlight values for continuous/discrete moderators.
73
78
  * Rich set of options to tweak the estimation and display of the different models: (almost) all the options from
74
79
  Process exist in PyProcessMacro. Check the doc for more details.
@@ -90,10 +95,41 @@ In the current version, the following features have not yet been ported to PyPro
90
95
  * Support for categorical independent variables.
91
96
  * Generation of individual fixed effects for repeated measures.
92
97
  * R² improvement from moderators in moderation models (1, 2, 3).
93
- * Estimation of serial mediation (Model 6)
94
98
  * Some options (`normal`, `varorder`, ...). PyProcessMacro will issue a warning to tell you if an option you are
95
99
  trying to use is not implemented.
96
100
 
101
+ # Upgrading to 2.0
102
+
103
+ Version 2.0 corrects several statistics and tightens input handling. Reported numbers change in these ways:
104
+
105
+ * Confidence intervals of OLS coefficients and of (conditional) direct effects use t critical values with the
106
+ residual degrees of freedom, as PROCESS does. They were based on z, so they widen slightly; the difference is
107
+ visible in small samples.
108
+ * Adjusted R² of OLS outcome models is slightly higher: the previous value used one degree of freedom too many.
109
+ * Cox-Snell and Nagelkerke pseudo R² of logistic outcome models are finite for large samples instead of NaN.
110
+ * No index of moderated mediation is reported when a moderator sits on both the X-to-M and the M-to-Y paths
111
+ (models 58 to 73, 75 and 76), matching PROCESS: the indirect effect is not linear in such a moderator. The
112
+ `*_index_summary()` methods raise `NotImplementedError` for those models.
113
+ * The sample size reported after listwise deletion is the number of rows kept.
114
+
115
+ Behaviour that used to be silent now speaks up:
116
+
117
+ * A misspelled key in `modval`, or a keyword argument that is neither a variable nor an option, raises an error
118
+ instead of being ignored.
119
+ * Unsupported PROCESS options (`jn`, `effsize`, `mc`, `normal`, ...) raise a visible `UserWarning`.
120
+ * A logistic regression that does not converge raises `pyprocessmacro.ConvergenceError`. Bootstrap resamples
121
+ that fail are counted, and the bootstrap stops with an error if more resamples fail than were requested.
122
+
123
+ Removed and added:
124
+
125
+ * `plot_direct_effects()` and `plot_indirect_effects()` are removed; use `plot_conditional_direct_effects()`
126
+ and `plot_conditional_indirect_effects()`.
127
+ * `cov_type` selects the OLS covariance estimator (`"standard"`, `"HC0"`, `"HC1"`, `"HC2"` or `"HC3"`);
128
+ `hc3=True` remains as shorthand for `"HC3"`.
129
+ * `seed=None` draws a different bootstrap sample on every run, and `seed=0` is accepted.
130
+ * `Process.dv` names the outcome variable (`iv` is kept for compatibility).
131
+ * Python 3.11 or newer is required (since 1.0.14).
132
+
97
133
  # Version History
98
134
 
99
135
  ## Master Versions
@@ -117,7 +153,7 @@ report and for the fix.
117
153
 
118
154
  ### 1.0.4
119
155
  **Bug fix for standard error estimate in all models**
120
- PyProcessMacro was, by default, using the HC3 estimator for the variance-covariance matrix instead of the HC0 estimator.
156
+ PyProcessMacro was, by default, using the HC3 estimator for the variance-covariance matrix instead of the standard (non-robust) estimator.
121
157
  This has now been changed. To continue using the HC3 estimator, specify `hc3=True` when initializing the Process instance.
122
158
  Thanks to Zoé Ziani for the bug report.
123
159
 
@@ -199,6 +235,8 @@ As you can see, the syntax for PyProcessMacro is (almost) identical to that of P
199
235
 
200
236
  Once the object is initialized, you can call its `summary()` method to display the estimation results
201
237
 
238
+ The standardized result tables (`tidy()`, `glance()`, `augment()`) are described in section 6.
239
+
202
240
  You might have noticed that there is no argument `varlist` in PyProcessMacro. This is because the list of variables
203
241
  is automatically inferred from the variable names given to x, y, m.
204
242
 
@@ -274,6 +312,48 @@ p = Process(data=df, model=13, x="Effort", y="Success", w="Motivation", z="Skill
274
312
  p.summary()
275
313
  ````
276
314
 
315
+ ### F. Choosing the covariance estimator
316
+
317
+ By default, the standard errors of the OLS outcome models use the standard (homoskedastic) estimator. The
318
+ `cov_type` argument selects a heteroskedasticity-consistent estimator instead: `"HC0"`, `"HC1"`, `"HC2"` or
319
+ `"HC3"`. `hc3=True` is shorthand for `cov_type="HC3"`, which is what the original Process macro uses when
320
+ `hc3=1` is specified. Logistic outcome models always use the inverse of the Hessian.
321
+
322
+ ````python
323
+ p = Process(data=df, model=4, x="Effort", y="Success", m=["MediationSkills"], cov_type="HC3")
324
+ ````
325
+
326
+ ### G. Serial mediation (Model 6)
327
+
328
+ In Model 6 the mediators form a chain: each mediator depends on X and on the mediators before it, and Y depends
329
+ on X and on every mediator. Pass two to four mediators in causal order. PyProcessMacro reports the specific
330
+ indirect effect through every ordered subset of mediators (three paths for two mediators, seven for three,
331
+ fifteen for four), labelled by the path, plus the total and the pairwise contrasts when `total=True` and
332
+ `contrast=True`.
333
+
334
+ ````python
335
+ p = Process(data=df, model=6, x="Effort", y="Success", m=["Attention", "MediationSkills"], total=True)
336
+ p.summary()
337
+ ````
338
+
339
+ Model 6 has no moderators, so the spotlight, floodlight and plotting methods do not apply to it. Its estimates are
340
+ checked against products of statsmodels coefficients and against an independent resampler; no PROCESS output for
341
+ Model 6 is part of the test fixtures yet, so a comparison file generated with PROCESS 2.16 would be a welcome
342
+ contribution.
343
+
344
+ ### H. Effect sizes for the indirect effect
345
+
346
+ With `effsize=True`, PyProcessMacro also reports the partially standardized indirect effect (the indirect effect
347
+ divided by the standard deviation of Y) and the completely standardized indirect effect (further multiplied by the
348
+ standard deviation of X), each with a bootstrap confidence interval computed by standardizing within every resample,
349
+ as PROCESS does. The option applies to unmoderated indirect paths with a continuous outcome, that is Models 4 and 6
350
+ with `logit=False`.
351
+
352
+ ````python
353
+ p = Process(data=df, model=4, x="Effort", y="Success", m=["MediationSkills"], effsize=True)
354
+ p.indirect_model.effect_size_summary()
355
+ ````
356
+
277
357
  ## 2. Accessing the estimation results
278
358
 
279
359
  After the `Process` object is initialized, you are not limited to printing the summary. PyProcessMacro implements the
@@ -371,6 +451,28 @@ Note that the methods are called from the `indirect_model` object! If you call `
371
451
  error.
372
452
 
373
453
 
454
+ ### E. Diagnostics and custom tests with statsmodels
455
+
456
+ Each outcome model can be handed to [statsmodels](https://www.statsmodels.org), which refits the same design
457
+ matrix with the same covariance estimator and returns the statsmodels results object. From there you get
458
+ `summary()`, custom contrasts with `t_test()` and `wald_test()`, heteroskedasticity and influence diagnostics,
459
+ variance inflation factors, prediction intervals, and the table formatters that accept statsmodels results.
460
+ statsmodels is optional: install it with `pip install pyprocessmacro[statsmodels]`.
461
+
462
+ ````python
463
+ p = Process(data=df, model=7, x="Effort", y="Success", w="Motivation", m=["MediationSkills"], suppr_init=True)
464
+
465
+ fit = p.outcome_models["Success"].to_statsmodels() # a statsmodels RegressionResults
466
+ print(fit.summary())
467
+ fit.t_test("Effort + MediationSkills = 0")
468
+
469
+ fits = p.to_statsmodels() # every outcome model, keyed by outcome name
470
+ ````
471
+
472
+ For a different question, statsmodels also ships `statsmodels.stats.mediation.Mediation`, Imai-style causal
473
+ mediation with a sensitivity analysis; it estimates a different quantity and is a useful cross-check rather than
474
+ a replacement for the PROCESS approach.
475
+
374
476
  ## 3. Spotlight and Floodlight Analysis
375
477
 
376
478
  ### A. Compute direct/indirect effects for specific values (spotlight analysis)
@@ -601,6 +703,32 @@ g = p.plot_conditional_indirect_effects(med_name="MediationSkills", x="Motivatio
601
703
  ````
602
704
  ![PlotCustomKws](images/Ex12.png)
603
705
 
706
+ ## 6. Standardized results: tidy(), glance() and augment()
707
+
708
+ Every table PyProcessMacro prints is also available in a standardized form, modelled on R's broom package:
709
+
710
+ * `tidy()` returns one long DataFrame with one row per estimate and fixed column names: `component`
711
+ (`outcome`, `direct`, `indirect`, `total`, `contrast`, or `index_mm`, `index_pmm`, `index_mmm`, `index_cmm`),
712
+ `outcome`, `term`, `moderator`, one column per moderator of the model holding the spotlight value the row is
713
+ evaluated at, then `estimate`, `std_error`, `statistic`, `p_value`, `conf_low`, `conf_high`, `method`,
714
+ `conf_level` and `n_boot`. Pass `component=` to keep one kind of row.
715
+ * `glance()` returns one row of fit statistics per outcome model, including the log-likelihood, AIC and BIC.
716
+ * `augment()` returns the analysis data with `.fitted_<outcome>` and `.resid_<outcome>` columns per outcome model.
717
+
718
+ ````python
719
+ p = Process(data=df, model=7, x="Effort", y="Success", w="Motivation", m=["MediationSkills"], suppr_init=True)
720
+
721
+ estimates = p.tidy() # every estimate
722
+ indirect = p.tidy("indirect") # only the conditional indirect effects
723
+ fit = p.glance() # R², AIC, BIC, ... per outcome model
724
+ residuals = p.augment(outcome="Success") # fitted values and residuals of the outcome model
725
+
726
+ estimates.to_csv("process_model7.csv", index=False)
727
+ ````
728
+
729
+ `summary()` returns the text it prints, so `report = p.summary()` keeps a copy, and a `Process` object displayed at
730
+ the end of a notebook cell shows its tables as HTML.
731
+
604
732
  # 7. About
605
733
  PyProcessMacro was developed by Quentin André during his PhD in Marketing at INSEAD Business School, France.
606
734
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyProcessMacro
3
- Version: 1.0.14
3
+ Version: 2.1.0
4
4
  Summary: A Python library for moderation, mediation and conditional process analysis. Based on Andrew F. Hayes' Process Macro.
5
5
  Author-email: Quentin André <quentin.andre@insead.edu>
6
6
  License-Expression: MIT
@@ -27,8 +27,11 @@ Requires-Dist: pandas>=2.0
27
27
  Requires-Dist: scipy>=1.10
28
28
  Requires-Dist: matplotlib>=3.7
29
29
  Requires-Dist: seaborn>=0.13
30
+ Provides-Extra: statsmodels
31
+ Requires-Dist: statsmodels>=0.14; extra == "statsmodels"
30
32
  Provides-Extra: test
31
33
  Requires-Dist: pytest>=8; extra == "test"
34
+ Requires-Dist: statsmodels>=0.14; extra == "test"
32
35
  Dynamic: license-file
33
36
 
34
37
  PyProcessMacro: A Python Implementation of Andrew F. Hayes' 'Process' Macro
@@ -61,14 +64,16 @@ softwaress. PyProcessMacro is released under a MIT license.
61
64
  # Features
62
65
 
63
66
  In the current version, PyProcessMacro replicates the following features from the original Process Macro v2.16:
64
- * All models (1 to 76), with the exception of Model 6 (serial mediation) are supported, and have been numerically
65
- tested for accuracy against the output of the original Process macro (see the `test_models_accuracy.py`)
67
+ * All models (1 to 76) are supported. Models 1 to 5 and 7 to 76 are tested for accuracy against the output of the
68
+ original Process macro (see `tests/test_models_accuracy.py`); Model 6 (serial mediation, added in 2.1) is tested
69
+ against statsmodels-based reference computations.
66
70
  * Estimation of binary/continuous outcome variables. The binary outcomes are estimated in Logit using the
67
71
  Newton-Raphson convergence algorithm, the continuous variables are estimated using OLS.
68
72
  * All statistics reported by Process:
69
73
  * Variable parameters for outcome models
70
74
  * (Conditional) direct and indirect effects
71
- * Indices for Partial/Conditional/Moderated Moderated Mediation are always reported if the model supports them.
75
+ * The index of moderated mediation and, following PROCESS 3, the indices of partial, conditional and
76
+ moderated moderated mediation, whenever the indirect effect is linear in the moderator(s).
72
77
  * Automatic generation of spotlight values for continuous/discrete moderators.
73
78
  * Rich set of options to tweak the estimation and display of the different models: (almost) all the options from
74
79
  Process exist in PyProcessMacro. Check the doc for more details.
@@ -90,10 +95,41 @@ In the current version, the following features have not yet been ported to PyPro
90
95
  * Support for categorical independent variables.
91
96
  * Generation of individual fixed effects for repeated measures.
92
97
  * R² improvement from moderators in moderation models (1, 2, 3).
93
- * Estimation of serial mediation (Model 6)
94
98
  * Some options (`normal`, `varorder`, ...). PyProcessMacro will issue a warning to tell you if an option you are
95
99
  trying to use is not implemented.
96
100
 
101
+ # Upgrading to 2.0
102
+
103
+ Version 2.0 corrects several statistics and tightens input handling. Reported numbers change in these ways:
104
+
105
+ * Confidence intervals of OLS coefficients and of (conditional) direct effects use t critical values with the
106
+ residual degrees of freedom, as PROCESS does. They were based on z, so they widen slightly; the difference is
107
+ visible in small samples.
108
+ * Adjusted R² of OLS outcome models is slightly higher: the previous value used one degree of freedom too many.
109
+ * Cox-Snell and Nagelkerke pseudo R² of logistic outcome models are finite for large samples instead of NaN.
110
+ * No index of moderated mediation is reported when a moderator sits on both the X-to-M and the M-to-Y paths
111
+ (models 58 to 73, 75 and 76), matching PROCESS: the indirect effect is not linear in such a moderator. The
112
+ `*_index_summary()` methods raise `NotImplementedError` for those models.
113
+ * The sample size reported after listwise deletion is the number of rows kept.
114
+
115
+ Behaviour that used to be silent now speaks up:
116
+
117
+ * A misspelled key in `modval`, or a keyword argument that is neither a variable nor an option, raises an error
118
+ instead of being ignored.
119
+ * Unsupported PROCESS options (`jn`, `effsize`, `mc`, `normal`, ...) raise a visible `UserWarning`.
120
+ * A logistic regression that does not converge raises `pyprocessmacro.ConvergenceError`. Bootstrap resamples
121
+ that fail are counted, and the bootstrap stops with an error if more resamples fail than were requested.
122
+
123
+ Removed and added:
124
+
125
+ * `plot_direct_effects()` and `plot_indirect_effects()` are removed; use `plot_conditional_direct_effects()`
126
+ and `plot_conditional_indirect_effects()`.
127
+ * `cov_type` selects the OLS covariance estimator (`"standard"`, `"HC0"`, `"HC1"`, `"HC2"` or `"HC3"`);
128
+ `hc3=True` remains as shorthand for `"HC3"`.
129
+ * `seed=None` draws a different bootstrap sample on every run, and `seed=0` is accepted.
130
+ * `Process.dv` names the outcome variable (`iv` is kept for compatibility).
131
+ * Python 3.11 or newer is required (since 1.0.14).
132
+
97
133
  # Version History
98
134
 
99
135
  ## Master Versions
@@ -117,7 +153,7 @@ report and for the fix.
117
153
 
118
154
  ### 1.0.4
119
155
  **Bug fix for standard error estimate in all models**
120
- PyProcessMacro was, by default, using the HC3 estimator for the variance-covariance matrix instead of the HC0 estimator.
156
+ PyProcessMacro was, by default, using the HC3 estimator for the variance-covariance matrix instead of the standard (non-robust) estimator.
121
157
  This has now been changed. To continue using the HC3 estimator, specify `hc3=True` when initializing the Process instance.
122
158
  Thanks to Zoé Ziani for the bug report.
123
159
 
@@ -199,6 +235,8 @@ As you can see, the syntax for PyProcessMacro is (almost) identical to that of P
199
235
 
200
236
  Once the object is initialized, you can call its `summary()` method to display the estimation results
201
237
 
238
+ The standardized result tables (`tidy()`, `glance()`, `augment()`) are described in section 6.
239
+
202
240
  You might have noticed that there is no argument `varlist` in PyProcessMacro. This is because the list of variables
203
241
  is automatically inferred from the variable names given to x, y, m.
204
242
 
@@ -274,6 +312,48 @@ p = Process(data=df, model=13, x="Effort", y="Success", w="Motivation", z="Skill
274
312
  p.summary()
275
313
  ````
276
314
 
315
+ ### F. Choosing the covariance estimator
316
+
317
+ By default, the standard errors of the OLS outcome models use the standard (homoskedastic) estimator. The
318
+ `cov_type` argument selects a heteroskedasticity-consistent estimator instead: `"HC0"`, `"HC1"`, `"HC2"` or
319
+ `"HC3"`. `hc3=True` is shorthand for `cov_type="HC3"`, which is what the original Process macro uses when
320
+ `hc3=1` is specified. Logistic outcome models always use the inverse of the Hessian.
321
+
322
+ ````python
323
+ p = Process(data=df, model=4, x="Effort", y="Success", m=["MediationSkills"], cov_type="HC3")
324
+ ````
325
+
326
+ ### G. Serial mediation (Model 6)
327
+
328
+ In Model 6 the mediators form a chain: each mediator depends on X and on the mediators before it, and Y depends
329
+ on X and on every mediator. Pass two to four mediators in causal order. PyProcessMacro reports the specific
330
+ indirect effect through every ordered subset of mediators (three paths for two mediators, seven for three,
331
+ fifteen for four), labelled by the path, plus the total and the pairwise contrasts when `total=True` and
332
+ `contrast=True`.
333
+
334
+ ````python
335
+ p = Process(data=df, model=6, x="Effort", y="Success", m=["Attention", "MediationSkills"], total=True)
336
+ p.summary()
337
+ ````
338
+
339
+ Model 6 has no moderators, so the spotlight, floodlight and plotting methods do not apply to it. Its estimates are
340
+ checked against products of statsmodels coefficients and against an independent resampler; no PROCESS output for
341
+ Model 6 is part of the test fixtures yet, so a comparison file generated with PROCESS 2.16 would be a welcome
342
+ contribution.
343
+
344
+ ### H. Effect sizes for the indirect effect
345
+
346
+ With `effsize=True`, PyProcessMacro also reports the partially standardized indirect effect (the indirect effect
347
+ divided by the standard deviation of Y) and the completely standardized indirect effect (further multiplied by the
348
+ standard deviation of X), each with a bootstrap confidence interval computed by standardizing within every resample,
349
+ as PROCESS does. The option applies to unmoderated indirect paths with a continuous outcome, that is Models 4 and 6
350
+ with `logit=False`.
351
+
352
+ ````python
353
+ p = Process(data=df, model=4, x="Effort", y="Success", m=["MediationSkills"], effsize=True)
354
+ p.indirect_model.effect_size_summary()
355
+ ````
356
+
277
357
  ## 2. Accessing the estimation results
278
358
 
279
359
  After the `Process` object is initialized, you are not limited to printing the summary. PyProcessMacro implements the
@@ -371,6 +451,28 @@ Note that the methods are called from the `indirect_model` object! If you call `
371
451
  error.
372
452
 
373
453
 
454
+ ### E. Diagnostics and custom tests with statsmodels
455
+
456
+ Each outcome model can be handed to [statsmodels](https://www.statsmodels.org), which refits the same design
457
+ matrix with the same covariance estimator and returns the statsmodels results object. From there you get
458
+ `summary()`, custom contrasts with `t_test()` and `wald_test()`, heteroskedasticity and influence diagnostics,
459
+ variance inflation factors, prediction intervals, and the table formatters that accept statsmodels results.
460
+ statsmodels is optional: install it with `pip install pyprocessmacro[statsmodels]`.
461
+
462
+ ````python
463
+ p = Process(data=df, model=7, x="Effort", y="Success", w="Motivation", m=["MediationSkills"], suppr_init=True)
464
+
465
+ fit = p.outcome_models["Success"].to_statsmodels() # a statsmodels RegressionResults
466
+ print(fit.summary())
467
+ fit.t_test("Effort + MediationSkills = 0")
468
+
469
+ fits = p.to_statsmodels() # every outcome model, keyed by outcome name
470
+ ````
471
+
472
+ For a different question, statsmodels also ships `statsmodels.stats.mediation.Mediation`, Imai-style causal
473
+ mediation with a sensitivity analysis; it estimates a different quantity and is a useful cross-check rather than
474
+ a replacement for the PROCESS approach.
475
+
374
476
  ## 3. Spotlight and Floodlight Analysis
375
477
 
376
478
  ### A. Compute direct/indirect effects for specific values (spotlight analysis)
@@ -601,6 +703,32 @@ g = p.plot_conditional_indirect_effects(med_name="MediationSkills", x="Motivatio
601
703
  ````
602
704
  ![PlotCustomKws](images/Ex12.png)
603
705
 
706
+ ## 6. Standardized results: tidy(), glance() and augment()
707
+
708
+ Every table PyProcessMacro prints is also available in a standardized form, modelled on R's broom package:
709
+
710
+ * `tidy()` returns one long DataFrame with one row per estimate and fixed column names: `component`
711
+ (`outcome`, `direct`, `indirect`, `total`, `contrast`, or `index_mm`, `index_pmm`, `index_mmm`, `index_cmm`),
712
+ `outcome`, `term`, `moderator`, one column per moderator of the model holding the spotlight value the row is
713
+ evaluated at, then `estimate`, `std_error`, `statistic`, `p_value`, `conf_low`, `conf_high`, `method`,
714
+ `conf_level` and `n_boot`. Pass `component=` to keep one kind of row.
715
+ * `glance()` returns one row of fit statistics per outcome model, including the log-likelihood, AIC and BIC.
716
+ * `augment()` returns the analysis data with `.fitted_<outcome>` and `.resid_<outcome>` columns per outcome model.
717
+
718
+ ````python
719
+ p = Process(data=df, model=7, x="Effort", y="Success", w="Motivation", m=["MediationSkills"], suppr_init=True)
720
+
721
+ estimates = p.tidy() # every estimate
722
+ indirect = p.tidy("indirect") # only the conditional indirect effects
723
+ fit = p.glance() # R², AIC, BIC, ... per outcome model
724
+ residuals = p.augment(outcome="Success") # fitted values and residuals of the outcome model
725
+
726
+ estimates.to_csv("process_model7.csv", index=False)
727
+ ````
728
+
729
+ `summary()` returns the text it prints, so `report = p.summary()` keeps a copy, and a `Process` object displayed at
730
+ the end of a notebook cell shows its tables as HTML.
731
+
604
732
  # 7. About
605
733
  PyProcessMacro was developed by Quentin André during his PhD in Marketing at INSEAD Business School, France.
606
734
 
@@ -8,9 +8,10 @@ PyProcessMacro.egg-info/dependency_links.txt
8
8
  PyProcessMacro.egg-info/requires.txt
9
9
  PyProcessMacro.egg-info/top_level.txt
10
10
  pyprocessmacro/__init__.py
11
+ pyprocessmacro/bootstrap.py
12
+ pyprocessmacro/effsize.py
11
13
  pyprocessmacro/models.py
12
- pyprocessmacro/models.pyi
13
14
  pyprocessmacro/process.py
14
- pyprocessmacro/process.pyi
15
- pyprocessmacro/utils.py
16
- pyprocessmacro/utils.pyi
15
+ pyprocessmacro/serial.py
16
+ pyprocessmacro/tidy.py
17
+ pyprocessmacro/utils.py
@@ -4,5 +4,9 @@ scipy>=1.10
4
4
  matplotlib>=3.7
5
5
  seaborn>=0.13
6
6
 
7
+ [statsmodels]
8
+ statsmodels>=0.14
9
+
7
10
  [test]
8
11
  pytest>=8
12
+ statsmodels>=0.14
@@ -28,14 +28,16 @@ softwaress. PyProcessMacro is released under a MIT license.
28
28
  # Features
29
29
 
30
30
  In the current version, PyProcessMacro replicates the following features from the original Process Macro v2.16:
31
- * All models (1 to 76), with the exception of Model 6 (serial mediation) are supported, and have been numerically
32
- tested for accuracy against the output of the original Process macro (see the `test_models_accuracy.py`)
31
+ * All models (1 to 76) are supported. Models 1 to 5 and 7 to 76 are tested for accuracy against the output of the
32
+ original Process macro (see `tests/test_models_accuracy.py`); Model 6 (serial mediation, added in 2.1) is tested
33
+ against statsmodels-based reference computations.
33
34
  * Estimation of binary/continuous outcome variables. The binary outcomes are estimated in Logit using the
34
35
  Newton-Raphson convergence algorithm, the continuous variables are estimated using OLS.
35
36
  * All statistics reported by Process:
36
37
  * Variable parameters for outcome models
37
38
  * (Conditional) direct and indirect effects
38
- * Indices for Partial/Conditional/Moderated Moderated Mediation are always reported if the model supports them.
39
+ * The index of moderated mediation and, following PROCESS 3, the indices of partial, conditional and
40
+ moderated moderated mediation, whenever the indirect effect is linear in the moderator(s).
39
41
  * Automatic generation of spotlight values for continuous/discrete moderators.
40
42
  * Rich set of options to tweak the estimation and display of the different models: (almost) all the options from
41
43
  Process exist in PyProcessMacro. Check the doc for more details.
@@ -57,10 +59,41 @@ In the current version, the following features have not yet been ported to PyPro
57
59
  * Support for categorical independent variables.
58
60
  * Generation of individual fixed effects for repeated measures.
59
61
  * R² improvement from moderators in moderation models (1, 2, 3).
60
- * Estimation of serial mediation (Model 6)
61
62
  * Some options (`normal`, `varorder`, ...). PyProcessMacro will issue a warning to tell you if an option you are
62
63
  trying to use is not implemented.
63
64
 
65
+ # Upgrading to 2.0
66
+
67
+ Version 2.0 corrects several statistics and tightens input handling. Reported numbers change in these ways:
68
+
69
+ * Confidence intervals of OLS coefficients and of (conditional) direct effects use t critical values with the
70
+ residual degrees of freedom, as PROCESS does. They were based on z, so they widen slightly; the difference is
71
+ visible in small samples.
72
+ * Adjusted R² of OLS outcome models is slightly higher: the previous value used one degree of freedom too many.
73
+ * Cox-Snell and Nagelkerke pseudo R² of logistic outcome models are finite for large samples instead of NaN.
74
+ * No index of moderated mediation is reported when a moderator sits on both the X-to-M and the M-to-Y paths
75
+ (models 58 to 73, 75 and 76), matching PROCESS: the indirect effect is not linear in such a moderator. The
76
+ `*_index_summary()` methods raise `NotImplementedError` for those models.
77
+ * The sample size reported after listwise deletion is the number of rows kept.
78
+
79
+ Behaviour that used to be silent now speaks up:
80
+
81
+ * A misspelled key in `modval`, or a keyword argument that is neither a variable nor an option, raises an error
82
+ instead of being ignored.
83
+ * Unsupported PROCESS options (`jn`, `effsize`, `mc`, `normal`, ...) raise a visible `UserWarning`.
84
+ * A logistic regression that does not converge raises `pyprocessmacro.ConvergenceError`. Bootstrap resamples
85
+ that fail are counted, and the bootstrap stops with an error if more resamples fail than were requested.
86
+
87
+ Removed and added:
88
+
89
+ * `plot_direct_effects()` and `plot_indirect_effects()` are removed; use `plot_conditional_direct_effects()`
90
+ and `plot_conditional_indirect_effects()`.
91
+ * `cov_type` selects the OLS covariance estimator (`"standard"`, `"HC0"`, `"HC1"`, `"HC2"` or `"HC3"`);
92
+ `hc3=True` remains as shorthand for `"HC3"`.
93
+ * `seed=None` draws a different bootstrap sample on every run, and `seed=0` is accepted.
94
+ * `Process.dv` names the outcome variable (`iv` is kept for compatibility).
95
+ * Python 3.11 or newer is required (since 1.0.14).
96
+
64
97
  # Version History
65
98
 
66
99
  ## Master Versions
@@ -84,7 +117,7 @@ report and for the fix.
84
117
 
85
118
  ### 1.0.4
86
119
  **Bug fix for standard error estimate in all models**
87
- PyProcessMacro was, by default, using the HC3 estimator for the variance-covariance matrix instead of the HC0 estimator.
120
+ PyProcessMacro was, by default, using the HC3 estimator for the variance-covariance matrix instead of the standard (non-robust) estimator.
88
121
  This has now been changed. To continue using the HC3 estimator, specify `hc3=True` when initializing the Process instance.
89
122
  Thanks to Zoé Ziani for the bug report.
90
123
 
@@ -166,6 +199,8 @@ As you can see, the syntax for PyProcessMacro is (almost) identical to that of P
166
199
 
167
200
  Once the object is initialized, you can call its `summary()` method to display the estimation results
168
201
 
202
+ The standardized result tables (`tidy()`, `glance()`, `augment()`) are described in section 6.
203
+
169
204
  You might have noticed that there is no argument `varlist` in PyProcessMacro. This is because the list of variables
170
205
  is automatically inferred from the variable names given to x, y, m.
171
206
 
@@ -241,6 +276,48 @@ p = Process(data=df, model=13, x="Effort", y="Success", w="Motivation", z="Skill
241
276
  p.summary()
242
277
  ````
243
278
 
279
+ ### F. Choosing the covariance estimator
280
+
281
+ By default, the standard errors of the OLS outcome models use the standard (homoskedastic) estimator. The
282
+ `cov_type` argument selects a heteroskedasticity-consistent estimator instead: `"HC0"`, `"HC1"`, `"HC2"` or
283
+ `"HC3"`. `hc3=True` is shorthand for `cov_type="HC3"`, which is what the original Process macro uses when
284
+ `hc3=1` is specified. Logistic outcome models always use the inverse of the Hessian.
285
+
286
+ ````python
287
+ p = Process(data=df, model=4, x="Effort", y="Success", m=["MediationSkills"], cov_type="HC3")
288
+ ````
289
+
290
+ ### G. Serial mediation (Model 6)
291
+
292
+ In Model 6 the mediators form a chain: each mediator depends on X and on the mediators before it, and Y depends
293
+ on X and on every mediator. Pass two to four mediators in causal order. PyProcessMacro reports the specific
294
+ indirect effect through every ordered subset of mediators (three paths for two mediators, seven for three,
295
+ fifteen for four), labelled by the path, plus the total and the pairwise contrasts when `total=True` and
296
+ `contrast=True`.
297
+
298
+ ````python
299
+ p = Process(data=df, model=6, x="Effort", y="Success", m=["Attention", "MediationSkills"], total=True)
300
+ p.summary()
301
+ ````
302
+
303
+ Model 6 has no moderators, so the spotlight, floodlight and plotting methods do not apply to it. Its estimates are
304
+ checked against products of statsmodels coefficients and against an independent resampler; no PROCESS output for
305
+ Model 6 is part of the test fixtures yet, so a comparison file generated with PROCESS 2.16 would be a welcome
306
+ contribution.
307
+
308
+ ### H. Effect sizes for the indirect effect
309
+
310
+ With `effsize=True`, PyProcessMacro also reports the partially standardized indirect effect (the indirect effect
311
+ divided by the standard deviation of Y) and the completely standardized indirect effect (further multiplied by the
312
+ standard deviation of X), each with a bootstrap confidence interval computed by standardizing within every resample,
313
+ as PROCESS does. The option applies to unmoderated indirect paths with a continuous outcome, that is Models 4 and 6
314
+ with `logit=False`.
315
+
316
+ ````python
317
+ p = Process(data=df, model=4, x="Effort", y="Success", m=["MediationSkills"], effsize=True)
318
+ p.indirect_model.effect_size_summary()
319
+ ````
320
+
244
321
  ## 2. Accessing the estimation results
245
322
 
246
323
  After the `Process` object is initialized, you are not limited to printing the summary. PyProcessMacro implements the
@@ -338,6 +415,28 @@ Note that the methods are called from the `indirect_model` object! If you call `
338
415
  error.
339
416
 
340
417
 
418
+ ### E. Diagnostics and custom tests with statsmodels
419
+
420
+ Each outcome model can be handed to [statsmodels](https://www.statsmodels.org), which refits the same design
421
+ matrix with the same covariance estimator and returns the statsmodels results object. From there you get
422
+ `summary()`, custom contrasts with `t_test()` and `wald_test()`, heteroskedasticity and influence diagnostics,
423
+ variance inflation factors, prediction intervals, and the table formatters that accept statsmodels results.
424
+ statsmodels is optional: install it with `pip install pyprocessmacro[statsmodels]`.
425
+
426
+ ````python
427
+ p = Process(data=df, model=7, x="Effort", y="Success", w="Motivation", m=["MediationSkills"], suppr_init=True)
428
+
429
+ fit = p.outcome_models["Success"].to_statsmodels() # a statsmodels RegressionResults
430
+ print(fit.summary())
431
+ fit.t_test("Effort + MediationSkills = 0")
432
+
433
+ fits = p.to_statsmodels() # every outcome model, keyed by outcome name
434
+ ````
435
+
436
+ For a different question, statsmodels also ships `statsmodels.stats.mediation.Mediation`, Imai-style causal
437
+ mediation with a sensitivity analysis; it estimates a different quantity and is a useful cross-check rather than
438
+ a replacement for the PROCESS approach.
439
+
341
440
  ## 3. Spotlight and Floodlight Analysis
342
441
 
343
442
  ### A. Compute direct/indirect effects for specific values (spotlight analysis)
@@ -568,6 +667,32 @@ g = p.plot_conditional_indirect_effects(med_name="MediationSkills", x="Motivatio
568
667
  ````
569
668
  ![PlotCustomKws](images/Ex12.png)
570
669
 
670
+ ## 6. Standardized results: tidy(), glance() and augment()
671
+
672
+ Every table PyProcessMacro prints is also available in a standardized form, modelled on R's broom package:
673
+
674
+ * `tidy()` returns one long DataFrame with one row per estimate and fixed column names: `component`
675
+ (`outcome`, `direct`, `indirect`, `total`, `contrast`, or `index_mm`, `index_pmm`, `index_mmm`, `index_cmm`),
676
+ `outcome`, `term`, `moderator`, one column per moderator of the model holding the spotlight value the row is
677
+ evaluated at, then `estimate`, `std_error`, `statistic`, `p_value`, `conf_low`, `conf_high`, `method`,
678
+ `conf_level` and `n_boot`. Pass `component=` to keep one kind of row.
679
+ * `glance()` returns one row of fit statistics per outcome model, including the log-likelihood, AIC and BIC.
680
+ * `augment()` returns the analysis data with `.fitted_<outcome>` and `.resid_<outcome>` columns per outcome model.
681
+
682
+ ````python
683
+ p = Process(data=df, model=7, x="Effort", y="Success", w="Motivation", m=["MediationSkills"], suppr_init=True)
684
+
685
+ estimates = p.tidy() # every estimate
686
+ indirect = p.tidy("indirect") # only the conditional indirect effects
687
+ fit = p.glance() # R², AIC, BIC, ... per outcome model
688
+ residuals = p.augment(outcome="Success") # fitted values and residuals of the outcome model
689
+
690
+ estimates.to_csv("process_model7.csv", index=False)
691
+ ````
692
+
693
+ `summary()` returns the text it prints, so `report = p.summary()` keeps a copy, and a `Process` object displayed at
694
+ the end of a notebook cell shows its tables as HTML.
695
+
571
696
  # 7. About
572
697
  PyProcessMacro was developed by Quentin André during his PhD in Marketing at INSEAD Business School, France.
573
698
 
@@ -0,0 +1,10 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Core module for the PyProcess Macro.
4
+ """
5
+ from .process import Process
6
+ from .utils import ConvergenceError
7
+
8
+ __all__ = ["Process", "ConvergenceError"]
9
+
10
+ __version__ = "2.1.0"