openstat-cli 1.0.0__py3-none-any.whl

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 (143) hide show
  1. openstat/__init__.py +3 -0
  2. openstat/__main__.py +4 -0
  3. openstat/backends/__init__.py +16 -0
  4. openstat/backends/duckdb_backend.py +70 -0
  5. openstat/backends/polars_backend.py +52 -0
  6. openstat/cli.py +92 -0
  7. openstat/commands/__init__.py +82 -0
  8. openstat/commands/adv_stat_cmds.py +1255 -0
  9. openstat/commands/advanced_ml_cmds.py +576 -0
  10. openstat/commands/advreg_cmds.py +207 -0
  11. openstat/commands/alias_cmds.py +135 -0
  12. openstat/commands/arch_cmds.py +82 -0
  13. openstat/commands/arules_cmds.py +111 -0
  14. openstat/commands/automodel_cmds.py +212 -0
  15. openstat/commands/backend_cmds.py +82 -0
  16. openstat/commands/base.py +170 -0
  17. openstat/commands/bayes_cmds.py +71 -0
  18. openstat/commands/causal_cmds.py +269 -0
  19. openstat/commands/cluster_cmds.py +152 -0
  20. openstat/commands/data_cmds.py +996 -0
  21. openstat/commands/datamanip_cmds.py +672 -0
  22. openstat/commands/dataquality_cmds.py +174 -0
  23. openstat/commands/datetime_cmds.py +176 -0
  24. openstat/commands/dimreduce_cmds.py +184 -0
  25. openstat/commands/discrete_cmds.py +149 -0
  26. openstat/commands/dsl_cmds.py +143 -0
  27. openstat/commands/epi_cmds.py +93 -0
  28. openstat/commands/equiv_tobit_cmds.py +94 -0
  29. openstat/commands/esttab_cmds.py +196 -0
  30. openstat/commands/export_beamer_cmds.py +142 -0
  31. openstat/commands/export_cmds.py +201 -0
  32. openstat/commands/export_extra_cmds.py +240 -0
  33. openstat/commands/factor_cmds.py +180 -0
  34. openstat/commands/groupby_cmds.py +155 -0
  35. openstat/commands/help_cmds.py +237 -0
  36. openstat/commands/i18n_cmds.py +43 -0
  37. openstat/commands/import_extra_cmds.py +561 -0
  38. openstat/commands/influence_cmds.py +134 -0
  39. openstat/commands/iv_cmds.py +106 -0
  40. openstat/commands/manova_cmds.py +105 -0
  41. openstat/commands/mediate_cmds.py +233 -0
  42. openstat/commands/meta_cmds.py +284 -0
  43. openstat/commands/mi_cmds.py +228 -0
  44. openstat/commands/mixed_cmds.py +79 -0
  45. openstat/commands/mixture_changepoint_cmds.py +166 -0
  46. openstat/commands/ml_adv_cmds.py +147 -0
  47. openstat/commands/ml_cmds.py +178 -0
  48. openstat/commands/model_eval_cmds.py +142 -0
  49. openstat/commands/network_cmds.py +288 -0
  50. openstat/commands/nlquery_cmds.py +161 -0
  51. openstat/commands/nonparam_cmds.py +149 -0
  52. openstat/commands/outreg_cmds.py +247 -0
  53. openstat/commands/panel_cmds.py +141 -0
  54. openstat/commands/pdf_cmds.py +226 -0
  55. openstat/commands/pipeline_cmds.py +319 -0
  56. openstat/commands/plot_cmds.py +189 -0
  57. openstat/commands/plugin_cmds.py +79 -0
  58. openstat/commands/posthoc_cmds.py +153 -0
  59. openstat/commands/power_cmds.py +172 -0
  60. openstat/commands/profile_cmds.py +246 -0
  61. openstat/commands/rbridge_cmds.py +81 -0
  62. openstat/commands/regex_cmds.py +104 -0
  63. openstat/commands/report_cmds.py +48 -0
  64. openstat/commands/repro_cmds.py +129 -0
  65. openstat/commands/resampling_cmds.py +109 -0
  66. openstat/commands/reshape_cmds.py +223 -0
  67. openstat/commands/sem_cmds.py +177 -0
  68. openstat/commands/stat_cmds.py +1040 -0
  69. openstat/commands/stata_import_cmds.py +215 -0
  70. openstat/commands/string_cmds.py +124 -0
  71. openstat/commands/surv_cmds.py +145 -0
  72. openstat/commands/survey_cmds.py +153 -0
  73. openstat/commands/textanalysis_cmds.py +192 -0
  74. openstat/commands/ts_adv_cmds.py +136 -0
  75. openstat/commands/ts_cmds.py +195 -0
  76. openstat/commands/tui_cmds.py +111 -0
  77. openstat/commands/ux_cmds.py +191 -0
  78. openstat/commands/validate_cmds.py +270 -0
  79. openstat/commands/viz_adv_cmds.py +312 -0
  80. openstat/commands/viz_extra_cmds.py +251 -0
  81. openstat/commands/watch_cmds.py +69 -0
  82. openstat/config.py +106 -0
  83. openstat/dsl/__init__.py +0 -0
  84. openstat/dsl/parser.py +332 -0
  85. openstat/dsl/tokenizer.py +105 -0
  86. openstat/i18n.py +120 -0
  87. openstat/io/__init__.py +0 -0
  88. openstat/io/loader.py +187 -0
  89. openstat/jupyter/__init__.py +18 -0
  90. openstat/jupyter/display.py +18 -0
  91. openstat/jupyter/magic.py +60 -0
  92. openstat/logging_config.py +59 -0
  93. openstat/plots/__init__.py +0 -0
  94. openstat/plots/plotter.py +437 -0
  95. openstat/plots/surv_plots.py +32 -0
  96. openstat/plots/ts_plots.py +59 -0
  97. openstat/plugins/__init__.py +5 -0
  98. openstat/plugins/manager.py +69 -0
  99. openstat/repl.py +457 -0
  100. openstat/reporting/__init__.py +0 -0
  101. openstat/reporting/eda.py +208 -0
  102. openstat/reporting/report.py +67 -0
  103. openstat/script_runner.py +319 -0
  104. openstat/session.py +133 -0
  105. openstat/stats/__init__.py +0 -0
  106. openstat/stats/advanced_regression.py +269 -0
  107. openstat/stats/arch_garch.py +84 -0
  108. openstat/stats/bayesian.py +103 -0
  109. openstat/stats/causal.py +258 -0
  110. openstat/stats/clustering.py +206 -0
  111. openstat/stats/discrete.py +311 -0
  112. openstat/stats/epidemiology.py +119 -0
  113. openstat/stats/equiv_tobit.py +163 -0
  114. openstat/stats/factor.py +174 -0
  115. openstat/stats/imputation.py +282 -0
  116. openstat/stats/influence.py +78 -0
  117. openstat/stats/iv.py +131 -0
  118. openstat/stats/manova.py +124 -0
  119. openstat/stats/mixed.py +128 -0
  120. openstat/stats/ml.py +275 -0
  121. openstat/stats/ml_advanced.py +117 -0
  122. openstat/stats/model_eval.py +183 -0
  123. openstat/stats/models.py +1342 -0
  124. openstat/stats/nonparametric.py +130 -0
  125. openstat/stats/panel.py +179 -0
  126. openstat/stats/power.py +295 -0
  127. openstat/stats/resampling.py +203 -0
  128. openstat/stats/survey.py +213 -0
  129. openstat/stats/survival.py +196 -0
  130. openstat/stats/timeseries.py +142 -0
  131. openstat/stats/ts_advanced.py +114 -0
  132. openstat/types.py +11 -0
  133. openstat/web/__init__.py +1 -0
  134. openstat/web/app.py +117 -0
  135. openstat/web/session_manager.py +73 -0
  136. openstat/web/static/app.js +117 -0
  137. openstat/web/static/index.html +38 -0
  138. openstat/web/static/style.css +103 -0
  139. openstat_cli-1.0.0.dist-info/METADATA +748 -0
  140. openstat_cli-1.0.0.dist-info/RECORD +143 -0
  141. openstat_cli-1.0.0.dist-info/WHEEL +4 -0
  142. openstat_cli-1.0.0.dist-info/entry_points.txt +2 -0
  143. openstat_cli-1.0.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,177 @@
1
+ """Structural Equation Modeling (SEM) commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from openstat.commands.base import command
6
+ from openstat.session import Session
7
+
8
+
9
+ def _fmt_sem(title: str, lines_body: list[str]) -> str:
10
+ sep = "=" * 60
11
+ return "\n".join([f"\n{title}", sep] + lines_body + [sep])
12
+
13
+
14
+ @command("sem", usage="sem model_syntax [--method=ml|gls|wls]")
15
+ def cmd_sem(session: Session, args: str) -> str:
16
+ """Structural Equation Model estimation via semopy.
17
+
18
+ Model syntax (lavaan/semopy style):
19
+ Latent variable: F1 =~ x1 + x2 + x3
20
+ Regression: y ~ x1 + x2
21
+ Covariance: x1 ~~ x2
22
+
23
+ Examples:
24
+ sem 'F1 =~ age + income + score'
25
+ sem 'eta =~ x1 + x2 + x3 \\n y ~ eta + z'
26
+ sem 'F1 =~ x1 + x2 \\n y ~ F1' --method=ml
27
+
28
+ Requires: pip install semopy
29
+ """
30
+ try:
31
+ import semopy
32
+ except ImportError:
33
+ return "SEM requires semopy. Install with: pip install semopy"
34
+
35
+ df = session.require_data()
36
+
37
+ import re
38
+ args = args.strip()
39
+
40
+ # Parse --method option
41
+ method = "ml"
42
+ m = re.search(r"--method[= ](\w+)", args)
43
+ if m:
44
+ method = m.group(1).lower()
45
+ args = re.sub(r"--method[= ]\w+", "", args).strip()
46
+
47
+ # Strip surrounding quotes
48
+ model_str = args.strip("\"'")
49
+ # Support \n in quoted strings as actual newlines
50
+ model_str = model_str.replace("\\n", "\n")
51
+
52
+ if not model_str:
53
+ return (
54
+ "Usage: sem '<model_syntax>' [--method=ml|gls|wls]\n"
55
+ "Example: sem 'F1 =~ x1 + x2 + x3'\n"
56
+ "Example: sem 'y ~ x1 + x2'"
57
+ )
58
+
59
+ # Map user-friendly method names to semopy obj parameter
60
+ _method_map = {"ml": "MLW", "gls": "GLS", "wls": "WLS", "uls": "ULS", "fiml": "FIML"}
61
+ obj = _method_map.get(method.lower(), "MLW")
62
+
63
+ try:
64
+ pandas_df = df.to_pandas()
65
+ model = semopy.Model(model_str)
66
+ res = model.fit(pandas_df, obj=obj)
67
+
68
+ # Model fit indices
69
+ stats = semopy.calc_stats(model)
70
+
71
+ lines = [
72
+ f"Model: {model_str.replace(chr(10), ' | ')}",
73
+ f"Method: {method.upper()} N = {len(pandas_df)}",
74
+ "",
75
+ ]
76
+
77
+ # Parameter estimates
78
+ try:
79
+ params = model.inspect()
80
+ lines.append("Parameter Estimates:")
81
+ lines.append(f" {'lval':<12} {'op':<5} {'rval':<12} {'Estimate':>10} {'Std.Err':>9} {'z':>7} {'p-value':>9}")
82
+ lines.append(" " + "-" * 65)
83
+ for _, row in params.iterrows():
84
+ p_str = f"{row.get('p-value', float('nan')):.4f}" if row.get('p-value') is not None else " ."
85
+ z_str = f"{row.get('z-value', float('nan')):.3f}" if row.get('z-value') is not None else " ."
86
+ se_str = f"{row.get('Std. Err', float('nan')):.4f}" if row.get('Std. Err') is not None else " ."
87
+ lines.append(
88
+ f" {str(row.get('lval','')):<12} {str(row.get('op','')):<5} "
89
+ f"{str(row.get('rval','')):<12} "
90
+ f"{row.get('Estimate', float('nan')):>10.4f} "
91
+ f"{se_str:>9} {z_str:>7} {p_str:>9}"
92
+ )
93
+ except Exception:
94
+ lines.append("(Parameter table unavailable)")
95
+
96
+ # Fit indices
97
+ lines.append("")
98
+ lines.append("Model Fit Indices:")
99
+ fit_map = {
100
+ "CFI": "CFI", "GFI": "GFI", "AGFI": "AGFI",
101
+ "NFI": "NFI", "RMSEA": "RMSEA", "SRMR": "SRMR",
102
+ "chi2": "Chi-sq", "DoF": "df", "pvalue": "p(chi-sq)",
103
+ "AIC": "AIC", "BIC": "BIC",
104
+ }
105
+ for key, label in fit_map.items():
106
+ try:
107
+ val = stats[key].iloc[0] if hasattr(stats[key], 'iloc') else stats.get(key)
108
+ if val is not None:
109
+ lines.append(f" {label:<12} {float(val):.4f}")
110
+ except Exception:
111
+ pass
112
+
113
+ # Interpretation hints
114
+ lines.append("")
115
+ lines.append("Fit guidelines: CFI/GFI > 0.95 (good), RMSEA < 0.05 (good), SRMR < 0.08 (good)")
116
+
117
+ return _fmt_sem("Structural Equation Model (SEM)", lines)
118
+
119
+ except Exception as exc:
120
+ return f"SEM error: {exc}"
121
+
122
+
123
+ @command("cfa", usage="cfa factor =~ x1 + x2 + x3 [+ factor2 =~ y1 + y2]")
124
+ def cmd_cfa(session: Session, args: str) -> str:
125
+ """Confirmatory Factor Analysis — shortcut for SEM with =~ syntax only.
126
+
127
+ Examples:
128
+ cfa F1 =~ age + income + score
129
+ cfa 'F1 =~ x1 + x2 \\n F2 =~ y1 + y2'
130
+ """
131
+ try:
132
+ import semopy
133
+ except ImportError:
134
+ return "CFA requires semopy. Install with: pip install semopy"
135
+
136
+ df = session.require_data()
137
+ model_str = args.strip().strip("\"'").replace("\\n", "\n")
138
+ if not model_str:
139
+ return "Usage: cfa 'F1 =~ x1 + x2 + x3'"
140
+
141
+ try:
142
+ pandas_df = df.to_pandas()
143
+ model = semopy.Model(model_str)
144
+ model.fit(pandas_df)
145
+
146
+ params = model.inspect() # type: ignore[attr-defined]
147
+ stats = semopy.calc_stats(model)
148
+
149
+ lines = [f"CFA Model: {model_str.replace(chr(10), ' | ')}", f"N = {len(pandas_df)}", ""]
150
+
151
+ # Loadings only (=~ relationships)
152
+ loadings = params[params["op"] == "=~"] if "op" in params.columns else params
153
+ if not loadings.empty:
154
+ lines.append("Factor Loadings:")
155
+ lines.append(f" {'Factor':<12} {'Indicator':<12} {'Loading':>9} {'Std.Err':>9} {'p-value':>9}")
156
+ lines.append(" " + "-" * 55)
157
+ for _, row in loadings.iterrows():
158
+ p_str = f"{row.get('p-value', float('nan')):.4f}"
159
+ se_str = f"{row.get('Std. Err', float('nan')):.4f}"
160
+ lines.append(
161
+ f" {str(row.get('lval','')):<12} {str(row.get('rval','')):<12} "
162
+ f"{row.get('Estimate', float('nan')):>9.4f} {se_str:>9} {p_str:>9}"
163
+ )
164
+
165
+ lines.append("")
166
+ lines.append("Fit Indices:")
167
+ for key, label in [("CFI", "CFI"), ("RMSEA", "RMSEA"), ("SRMR", "SRMR"), ("AIC", "AIC")]:
168
+ try:
169
+ val = stats[key].iloc[0]
170
+ lines.append(f" {label:<10} {float(val):.4f}")
171
+ except Exception:
172
+ pass
173
+
174
+ return _fmt_sem("Confirmatory Factor Analysis (CFA)", lines)
175
+
176
+ except Exception as exc:
177
+ return f"CFA error: {exc}"