statslibx 0.1.4__py3-none-any.whl → 0.1.5__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.
- statslibx/__init__.py +2 -2
- statslibx/datasets/__init__.py +1 -0
- statslibx/datasets/course_completion.csv +100001 -0
- statslibx/descriptive.py +39 -0
- statslibx/inferential.py +39 -0
- statslibx/utils.py +243 -404
- {statslibx-0.1.4.dist-info → statslibx-0.1.5.dist-info}/METADATA +1 -1
- statslibx-0.1.5.dist-info/RECORD +14 -0
- statslibx-0.1.4.dist-info/RECORD +0 -13
- {statslibx-0.1.4.dist-info → statslibx-0.1.5.dist-info}/WHEEL +0 -0
- {statslibx-0.1.4.dist-info → statslibx-0.1.5.dist-info}/top_level.txt +0 -0
statslibx/utils.py
CHANGED
|
@@ -6,6 +6,7 @@ import warnings
|
|
|
6
6
|
import os
|
|
7
7
|
from scipy import stats
|
|
8
8
|
import seaborn as sns
|
|
9
|
+
from pathlib import Path
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class UtilsStats:
|
|
@@ -13,11 +14,15 @@ class UtilsStats:
|
|
|
13
14
|
Clase utilitaria para operaciones estadísticas comunes y visualización
|
|
14
15
|
|
|
15
16
|
Esta clase proporciona métodos para validación de datos, análisis estadísticos
|
|
16
|
-
básicos y visualización de resultados.
|
|
17
|
+
básicos y visualización de resultados. Ahora con soporte para leer archivos directamente.
|
|
17
18
|
|
|
18
19
|
Examples:
|
|
19
20
|
---------
|
|
20
21
|
>>> utils = UtilsStats()
|
|
22
|
+
>>> # Desde archivo
|
|
23
|
+
>>> data = utils.load_data("datos.csv")
|
|
24
|
+
>>> utils.check_normality(data, column='edad')
|
|
25
|
+
>>> # Desde array
|
|
21
26
|
>>> data = np.random.normal(0, 1, 100)
|
|
22
27
|
>>> utils.check_normality(data)
|
|
23
28
|
>>> utils.plot_distribution(data)
|
|
@@ -47,15 +52,11 @@ class UtilsStats:
|
|
|
47
52
|
plt.rcParams['lines.linewidth'] = 2
|
|
48
53
|
|
|
49
54
|
def set_plot_backend(self, backend: Literal['matplotlib', 'seaborn', 'plotly']):
|
|
50
|
-
"""
|
|
51
|
-
Establecer el backend de visualización por defecto
|
|
52
|
-
"""
|
|
55
|
+
"""Establecer el backend de visualización por defecto"""
|
|
53
56
|
self._plot_backend = backend
|
|
54
57
|
|
|
55
58
|
def set_default_figsize(self, figsize: Tuple[int, int]):
|
|
56
|
-
"""
|
|
57
|
-
Establecer el tamaño de figura por defecto
|
|
58
|
-
"""
|
|
59
|
+
"""Establecer el tamaño de figura por defecto"""
|
|
59
60
|
self._default_figsize = figsize
|
|
60
61
|
plt.rcParams['figure.figsize'] = [figsize[0], figsize[1]]
|
|
61
62
|
|
|
@@ -63,18 +64,14 @@ class UtilsStats:
|
|
|
63
64
|
fig_format: str = 'png',
|
|
64
65
|
fig_dpi: int = 300,
|
|
65
66
|
figures_dir: str = 'figures'):
|
|
66
|
-
"""
|
|
67
|
-
Configurar opciones para guardar figuras
|
|
68
|
-
"""
|
|
67
|
+
"""Configurar opciones para guardar figuras"""
|
|
69
68
|
self._save_fig = save_fig
|
|
70
69
|
self._fig_format = fig_format
|
|
71
70
|
self._fig_dpi = fig_dpi
|
|
72
71
|
self._figures_dir = figures_dir
|
|
73
72
|
|
|
74
73
|
def _save_figure(self, fig, filename: str, **kwargs):
|
|
75
|
-
"""
|
|
76
|
-
Guardar figura si save_fig está activado
|
|
77
|
-
"""
|
|
74
|
+
"""Guardar figura si save_fig está activado"""
|
|
78
75
|
if self._save_fig:
|
|
79
76
|
try:
|
|
80
77
|
os.makedirs(self._figures_dir, exist_ok=True)
|
|
@@ -93,10 +90,114 @@ class UtilsStats:
|
|
|
93
90
|
except Exception as e:
|
|
94
91
|
print(f"✗ Error guardando figura: {e}")
|
|
95
92
|
|
|
96
|
-
# ============= MÉTODOS DE
|
|
93
|
+
# ============= NUEVO: MÉTODOS DE CARGA DE DATOS =============
|
|
94
|
+
|
|
95
|
+
def load_data(self, path: Union[str, Path], **kwargs) -> pd.DataFrame:
|
|
96
|
+
"""
|
|
97
|
+
Carga datos desde archivo en múltiples formatos
|
|
98
|
+
|
|
99
|
+
Parameters:
|
|
100
|
+
-----------
|
|
101
|
+
path : str o Path
|
|
102
|
+
Ruta al archivo de datos
|
|
103
|
+
**kwargs : dict
|
|
104
|
+
Argumentos adicionales para la función de lectura de pandas
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
--------
|
|
108
|
+
pd.DataFrame
|
|
109
|
+
DataFrame con los datos cargados
|
|
110
|
+
|
|
111
|
+
Supported formats:
|
|
112
|
+
------------------
|
|
113
|
+
- CSV (.csv)
|
|
114
|
+
- Excel (.xlsx, .xls)
|
|
115
|
+
- Text/TSV (.txt, .tsv)
|
|
116
|
+
- JSON (.json)
|
|
117
|
+
- Parquet (.parquet)
|
|
118
|
+
- Feather (.feather)
|
|
119
|
+
|
|
120
|
+
Examples:
|
|
121
|
+
---------
|
|
122
|
+
>>> utils = UtilsStats()
|
|
123
|
+
>>> df = utils.load_data("datos.csv")
|
|
124
|
+
>>> df = utils.load_data("datos.xlsx", sheet_name="Hoja1")
|
|
125
|
+
>>> df = utils.load_data("datos.json")
|
|
126
|
+
"""
|
|
127
|
+
path = Path(path)
|
|
128
|
+
|
|
129
|
+
if not path.exists():
|
|
130
|
+
raise FileNotFoundError(f"El archivo no existe: {path}")
|
|
131
|
+
|
|
132
|
+
ext = path.suffix.lower()
|
|
133
|
+
|
|
134
|
+
try:
|
|
135
|
+
if ext == ".csv":
|
|
136
|
+
df = pd.read_csv(path, **kwargs)
|
|
137
|
+
|
|
138
|
+
elif ext in [".xlsx", ".xls"]:
|
|
139
|
+
df = pd.read_excel(path, **kwargs)
|
|
140
|
+
|
|
141
|
+
elif ext in [".txt", ".tsv"]:
|
|
142
|
+
df = pd.read_table(path, **kwargs)
|
|
143
|
+
|
|
144
|
+
elif ext == ".json":
|
|
145
|
+
df = pd.read_json(path, **kwargs)
|
|
146
|
+
|
|
147
|
+
elif ext == ".parquet":
|
|
148
|
+
df = pd.read_parquet(path, **kwargs)
|
|
149
|
+
|
|
150
|
+
elif ext == ".feather":
|
|
151
|
+
df = pd.read_feather(path, **kwargs)
|
|
152
|
+
|
|
153
|
+
else:
|
|
154
|
+
raise ValueError(f"Formato de archivo no soportado: {ext}")
|
|
155
|
+
|
|
156
|
+
print(f"✓ Datos cargados exitosamente desde: {path}")
|
|
157
|
+
print(f" Shape: {df.shape}")
|
|
158
|
+
print(f" Columnas: {list(df.columns)}")
|
|
159
|
+
|
|
160
|
+
return df
|
|
161
|
+
|
|
162
|
+
except Exception as e:
|
|
163
|
+
raise Exception(f"Error al cargar el archivo {path}: {str(e)}")
|
|
97
164
|
|
|
98
|
-
def
|
|
99
|
-
|
|
165
|
+
def _resolve_data(self, data: Union[pd.DataFrame, pd.Series, np.ndarray, list, str, Path],
|
|
166
|
+
column: Optional[str] = None) -> Tuple[Union[pd.DataFrame, pd.Series, np.ndarray], str]:
|
|
167
|
+
"""
|
|
168
|
+
Resuelve el input de datos: si es una ruta, carga el archivo; si no, usa los datos directamente
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
--------
|
|
172
|
+
Tuple[data, data_source]
|
|
173
|
+
- data: Los datos procesados
|
|
174
|
+
- data_source: String indicando la fuente ('file' o 'memory')
|
|
175
|
+
"""
|
|
176
|
+
# Si es string o Path, intentar cargar como archivo
|
|
177
|
+
if isinstance(data, (str, Path)):
|
|
178
|
+
path = Path(data)
|
|
179
|
+
if path.exists():
|
|
180
|
+
df = self.load_data(path)
|
|
181
|
+
if column is not None and column in df.columns:
|
|
182
|
+
return df[column], 'file'
|
|
183
|
+
return df, 'file'
|
|
184
|
+
else:
|
|
185
|
+
raise FileNotFoundError(f"El archivo no existe: {path}")
|
|
186
|
+
|
|
187
|
+
# Si ya son datos en memoria, devolverlos tal cual
|
|
188
|
+
return data, 'memory'
|
|
189
|
+
|
|
190
|
+
# ============= MÉTODOS DE ANÁLISIS ESTADÍSTICO (ACTUALIZADOS) =============
|
|
191
|
+
|
|
192
|
+
def validate_dataframe(self, data: Union[pd.DataFrame, np.ndarray, list, str, Path]) -> pd.DataFrame:
|
|
193
|
+
"""
|
|
194
|
+
Valida y convierte datos a DataFrame
|
|
195
|
+
|
|
196
|
+
Ahora acepta también rutas de archivos
|
|
197
|
+
"""
|
|
198
|
+
# Intentar resolver si es un archivo
|
|
199
|
+
data, source = self._resolve_data(data)
|
|
200
|
+
|
|
100
201
|
if isinstance(data, pd.DataFrame):
|
|
101
202
|
return data
|
|
102
203
|
elif isinstance(data, np.ndarray):
|
|
@@ -117,8 +218,36 @@ class UtilsStats:
|
|
|
117
218
|
return f"{num:.{decimals}e}"
|
|
118
219
|
return f"{num:.{decimals}f}"
|
|
119
220
|
|
|
120
|
-
def check_normality(self,
|
|
121
|
-
|
|
221
|
+
def check_normality(self,
|
|
222
|
+
data: Union[pd.Series, np.ndarray, pd.DataFrame, str, Path],
|
|
223
|
+
column: Optional[str] = None,
|
|
224
|
+
alpha: float = 0.05) -> dict:
|
|
225
|
+
"""
|
|
226
|
+
Verifica si los datos siguen distribución normal usando Shapiro-Wilk
|
|
227
|
+
|
|
228
|
+
Parameters:
|
|
229
|
+
-----------
|
|
230
|
+
data : Series, ndarray, DataFrame, str o Path
|
|
231
|
+
Datos a analizar o ruta al archivo
|
|
232
|
+
column : str, optional
|
|
233
|
+
Columna a analizar (si data es DataFrame o archivo)
|
|
234
|
+
alpha : float
|
|
235
|
+
Nivel de significancia
|
|
236
|
+
|
|
237
|
+
Examples:
|
|
238
|
+
---------
|
|
239
|
+
>>> utils.check_normality("datos.csv", column="edad")
|
|
240
|
+
>>> utils.check_normality(np.random.normal(0, 1, 100))
|
|
241
|
+
"""
|
|
242
|
+
# Resolver datos
|
|
243
|
+
data, source = self._resolve_data(data, column)
|
|
244
|
+
|
|
245
|
+
# Extraer array
|
|
246
|
+
if isinstance(data, pd.DataFrame):
|
|
247
|
+
if column is None:
|
|
248
|
+
raise ValueError("Debe especificar 'column' cuando data es DataFrame")
|
|
249
|
+
data = data[column]
|
|
250
|
+
|
|
122
251
|
if isinstance(data, pd.Series):
|
|
123
252
|
data = data.dropna().values
|
|
124
253
|
else:
|
|
@@ -135,16 +264,39 @@ class UtilsStats:
|
|
|
135
264
|
'interpretation': 'Normal' if shapiro_p > alpha else 'No Normal'
|
|
136
265
|
}
|
|
137
266
|
|
|
138
|
-
def calculate_confidence_intervals(self,
|
|
267
|
+
def calculate_confidence_intervals(self,
|
|
268
|
+
data: Union[pd.Series, np.ndarray, pd.DataFrame, str, Path],
|
|
269
|
+
column: Optional[str] = None,
|
|
139
270
|
confidence_level: float = 0.95,
|
|
140
271
|
method: str = 'parametric') -> dict:
|
|
141
272
|
"""
|
|
142
273
|
Calcula intervalos de confianza para la media
|
|
274
|
+
|
|
275
|
+
Parameters:
|
|
276
|
+
-----------
|
|
277
|
+
data : Series, ndarray, DataFrame, str o Path
|
|
278
|
+
Datos a analizar o ruta al archivo
|
|
279
|
+
column : str, optional
|
|
280
|
+
Columna a analizar
|
|
281
|
+
confidence_level : float
|
|
282
|
+
Nivel de confianza (default: 0.95)
|
|
283
|
+
method : str
|
|
284
|
+
'parametric' o 'bootstrap'
|
|
143
285
|
"""
|
|
286
|
+
# Resolver datos
|
|
287
|
+
data, source = self._resolve_data(data, column)
|
|
288
|
+
|
|
289
|
+
# Extraer array
|
|
290
|
+
if isinstance(data, pd.DataFrame):
|
|
291
|
+
if column is None:
|
|
292
|
+
raise ValueError("Debe especificar 'column' cuando data es DataFrame")
|
|
293
|
+
data = data[column]
|
|
294
|
+
|
|
144
295
|
if isinstance(data, pd.Series):
|
|
145
296
|
data_clean = data.dropna().values
|
|
146
297
|
else:
|
|
147
|
-
data_clean =
|
|
298
|
+
data_clean = np.array(data)
|
|
299
|
+
data_clean = data_clean[~np.isnan(data_clean)]
|
|
148
300
|
|
|
149
301
|
n = len(data_clean)
|
|
150
302
|
mean = np.mean(data_clean)
|
|
@@ -185,7 +337,9 @@ class UtilsStats:
|
|
|
185
337
|
'method': method
|
|
186
338
|
}
|
|
187
339
|
|
|
188
|
-
def detect_outliers(self,
|
|
340
|
+
def detect_outliers(self,
|
|
341
|
+
data: Union[pd.Series, np.ndarray, pd.DataFrame, str, Path],
|
|
342
|
+
column: Optional[str] = None,
|
|
189
343
|
method: Literal['iqr', 'zscore', 'isolation_forest'] = 'iqr',
|
|
190
344
|
**kwargs) -> np.ndarray:
|
|
191
345
|
"""
|
|
@@ -193,8 +347,10 @@ class UtilsStats:
|
|
|
193
347
|
|
|
194
348
|
Parameters:
|
|
195
349
|
-----------
|
|
196
|
-
data :
|
|
197
|
-
Datos a analizar
|
|
350
|
+
data : Series, ndarray, DataFrame, str o Path
|
|
351
|
+
Datos a analizar o ruta al archivo
|
|
352
|
+
column : str, optional
|
|
353
|
+
Columna a analizar
|
|
198
354
|
method : str
|
|
199
355
|
'iqr', 'zscore', o 'isolation_forest'
|
|
200
356
|
|
|
@@ -203,6 +359,15 @@ class UtilsStats:
|
|
|
203
359
|
np.ndarray
|
|
204
360
|
Array booleano indicando outliers
|
|
205
361
|
"""
|
|
362
|
+
# Resolver datos
|
|
363
|
+
data, source = self._resolve_data(data, column)
|
|
364
|
+
|
|
365
|
+
# Extraer array
|
|
366
|
+
if isinstance(data, pd.DataFrame):
|
|
367
|
+
if column is None:
|
|
368
|
+
raise ValueError("Debe especificar 'column' cuando data es DataFrame")
|
|
369
|
+
data = data[column]
|
|
370
|
+
|
|
206
371
|
if isinstance(data, pd.Series):
|
|
207
372
|
data = data.values
|
|
208
373
|
|
|
@@ -364,7 +529,8 @@ class UtilsStats:
|
|
|
364
529
|
|
|
365
530
|
return fig
|
|
366
531
|
|
|
367
|
-
def plot_distribution(self,
|
|
532
|
+
def plot_distribution(self,
|
|
533
|
+
data: Union[pd.DataFrame, pd.Series, np.ndarray, str, Path],
|
|
368
534
|
column: Optional[str] = None,
|
|
369
535
|
plot_type: Literal['hist', 'kde', 'box', 'violin', 'all'] = 'hist',
|
|
370
536
|
backend: Optional[Literal['matplotlib', 'seaborn', 'plotly']] = "seaborn",
|
|
@@ -378,10 +544,10 @@ class UtilsStats:
|
|
|
378
544
|
|
|
379
545
|
Parameters:
|
|
380
546
|
-----------
|
|
381
|
-
data : DataFrame, Series o
|
|
382
|
-
Datos a graficar
|
|
547
|
+
data : DataFrame, Series, ndarray, str o Path
|
|
548
|
+
Datos a graficar o ruta al archivo
|
|
383
549
|
column : str, optional
|
|
384
|
-
Columna a graficar (si data es DataFrame)
|
|
550
|
+
Columna a graficar (si data es DataFrame o archivo)
|
|
385
551
|
plot_type : str
|
|
386
552
|
Tipo de gráfico
|
|
387
553
|
backend : str, optional
|
|
@@ -394,11 +560,19 @@ class UtilsStats:
|
|
|
394
560
|
Si guardar la figura
|
|
395
561
|
filename : str, optional
|
|
396
562
|
Nombre del archivo
|
|
563
|
+
|
|
564
|
+
Examples:
|
|
565
|
+
---------
|
|
566
|
+
>>> utils.plot_distribution("datos.csv", column="edad")
|
|
567
|
+
>>> utils.plot_distribution(df, column="salario", plot_type="all")
|
|
397
568
|
"""
|
|
398
569
|
backend = backend or self._plot_backend
|
|
399
570
|
figsize = figsize or self._default_figsize
|
|
400
571
|
save_fig = save_fig if save_fig is not None else self._save_fig
|
|
401
572
|
|
|
573
|
+
# Resolver datos
|
|
574
|
+
data, source = self._resolve_data(data, column)
|
|
575
|
+
|
|
402
576
|
# Extraer datos
|
|
403
577
|
if isinstance(data, pd.DataFrame):
|
|
404
578
|
if column is None:
|
|
@@ -478,7 +652,8 @@ class UtilsStats:
|
|
|
478
652
|
|
|
479
653
|
return fig
|
|
480
654
|
|
|
481
|
-
def plot_correlation_matrix(self,
|
|
655
|
+
def plot_correlation_matrix(self,
|
|
656
|
+
data: Union[pd.DataFrame, str, Path],
|
|
482
657
|
method: str = 'pearson',
|
|
483
658
|
backend: Optional[Literal['seaborn', 'plotly']] = None,
|
|
484
659
|
figsize: Optional[Tuple[int, int]] = None,
|
|
@@ -490,8 +665,8 @@ class UtilsStats:
|
|
|
490
665
|
|
|
491
666
|
Parameters:
|
|
492
667
|
-----------
|
|
493
|
-
data : DataFrame
|
|
494
|
-
Datos para calcular correlación
|
|
668
|
+
data : DataFrame, str o Path
|
|
669
|
+
Datos para calcular correlación o ruta al archivo
|
|
495
670
|
method : str
|
|
496
671
|
'pearson', 'spearman' o 'kendall'
|
|
497
672
|
backend : str, optional
|
|
@@ -502,6 +677,12 @@ class UtilsStats:
|
|
|
502
677
|
save_fig = save_fig if save_fig is not None else self._save_fig
|
|
503
678
|
filename = filename or "matriz_correlacion"
|
|
504
679
|
|
|
680
|
+
# Resolver datos
|
|
681
|
+
data, source = self._resolve_data(data)
|
|
682
|
+
|
|
683
|
+
if not isinstance(data, pd.DataFrame):
|
|
684
|
+
raise ValueError("Se requiere un DataFrame para calcular matriz de correlación")
|
|
685
|
+
|
|
505
686
|
# Calcular matriz de correlación
|
|
506
687
|
corr_matrix = data.corr(method=method)
|
|
507
688
|
|
|
@@ -553,7 +734,8 @@ class UtilsStats:
|
|
|
553
734
|
|
|
554
735
|
return fig
|
|
555
736
|
|
|
556
|
-
def plot_scatter_matrix(self,
|
|
737
|
+
def plot_scatter_matrix(self,
|
|
738
|
+
data: Union[pd.DataFrame, str, Path],
|
|
557
739
|
columns: Optional[List[str]] = None,
|
|
558
740
|
backend: Optional[Literal['seaborn', 'plotly', 'pandas']] = None,
|
|
559
741
|
figsize: Optional[Tuple[int, int]] = None,
|
|
@@ -562,12 +744,23 @@ class UtilsStats:
|
|
|
562
744
|
**kwargs):
|
|
563
745
|
"""
|
|
564
746
|
Matriz de gráficos de dispersión (pairplot)
|
|
747
|
+
|
|
748
|
+
Parameters:
|
|
749
|
+
-----------
|
|
750
|
+
data : DataFrame, str o Path
|
|
751
|
+
Datos o ruta al archivo
|
|
565
752
|
"""
|
|
566
753
|
backend = backend or self._plot_backend
|
|
567
754
|
figsize = figsize or self._default_figsize
|
|
568
755
|
save_fig = save_fig if save_fig is not None else self._save_fig
|
|
569
756
|
filename = filename or "scatter_matrix"
|
|
570
757
|
|
|
758
|
+
# Resolver datos
|
|
759
|
+
data, source = self._resolve_data(data)
|
|
760
|
+
|
|
761
|
+
if not isinstance(data, pd.DataFrame):
|
|
762
|
+
raise ValueError("Se requiere un DataFrame para matriz de dispersión")
|
|
763
|
+
|
|
571
764
|
if columns:
|
|
572
765
|
data = data[columns]
|
|
573
766
|
|
|
@@ -603,7 +796,7 @@ class UtilsStats:
|
|
|
603
796
|
# ============= GRÁFICOS CON INTERVALOS DE CONFIANZA =============
|
|
604
797
|
|
|
605
798
|
def plot_distribution_with_ci(self,
|
|
606
|
-
data: Union[pd.DataFrame, pd.Series, np.ndarray],
|
|
799
|
+
data: Union[pd.DataFrame, pd.Series, np.ndarray, str, Path],
|
|
607
800
|
column: Optional[str] = None,
|
|
608
801
|
confidence_level: float = 0.95,
|
|
609
802
|
ci_method: str = 'parametric',
|
|
@@ -612,7 +805,14 @@ class UtilsStats:
|
|
|
612
805
|
save_fig: Optional[bool] = None,
|
|
613
806
|
filename: Optional[str] = None,
|
|
614
807
|
**kwargs) -> plt.Figure:
|
|
615
|
-
|
|
808
|
+
"""
|
|
809
|
+
Distribución con intervalos de confianza
|
|
810
|
+
|
|
811
|
+
Ahora acepta rutas de archivos
|
|
812
|
+
"""
|
|
813
|
+
# Resolver datos
|
|
814
|
+
data, source = self._resolve_data(data, column)
|
|
815
|
+
|
|
616
816
|
# ======= PREPARACIÓN =======
|
|
617
817
|
if isinstance(data, pd.DataFrame):
|
|
618
818
|
if column is None:
|
|
@@ -630,7 +830,7 @@ class UtilsStats:
|
|
|
630
830
|
filename = filename or f"distribucion_ci_{data_name.lower().replace(' ', '_')}"
|
|
631
831
|
|
|
632
832
|
# Estadísticas
|
|
633
|
-
ci_result = self.calculate_confidence_intervals(data_array, confidence_level, ci_method)
|
|
833
|
+
ci_result = self.calculate_confidence_intervals(data_array, confidence_level=confidence_level, method=ci_method)
|
|
634
834
|
normality_result = self.check_normality(data_array)
|
|
635
835
|
|
|
636
836
|
# KDE
|
|
@@ -739,7 +939,7 @@ class UtilsStats:
|
|
|
739
939
|
data_array = data_array[~np.isnan(data_array)]
|
|
740
940
|
|
|
741
941
|
# Calcular estadísticas
|
|
742
|
-
ci_result = self.calculate_confidence_intervals(data_array, confidence_level)
|
|
942
|
+
ci_result = self.calculate_confidence_intervals(data_array, confidence_level=confidence_level)
|
|
743
943
|
|
|
744
944
|
# Gráfica izquierda: Distribución básica
|
|
745
945
|
ax1.hist(data_array, bins=30, alpha=0.7, color=colors[idx],
|
|
@@ -779,11 +979,17 @@ class UtilsStats:
|
|
|
779
979
|
|
|
780
980
|
# ============= MÉTODOS UTILITARIOS ADICIONALES =============
|
|
781
981
|
|
|
782
|
-
def get_descriptive_stats(self,
|
|
982
|
+
def get_descriptive_stats(self,
|
|
983
|
+
data: Union[pd.DataFrame, pd.Series, np.ndarray, str, Path],
|
|
783
984
|
column: Optional[str] = None) -> dict:
|
|
784
985
|
"""
|
|
785
986
|
Obtiene estadísticas descriptivas completas
|
|
987
|
+
|
|
988
|
+
Ahora acepta rutas de archivos
|
|
786
989
|
"""
|
|
990
|
+
# Resolver datos
|
|
991
|
+
data, source = self._resolve_data(data, column)
|
|
992
|
+
|
|
787
993
|
if isinstance(data, pd.DataFrame):
|
|
788
994
|
if column is None:
|
|
789
995
|
raise ValueError("Debe especificar 'column' cuando data es DataFrame")
|
|
@@ -810,371 +1016,4 @@ class UtilsStats:
|
|
|
810
1016
|
'skewness': stats.skew(data_clean),
|
|
811
1017
|
'kurtosis': stats.kurtosis(data_clean),
|
|
812
1018
|
'range': np.max(data_clean) - np.min(data_clean)
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
def help(self):
|
|
816
|
-
"""
|
|
817
|
-
Muestra ayuda completa de la clase DescriptiveStats
|
|
818
|
-
"""
|
|
819
|
-
help_text = """
|
|
820
|
-
╔════════════════════════════════════════════════════════════════════════════╗
|
|
821
|
-
║ 📊 CLASE UtilsStats - AYUDA COMPLETA ║
|
|
822
|
-
╚════════════════════════════════════════════════════════════════════════════╝
|
|
823
|
-
|
|
824
|
-
📝 DESCRIPCIÓN:
|
|
825
|
-
Clase para análisis estadístico descriptivo univariado y multivariado.
|
|
826
|
-
Proporciona herramientas para análisis exploratorio de datos, medidas de
|
|
827
|
-
tendencia central, dispersión, forma de distribución y regresión lineal.
|
|
828
|
-
|
|
829
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
830
|
-
|
|
831
|
-
📋 MÉTODOS PRINCIPALES:
|
|
832
|
-
|
|
833
|
-
┌────────────────────────────────────────────────────────────────────────────┐
|
|
834
|
-
│ 1. 📊 ANÁLISIS ESTADÍSTICO │
|
|
835
|
-
└────────────────────────────────────────────────────────────────────────────┘
|
|
836
|
-
|
|
837
|
-
• .check_normality(data, alpha=0.05)
|
|
838
|
-
Verifica normalidad usando test Shapiro-Wilk
|
|
839
|
-
Retorna: dict con estadístico, p-value e interpretación
|
|
840
|
-
|
|
841
|
-
• .calculate_confidence_intervals(data, confidence_level=0.95,
|
|
842
|
-
method='parametric')
|
|
843
|
-
Calcula intervalos de confianza para la media
|
|
844
|
-
Métodos: 'parametric' o 'bootstrap'
|
|
845
|
-
|
|
846
|
-
• .detect_outliers(data, method='iqr', **kwargs)
|
|
847
|
-
Detecta valores atípicos
|
|
848
|
-
Métodos: 'iqr', 'zscore', 'isolation_forest'
|
|
849
|
-
|
|
850
|
-
• .calculate_effect_size(group1, group2, method='cohen')
|
|
851
|
-
Calcula tamaño del efecto entre grupos
|
|
852
|
-
Métodos: 'cohen' (Cohen's d) o 'hedges' (Hedges' g)
|
|
853
|
-
|
|
854
|
-
• .get_descriptive_stats(data, column=None)
|
|
855
|
-
Estadísticas descriptivas completas en un dict
|
|
856
|
-
|
|
857
|
-
┌────────────────────────────────────────────────────────────────────────────┐
|
|
858
|
-
│ 2. 🎨 VISUALIZACIÓN DE DISTRIBUCIONES │
|
|
859
|
-
└────────────────────────────────────────────────────────────────────────────┘
|
|
860
|
-
|
|
861
|
-
• .plot_distribution(data, column=None, plot_type='hist',
|
|
862
|
-
backend='seaborn', bins=30, figsize=None,
|
|
863
|
-
save_fig=None, filename=None)
|
|
864
|
-
|
|
865
|
-
Grafica distribución de una variable
|
|
866
|
-
|
|
867
|
-
plot_type: 'hist', 'kde', 'box', 'violin', 'all'
|
|
868
|
-
backend: 'matplotlib', 'seaborn', 'plotly'
|
|
869
|
-
|
|
870
|
-
• .plot_distribution_with_ci(data, column=None, confidence_level=0.95,
|
|
871
|
-
ci_method='parametric', bins=30, figsize=None,
|
|
872
|
-
save_fig=None, filename=None)
|
|
873
|
-
|
|
874
|
-
Distribución con intervalos de confianza visualizados
|
|
875
|
-
|
|
876
|
-
• .plot_multiple_distributions_with_ci(data_dict, confidence_level=0.95)
|
|
877
|
-
|
|
878
|
-
Compara múltiples distribuciones con sus IC
|
|
879
|
-
|
|
880
|
-
┌────────────────────────────────────────────────────────────────────────────┐
|
|
881
|
-
│ 3. 🎨 VISUALIZACIÓN MULTIVARIADA │
|
|
882
|
-
└────────────────────────────────────────────────────────────────────────────┘
|
|
883
|
-
|
|
884
|
-
• .plot_correlation_matrix(data, method='pearson', backend='seaborn',
|
|
885
|
-
figsize=None, save_fig=None)
|
|
886
|
-
|
|
887
|
-
Matriz de correlación con heatmap
|
|
888
|
-
Métodos: 'pearson', 'spearman', 'kendall'
|
|
889
|
-
|
|
890
|
-
• .plot_scatter_matrix(data, columns=None, backend='seaborn',
|
|
891
|
-
figsize=None, save_fig=None)
|
|
892
|
-
|
|
893
|
-
Matriz de gráficos de dispersión (pairplot)
|
|
894
|
-
Backends: 'seaborn', 'plotly', 'pandas'
|
|
895
|
-
|
|
896
|
-
┌────────────────────────────────────────────────────────────────────────────┐
|
|
897
|
-
│ 4. ⚙️ CONFIGURACIÓN │
|
|
898
|
-
└────────────────────────────────────────────────────────────────────────────┘
|
|
899
|
-
|
|
900
|
-
• .set_plot_backend(backend)
|
|
901
|
-
Establece backend por defecto: 'matplotlib', 'seaborn', 'plotly'
|
|
902
|
-
|
|
903
|
-
• .set_default_figsize(figsize)
|
|
904
|
-
Establece tamaño de figura por defecto: (ancho, alto)
|
|
905
|
-
|
|
906
|
-
• .set_save_fig_options(save_fig=False, fig_format='png',
|
|
907
|
-
fig_dpi=300, figures_dir='figures')
|
|
908
|
-
|
|
909
|
-
Configura guardado automático de figuras
|
|
910
|
-
|
|
911
|
-
┌────────────────────────────────────────────────────────────────────────────┐
|
|
912
|
-
│ 5. 🛠️ UTILIDADES │
|
|
913
|
-
└────────────────────────────────────────────────────────────────────────────┘
|
|
914
|
-
|
|
915
|
-
• .validate_dataframe(data)
|
|
916
|
-
Valida y convierte datos a DataFrame
|
|
917
|
-
|
|
918
|
-
• .format_number(num, decimals=6, scientific=False)
|
|
919
|
-
Formatea números con precisión específica
|
|
920
|
-
|
|
921
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
922
|
-
|
|
923
|
-
💡 EJEMPLOS DE USO:
|
|
924
|
-
|
|
925
|
-
┌─ Ejemplo 1: Configuración Inicial ──────────────────────────────────────┐
|
|
926
|
-
│ from utils import UtilsStats │
|
|
927
|
-
│ import pandas as pd │
|
|
928
|
-
│ import numpy as np │
|
|
929
|
-
│ │
|
|
930
|
-
│ # Inicializar │
|
|
931
|
-
│ utils = UtilsStats() │
|
|
932
|
-
│ │
|
|
933
|
-
│ # Configurar visualización │
|
|
934
|
-
│ utils.set_plot_backend('seaborn') │
|
|
935
|
-
│ utils.set_default_figsize((12, 6)) │
|
|
936
|
-
│ │
|
|
937
|
-
│ # Configurar guardado automático │
|
|
938
|
-
│ utils.set_save_fig_options( │
|
|
939
|
-
│ save_fig=True, │
|
|
940
|
-
│ fig_format='png', │
|
|
941
|
-
│ fig_dpi=300, │
|
|
942
|
-
│ figures_dir='mis_graficos' │
|
|
943
|
-
│ ) │
|
|
944
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
945
|
-
|
|
946
|
-
┌─ Ejemplo 2: Análisis de Normalidad ─────────────────────────────────────┐
|
|
947
|
-
│ # Generar datos │
|
|
948
|
-
│ datos_normales = np.random.normal(0, 1, 1000) │
|
|
949
|
-
│ datos_no_normales = np.random.exponential(2, 1000) │
|
|
950
|
-
│ │
|
|
951
|
-
│ # Test de normalidad │
|
|
952
|
-
│ resultado1 = utils.check_normality(datos_normales) │
|
|
953
|
-
│ print(f"Normales: {resultado1['interpretation']}") │
|
|
954
|
-
│ print(f"p-value: {resultado1['shapiro_pvalue']:.4f}") │
|
|
955
|
-
│ │
|
|
956
|
-
│ resultado2 = utils.check_normality(datos_no_normales) │
|
|
957
|
-
│ print(f"No normales: {resultado2['interpretation']}") │
|
|
958
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
959
|
-
|
|
960
|
-
┌─ Ejemplo 3: Intervalos de Confianza ────────────────────────────────────┐
|
|
961
|
-
│ # Método paramétrico │
|
|
962
|
-
│ ci_param = utils.calculate_confidence_intervals( │
|
|
963
|
-
│ datos_normales, │
|
|
964
|
-
│ confidence_level=0.95, │
|
|
965
|
-
│ method='parametric' │
|
|
966
|
-
│ ) │
|
|
967
|
-
│ │
|
|
968
|
-
│ print(f"Media: {ci_param['mean']:.3f}") │
|
|
969
|
-
│ print(f"IC 95%: [{ci_param['ci_lower']:.3f}, " │
|
|
970
|
-
│ f"{ci_param['ci_upper']:.3f}]") │
|
|
971
|
-
│ │
|
|
972
|
-
│ # Método bootstrap (para datos no normales) │
|
|
973
|
-
│ ci_boot = utils.calculate_confidence_intervals( │
|
|
974
|
-
│ datos_no_normales, │
|
|
975
|
-
│ confidence_level=0.95, │
|
|
976
|
-
│ method='bootstrap' │
|
|
977
|
-
│ ) │
|
|
978
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
979
|
-
|
|
980
|
-
┌─ Ejemplo 4: Detección de Outliers ──────────────────────────────────────┐
|
|
981
|
-
│ # Método IQR (rango intercuartílico) │
|
|
982
|
-
│ datos = np.random.normal(100, 15, 1000) │
|
|
983
|
-
│ datos = np.append(datos, [200, 210, -50]) # Agregar outliers │
|
|
984
|
-
│ │
|
|
985
|
-
│ outliers_iqr = utils.detect_outliers(datos, method='iqr') │
|
|
986
|
-
│ print(f"Outliers IQR: {outliers_iqr.sum()}") │
|
|
987
|
-
│ │
|
|
988
|
-
│ # Método Z-score │
|
|
989
|
-
│ outliers_z = utils.detect_outliers( │
|
|
990
|
-
│ datos, │
|
|
991
|
-
│ method='zscore', │
|
|
992
|
-
│ threshold=3 │
|
|
993
|
-
│ ) │
|
|
994
|
-
│ print(f"Outliers Z-score: {outliers_z.sum()}") │
|
|
995
|
-
│ │
|
|
996
|
-
│ # Isolation Forest (machine learning) │
|
|
997
|
-
│ outliers_if = utils.detect_outliers( │
|
|
998
|
-
│ datos, │
|
|
999
|
-
│ method='isolation_forest', │
|
|
1000
|
-
│ contamination=0.05 │
|
|
1001
|
-
│ ) │
|
|
1002
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
1003
|
-
|
|
1004
|
-
┌─ Ejemplo 5: Tamaño del Efecto ──────────────────────────────────────────┐
|
|
1005
|
-
│ # Comparar dos grupos │
|
|
1006
|
-
│ grupo_control = np.random.normal(100, 15, 100) │
|
|
1007
|
-
│ grupo_tratamiento = np.random.normal(110, 15, 100) │
|
|
1008
|
-
│ │
|
|
1009
|
-
│ efecto = utils.calculate_effect_size( │
|
|
1010
|
-
│ grupo_control, │
|
|
1011
|
-
│ grupo_tratamiento, │
|
|
1012
|
-
│ method='cohen' │
|
|
1013
|
-
│ ) │
|
|
1014
|
-
│ │
|
|
1015
|
-
│ print(f"Cohen's d: {efecto['effect_size']:.3f}") │
|
|
1016
|
-
│ print(f"Interpretación: {efecto['interpretation']}") │
|
|
1017
|
-
│ print(f"Diferencia de medias: {efecto['mean_diff']:.2f}") │
|
|
1018
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
1019
|
-
|
|
1020
|
-
┌─ Ejemplo 6: Gráficos de Distribución ───────────────────────────────────┐
|
|
1021
|
-
│ df = pd.DataFrame({ │
|
|
1022
|
-
│ 'edad': np.random.normal(35, 10, 500), │
|
|
1023
|
-
│ 'salario': np.random.lognormal(10.5, 0.5, 500) │
|
|
1024
|
-
│ }) │
|
|
1025
|
-
│ │
|
|
1026
|
-
│ # Histograma simple │
|
|
1027
|
-
│ fig1 = utils.plot_distribution( │
|
|
1028
|
-
│ df, │
|
|
1029
|
-
│ column='edad', │
|
|
1030
|
-
│ plot_type='hist', │
|
|
1031
|
-
│ bins=30 │
|
|
1032
|
-
│ ) │
|
|
1033
|
-
│ │
|
|
1034
|
-
│ # Panel completo (histograma, box, violin, Q-Q) │
|
|
1035
|
-
│ fig2 = utils.plot_distribution( │
|
|
1036
|
-
│ df, │
|
|
1037
|
-
│ column='salario', │
|
|
1038
|
-
│ plot_type='all', │
|
|
1039
|
-
│ backend='seaborn' │
|
|
1040
|
-
│ ) │
|
|
1041
|
-
│ │
|
|
1042
|
-
│ # Con Plotly (interactivo) │
|
|
1043
|
-
│ fig3 = utils.plot_distribution( │
|
|
1044
|
-
│ df, │
|
|
1045
|
-
│ column='edad', │
|
|
1046
|
-
│ plot_type='violin', │
|
|
1047
|
-
│ backend='plotly' │
|
|
1048
|
-
│ ) │
|
|
1049
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
1050
|
-
|
|
1051
|
-
┌─ Ejemplo 7: Distribución con Intervalos de Confianza ───────────────────┐
|
|
1052
|
-
│ # Visualizar distribución con IC │
|
|
1053
|
-
│ fig = utils.plot_distribution_with_ci( │
|
|
1054
|
-
│ df, │
|
|
1055
|
-
│ column='edad', │
|
|
1056
|
-
│ confidence_level=0.95, │
|
|
1057
|
-
│ ci_method='parametric', │
|
|
1058
|
-
│ bins=30, │
|
|
1059
|
-
│ save_fig=True, │
|
|
1060
|
-
│ filename='edad_con_ic' │
|
|
1061
|
-
│ ) │
|
|
1062
|
-
│ │
|
|
1063
|
-
│ # Comparar múltiples distribuciones │
|
|
1064
|
-
│ data_dict = { │
|
|
1065
|
-
│ 'Grupo A': df['edad'][:200], │
|
|
1066
|
-
│ 'Grupo B': df['edad'][200:400], │
|
|
1067
|
-
│ 'Grupo C': df['edad'][400:] │
|
|
1068
|
-
│ } │
|
|
1069
|
-
│ │
|
|
1070
|
-
│ fig = utils.plot_multiple_distributions_with_ci( │
|
|
1071
|
-
│ data_dict, │
|
|
1072
|
-
│ confidence_level=0.95 │
|
|
1073
|
-
│ ) │
|
|
1074
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
1075
|
-
|
|
1076
|
-
┌─ Ejemplo 8: Matriz de Correlación ──────────────────────────────────────┐
|
|
1077
|
-
│ # Crear datos correlacionados │
|
|
1078
|
-
│ df = pd.DataFrame({ │
|
|
1079
|
-
│ 'A': np.random.normal(0, 1, 100), │
|
|
1080
|
-
│ 'B': np.random.normal(0, 1, 100), │
|
|
1081
|
-
│ 'C': np.random.normal(0, 1, 100) │
|
|
1082
|
-
│ }) │
|
|
1083
|
-
│ df['D'] = df['A'] * 0.8 + np.random.normal(0, 0.2, 100) │
|
|
1084
|
-
│ │
|
|
1085
|
-
│ # Matriz de correlación con seaborn │
|
|
1086
|
-
│ fig = utils.plot_correlation_matrix( │
|
|
1087
|
-
│ df, │
|
|
1088
|
-
│ method='pearson', │
|
|
1089
|
-
│ backend='seaborn', │
|
|
1090
|
-
│ figsize=(10, 8) │
|
|
1091
|
-
│ ) │
|
|
1092
|
-
│ │
|
|
1093
|
-
│ # Con Plotly (interactiva) │
|
|
1094
|
-
│ fig = utils.plot_correlation_matrix( │
|
|
1095
|
-
│ df, │
|
|
1096
|
-
│ method='spearman', │
|
|
1097
|
-
│ backend='plotly' │
|
|
1098
|
-
│ ) │
|
|
1099
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
1100
|
-
|
|
1101
|
-
┌─ Ejemplo 9: Matriz de Dispersión ───────────────────────────────────────┐
|
|
1102
|
-
│ # Pairplot completo │
|
|
1103
|
-
│ fig = utils.plot_scatter_matrix( │
|
|
1104
|
-
│ df, │
|
|
1105
|
-
│ columns=['A', 'B', 'C', 'D'], │
|
|
1106
|
-
│ backend='seaborn' │
|
|
1107
|
-
│ ) │
|
|
1108
|
-
│ │
|
|
1109
|
-
│ # Con Plotly │
|
|
1110
|
-
│ fig = utils.plot_scatter_matrix( │
|
|
1111
|
-
│ df, │
|
|
1112
|
-
│ backend='plotly' │
|
|
1113
|
-
│ ) │
|
|
1114
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
1115
|
-
|
|
1116
|
-
┌─ Ejemplo 10: Estadísticas Descriptivas Completas ───────────────────────┐
|
|
1117
|
-
│ # Obtener todas las estadísticas │
|
|
1118
|
-
│ stats = utils.get_descriptive_stats(df, column='edad') │
|
|
1119
|
-
│ │
|
|
1120
|
-
│ print(f"Media: {stats['mean']:.2f}") │
|
|
1121
|
-
│ print(f"Mediana: {stats['median']:.2f}") │
|
|
1122
|
-
│ print(f"Desv. Est.: {stats['std']:.2f}") │
|
|
1123
|
-
│ print(f"IQR: {stats['iqr']:.2f}") │
|
|
1124
|
-
│ print(f"Asimetría: {stats['skewness']:.3f}") │
|
|
1125
|
-
│ print(f"Curtosis: {stats['kurtosis']:.3f}") │
|
|
1126
|
-
└──────────────────────────────────────────────────────────────────────────┘
|
|
1127
|
-
|
|
1128
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1129
|
-
|
|
1130
|
-
🎯 CARACTERÍSTICAS CLAVE:
|
|
1131
|
-
|
|
1132
|
-
✓ Múltiples backends de visualización (matplotlib, seaborn, plotly)
|
|
1133
|
-
✓ Guardado automático de figuras en alta resolución
|
|
1134
|
-
✓ Análisis estadísticos robustos
|
|
1135
|
-
✓ Detección de outliers con 3 métodos
|
|
1136
|
-
✓ Intervalos de confianza paramétricos y bootstrap
|
|
1137
|
-
✓ Visualizaciones profesionales listas para publicación
|
|
1138
|
-
✓ Manejo automático de valores faltantes
|
|
1139
|
-
✓ Integración perfecta con pandas y numpy
|
|
1140
|
-
✓ Gráficos interactivos con Plotly
|
|
1141
|
-
|
|
1142
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1143
|
-
|
|
1144
|
-
📊 BACKENDS DE VISUALIZACIÓN:
|
|
1145
|
-
|
|
1146
|
-
🔹 Matplotlib:
|
|
1147
|
-
• Rápido y ligero
|
|
1148
|
-
• Ideal para gráficos simples
|
|
1149
|
-
• Mejor para exportar a archivos
|
|
1150
|
-
|
|
1151
|
-
🔹 Seaborn:
|
|
1152
|
-
• Gráficos estadísticos elegantes
|
|
1153
|
-
• Temas predefinidos atractivos
|
|
1154
|
-
• Mejor para análisis exploratorio
|
|
1155
|
-
|
|
1156
|
-
🔹 Plotly:
|
|
1157
|
-
• Gráficos interactivos
|
|
1158
|
-
• Zoom, pan, hover tooltips
|
|
1159
|
-
• Ideal para presentaciones y dashboards
|
|
1160
|
-
|
|
1161
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1162
|
-
|
|
1163
|
-
💡 CONSEJOS Y MEJORES PRÁCTICAS:
|
|
1164
|
-
|
|
1165
|
-
1. Siempre verificar normalidad antes de usar métodos paramétricos
|
|
1166
|
-
2. Usar bootstrap para IC cuando los datos no son normales
|
|
1167
|
-
3. Detectar outliers antes de calcular estadísticas
|
|
1168
|
-
4. Guardar figuras en alta resolución (300 DPI) para publicaciones
|
|
1169
|
-
5. Usar Plotly para presentaciones interactivas
|
|
1170
|
-
6. Usar seaborn para análisis exploratorio rápido
|
|
1171
|
-
|
|
1172
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
1173
|
-
|
|
1174
|
-
📚 DOCUMENTACIÓN ADICIONAL:
|
|
1175
|
-
Para más información sobre métodos específicos, use:
|
|
1176
|
-
help(UtilsStats.nombre_metodo)
|
|
1177
|
-
|
|
1178
|
-
╚════════════════════════════════════════════════════════════════════════════╝
|
|
1179
|
-
"""
|
|
1180
|
-
print(help_text)
|
|
1019
|
+
}
|