hossam 0.3.20__py3-none-any.whl → 0.4.1__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.
hossam/hs_stats.py CHANGED
@@ -35,6 +35,8 @@ from statsmodels.stats.diagnostic import linear_reset, het_breuschpagan, het_whi
35
35
  from statsmodels.stats.outliers_influence import variance_inflation_factor
36
36
  from statsmodels.stats.multitest import multipletests
37
37
  from statsmodels.stats.stattools import durbin_watson
38
+ from statsmodels.regression.linear_model import RegressionResultsWrapper
39
+ from statsmodels.discrete.discrete_model import BinaryResults
38
40
 
39
41
  from pingouin import anova, pairwise_tukey, welch_anova, pairwise_gameshowell
40
42
 
@@ -58,21 +60,22 @@ def missing_values(data: DataFrame, *fields: str):
58
60
  - missing_rate (float): 전체 행에서 결측치의 비율(%)
59
61
 
60
62
  Examples:
61
- 전체 컬럼에 대한 결측치 확인:
62
-
63
- >>> from hossam import missing_values
64
- >>> import pandas as pd
65
- >>> df = pd.DataFrame({'x': [1, 2, None, 4], 'y': [10, None, None, 40]})
66
- >>> result = missing_values(df)
67
- >>> print(result)
68
-
69
- 특정 컬럼만 분석:
70
-
71
- >>> result = missing_values(df, 'x', 'y')
72
- >>> print(result)
63
+ ```python
64
+ from hossam import *
65
+ from pandas import DataFrame
66
+
67
+ # 전체 컬럼에 대한 결측치 확인:
68
+ df = DataFrame({'x': [1, 2, None, 4], 'y': [10, None, None, 40]})
69
+ result = hs_stats.missing_values(df)
70
+ print(result)
71
+
72
+ # 특정 컬럼만 분석:
73
+ result = hs_stats.missing_values(df, 'x', 'y')
74
+ print(result)
75
+ ```
73
76
  """
74
77
  if not fields:
75
- fields = data.columns
78
+ fields = tuple(data.columns)
76
79
 
77
80
  result = []
78
81
  for f in fields:
@@ -121,18 +124,20 @@ def outlier_table(data: DataFrame, *fields: str):
121
124
  - outlier_rate (float): 이상치 비율(%)
122
125
 
123
126
  Examples:
124
- 전체 숫자형 컬럼에 대한 이상치 경계 확인:
127
+ ```python
128
+ from hossam import *
129
+ from pandas import DataFrame
125
130
 
126
- >>> from hossam import outlier_table
127
- >>> import pandas as pd
128
- >>> df = pd.DataFrame({'x': [1, 2, 3, 100], 'y': [10, 20, 30, 40]})
129
- >>> result = outlier_table(df)
130
- >>> print(result)
131
+ df = DataFrame({'x': [1, 2, 3, 100], 'y': [10, 20, 30, 40]})
131
132
 
132
- 특정 컬럼만 분석:
133
+ # 전체 숫자형 컬럼에 대한 이상치 경계 확인:
134
+ result = hs_stats.outlier_table(df)
135
+ print(result)
133
136
 
134
- >>> result = outlier_table(df, 'x', 'y')
135
- >>> print(result[['Q1', 'Q3', 'UP', 'DOWN']])
137
+ # 특정 컬럼만 분석:
138
+ result = hs_stats.outlier_table(df, 'x', 'y')
139
+ print(result[['q1', 'q3', 'up', 'down']])
140
+ ```
136
141
 
137
142
  Notes:
138
143
  - DOWN 미만이거나 UP 초과인 값은 이상치(outlier)로 간주됩니다.
@@ -140,7 +145,7 @@ def outlier_table(data: DataFrame, *fields: str):
140
145
  - Tukey의 1.5 * IQR 규칙을 사용합니다 (상자그림의 표준 방법).
141
146
  """
142
147
  if not fields:
143
- fields = data.columns
148
+ fields = tuple(data.columns)
144
149
 
145
150
  result = []
146
151
  for f in fields:
@@ -195,80 +200,160 @@ def outlier_table(data: DataFrame, *fields: str):
195
200
 
196
201
 
197
202
  # ===================================================================
198
- # 범주형 변수 분석 (Categorical Variable Analysis)
203
+ # 확장된 기술통계량 (Extended Descriptive Statistics)
199
204
  # ===================================================================
200
- def category_table(data: DataFrame, *fields: str):
201
- """데이터프레임의 명목형(범주형) 변수에 대한 기술통계를 반환한다.
205
+ def describe(data: DataFrame, *fields: str, columns: list | None = None):
206
+ """데이터프레임의 연속형 변수의 단위 현실성을 평가하기 위해 확장된 기술통계량을 반환한다.
202
207
 
203
- 명목형 컬럼의 범주값별 빈도수와 비율을 계산하여 데이터프레임으로 반환한다.
208
+ 연속형(숫자형) 컬럼의 기술통계량(describe)을 구하고, 이에 사분위수 범위(IQR),
209
+ 이상치 경계값(UP, DOWN), 왜도(skew), 이상치 개수 및 비율, 분포 특성, 로그변환 필요성을
210
+ 추가하여 반환한다.
204
211
 
205
212
  Args:
206
213
  data (DataFrame): 분석 대상 데이터프레임.
207
- *fields (str): 분석할 컬럼명 목록. 지정하지 않으면 모든 명목형 컬럼을 처리.
214
+ *fields (str): 분석할 컬럼명 목록. 지정하지 않으면 모든 숫자형 컬럼을 처리.
215
+ columns (list, optional): 반환할 통계량 컬럼 목록. None이면 모든 통계량 반환.
208
216
 
209
217
  Returns:
210
- DataFrame: 각 컬럼별 범주값의 빈도와 비율 정보를 포함한 데이터프레임.
211
- 인덱스는 FIELD(컬럼명)와 CATEGORY(범주값)이며, 다음 컬럼을 포함:
218
+ DataFrame: 각 필드별 확장된 기술통계량을 포함한 데이터프레임.
219
+ 행은 다음과 같은 통계량을 포함:
212
220
 
213
- - count (int): 해당 범주값의 빈도수
214
- - rate (float): 전체 행에서 해당 범주값의 비율(%)
221
+ - count (float): 비결측치의
222
+ - mean (float): 평균값
223
+ - std (float): 표준편차
224
+ - min (float): 최소값
225
+ - 25% (float): 제1사분위수 (Q1)
226
+ - 50% (float): 제2사분위수 (중앙값)
227
+ - 75% (float): 제3사분위수 (Q3)
228
+ - max (float): 최대값
229
+ - iqr (float): 사분위 범위 (Q3 - Q1)
230
+ - up (float): 이상치 상한 경계값 (Q3 + 1.5 * IQR)
231
+ - down (float): 이상치 하한 경계값 (Q1 - 1.5 * IQR)
232
+ - skew (float): 왜도
233
+ - outlier_count (int): 이상치 개수
234
+ - outlier_rate (float): 이상치 비율(%)
235
+ - dist (str): 분포 특성 ("극단 우측 꼬리", "거의 대칭" 등)
236
+ - log_need (str): 로그변환 필요성 ("높음", "중간", "낮음")
215
237
 
216
238
  Examples:
217
- 전체 명목형 컬럼에 대한 기술통계:
218
-
219
- >>> from hossam import category_table
220
- >>> import pandas as pd
221
- >>> df = pd.DataFrame({
222
- ... 'color': ['red', 'blue', 'red', 'green', 'blue', 'red'],
223
- ... 'size': ['S', 'M', 'L', 'M', 'S', 'M'],
224
- ... 'price': [100, 200, 150, 300, 120, 180]
225
- ... })
226
- >>> result = category_table(df)
227
- >>> print(result)
239
+ ```python
240
+ from hossam import *
241
+ from pandas import DataFrame
242
+
243
+ df = DataFrame({
244
+ 'x': [1, 2, 3, 4, 5, 100],
245
+ 'y': [10, 20, 30, 40, 50, 60],
246
+ 'z': ['a', 'b', 'c', 'd', 'e', 'f']
247
+ })
228
248
 
229
- 특정 컬럼만 분석:
249
+ # 전체 숫자형 컬럼에 대한 확장된 기술통계:
250
+ result = hs_stats.describe(df)
251
+ print(result)
230
252
 
231
- >>> result = category_table(df, 'color', 'size')
232
- >>> print(result)
253
+ # 특정 컬럼만 분석:
254
+ result = hs_stats.describe(df, 'x', 'y')
255
+ print(result)
256
+ ```
233
257
 
234
258
  Notes:
235
- - 숫자형 컬럼은 자동으로 제외됩니다.
236
- - 범주값별로 별도의 행으로 반환됩니다.
237
- - NaN 값도 하나의 범주로 포함됩니다.
259
+ - 숫자형이 아닌 컬럼은 자동으로 제외됩니다.
260
+ - 결과는 필드(컬럼)가 행으로, 통계량이 열로 구성됩니다.
261
+ - Tukey의 1.5 * IQR 규칙을 사용하여 이상치를 판정합니다.
262
+ - 분포 특성은 왜도 값으로 판정합니다.
263
+ - 로그변환 필요성은 왜도의 절댓값 크기로 판정합니다.
238
264
  """
239
265
  if not fields:
240
- # 명목형(범주형) 컬럼 선택: object, category, bool 타입
241
- fields = data.select_dtypes(include=['object', 'category', 'bool']).columns
266
+ fields = tuple(data.select_dtypes(include=['int', 'int32', 'int64', 'float', 'float32', 'float64']).columns)
242
267
 
243
- result = []
268
+ # 기술통계량 구하기
269
+ desc = data[list(fields)].describe().T
270
+ # 각 컬럼별 결측치 수(null_count) 추가
271
+ null_counts = data[list(fields)].isnull().sum()
272
+ desc.insert(1, 'null_count', null_counts)
273
+
274
+ # 추가 통계량 계산
275
+ additional_stats = []
244
276
  for f in fields:
245
- # 숫자형 컬럼은 건너뜀
246
- if data[f].dtypes in [
247
- "int",
248
- "int32",
249
- "int64",
250
- "float",
251
- "float32",
252
- "float64",
277
+ # 숫자 타입이 아니라면 건너뜀
278
+ if data[f].dtype not in [
279
+ 'int',
280
+ 'int32',
281
+ 'int64',
282
+ 'float',
283
+ 'float32',
284
+ 'float64',
285
+ 'int64',
286
+ 'float64',
287
+ 'float32'
253
288
  ]:
254
289
  continue
255
290
 
256
- # 각 범주값의 빈도수 계산 (NaN 포함)
257
- value_counts = data[f].value_counts(dropna=False)
291
+ # 사분위수
292
+ q1 = data[f].quantile(q=0.25)
293
+ q3 = data[f].quantile(q=0.75)
258
294
 
259
- for category, count in value_counts.items():
260
- rate = (count / len(data)) * 100
295
+ # 이상치 경계 (Tukey's fences)
296
+ iqr = q3 - q1
297
+ down = q1 - 1.5 * iqr
298
+ up = q3 + 1.5 * iqr
261
299
 
262
- iq = {
263
- "field": f,
264
- "category": category,
265
- "count": count,
266
- "rate": rate
267
- }
300
+ # 왜도
301
+ skew = data[f].skew()
268
302
 
269
- result.append(iq)
303
+ # 이상치 개수 및 비율
304
+ outlier_count = ((data[f] < down) | (data[f] > up)).sum()
305
+ outlier_rate = (outlier_count / len(data)) * 100
270
306
 
271
- return DataFrame(result).set_index(["field", "category"])
307
+ # 분포 특성 판정 (왜도 기준)
308
+ abs_skew = abs(skew)
309
+ if abs_skew < 0.5:
310
+ dist = "거의 대칭"
311
+ elif abs_skew < 1.0:
312
+ if skew > 0:
313
+ dist = "약한 우측 꼬리"
314
+ else:
315
+ dist = "약한 좌측 꼬리"
316
+ elif abs_skew < 2.0:
317
+ if skew > 0:
318
+ dist = "중간 우측 꼬리"
319
+ else:
320
+ dist = "중간 좌측 꼬리"
321
+ else:
322
+ if skew > 0:
323
+ dist = "극단 우측 꼬리"
324
+ else:
325
+ dist = "극단 좌측 꼬리"
326
+
327
+ # 로그변환 필요성 판정
328
+ if abs_skew < 0.5:
329
+ log_need = "낮음"
330
+ elif abs_skew < 1.0:
331
+ log_need = "중간"
332
+ else:
333
+ log_need = "높음"
334
+
335
+ additional_stats.append({
336
+ 'field': f,
337
+ 'iqr': iqr,
338
+ 'up': up,
339
+ 'down': down,
340
+ 'outlier_count': outlier_count,
341
+ 'outlier_rate': outlier_rate,
342
+ 'skew': skew,
343
+ 'dist': dist,
344
+ 'log_need': log_need
345
+ })
346
+
347
+ additional_df = DataFrame(additional_stats).set_index('field')
348
+
349
+ # 결과 병합
350
+ result = concat([desc, additional_df], axis=1)
351
+
352
+ # columns 파라미터가 지정된 경우 해당 컬럼만 필터링
353
+ if columns is not None:
354
+ result = result[columns]
355
+
356
+ return result
272
357
 
273
358
 
274
359
  # ===================================================================
@@ -284,7 +369,8 @@ def category_describe(data: DataFrame, *fields: str):
284
369
  *fields (str): 분석할 컬럼명 목록. 지정하지 않으면 모든 명목형 컬럼을 처리.
285
370
 
286
371
  Returns:
287
- DataFrame: 각 컬럼별 최다/최소 범주 정보를 포함한 데이터프레임.
372
+ tuple[DataFrame, DataFrame]: 각 컬럼별 최다/최소 범주 정보를 포함한 데이터프레임과
373
+ 각 범주별 빈도/비율 정보를 포함한 데이터프레임을 튜플로 반환.
288
374
  다음 컬럼을 포함:
289
375
 
290
376
  - 변수 (str): 컬럼명
@@ -294,22 +380,22 @@ def category_describe(data: DataFrame, *fields: str):
294
380
  - 최소_비율(%) (float): 최소 범주의 비율
295
381
 
296
382
  Examples:
297
- 전체 명목형 컬럼에 대한 분포 편향 요약:
298
-
299
- >>> from hossam import category_describe
300
- >>> import pandas as pd
301
- >>> df = pd.DataFrame({
302
- ... 'cut': ['Ideal', 'Premium', 'Good', 'Ideal', 'Premium'],
303
- ... 'color': ['E', 'F', 'G', 'E', 'F'],
304
- ... 'price': [100, 200, 150, 300, 120]
305
- ... })
306
- >>> result = category_describe(df)
307
- >>> print(result)
383
+ ```python
384
+ from hossam import *
385
+ from pandas import DataFrame
386
+
387
+ df = DataFrame({
388
+ 'cut': ['Ideal', 'Premium', 'Good', 'Ideal', 'Premium'],
389
+ 'color': ['E', 'F', 'G', 'E', 'F'],
390
+ 'price': [100, 200, 150, 300, 120]
391
+ })
308
392
 
309
- 특정 컬럼만 분석:
393
+ # 전체 명목형 컬럼에 대한 요약:
394
+ result, summary = hs_stats.category_describe(df)
310
395
 
311
- >>> result = category_describe(df, 'cut', 'color')
312
- >>> print(result)
396
+ # 특정 컬럼만 분석:
397
+ result, summary = hs_stats.category_describe(df, 'cut', 'color')
398
+ ```
313
399
 
314
400
  Notes:
315
401
  - 숫자형 컬럼은 자동으로 제외됩니다.
@@ -320,6 +406,7 @@ def category_describe(data: DataFrame, *fields: str):
320
406
  fields = data.select_dtypes(include=['object', 'category', 'bool']).columns
321
407
 
322
408
  result = []
409
+ summary = []
323
410
  for f in fields:
324
411
  # 숫자형 컬럼은 건너뜀
325
412
  if data[f].dtypes in [
@@ -335,40 +422,35 @@ def category_describe(data: DataFrame, *fields: str):
335
422
  # 각 범주값의 빈도수 계산 (NaN 포함)
336
423
  value_counts = data[f].value_counts(dropna=False)
337
424
 
425
+ # 범주별 빈도/비율 정보 추가 (category_table 기능)
426
+ for category, count in value_counts.items():
427
+ rate = (count / len(data)) * 100
428
+ result.append({
429
+ "변수": f,
430
+ "범주": category,
431
+ "빈도": count,
432
+ "비율(%)": round(rate, 2)
433
+ })
434
+
338
435
  if len(value_counts) == 0:
339
436
  continue
340
437
 
341
- # 최다 범주 ( 번째)
438
+ # 최다/최소 범주 정보 추가 (category_describe 기능)
342
439
  max_category = value_counts.index[0]
343
440
  max_count = value_counts.iloc[0]
344
441
  max_rate = (max_count / len(data)) * 100
345
-
346
- # 최소 범주 (마지막)
347
442
  min_category = value_counts.index[-1]
348
443
  min_count = value_counts.iloc[-1]
349
444
  min_rate = (min_count / len(data)) * 100
350
-
351
- iq = {
445
+ summary.append({
352
446
  "변수": f,
353
447
  "최다_범주": max_category,
354
448
  "최다_비율(%)": round(max_rate, 2),
355
449
  "최소_범주": min_category,
356
450
  "최소_비율(%)": round(min_rate, 2)
357
- }
358
-
359
- result.append(iq)
360
-
361
- return DataFrame(result)
451
+ })
362
452
 
363
- # -------------------------------------------------------------------
364
- # Backward-compatibility alias for categorical summary
365
- # 기존 함수명(category_summary)을 계속 지원합니다.
366
- def category_summary(data: DataFrame, *fields: str):
367
- """Deprecated alias for category_describe.
368
-
369
- 기존 코드 호환을 위해 유지됩니다. 내부적으로 category_describe를 호출합니다.
370
- """
371
- return category_describe(data, *fields)
453
+ return DataFrame(result), DataFrame(summary).set_index("변수")
372
454
 
373
455
  # ===================================================================
374
456
  # 정규성 검정 (Normal Test)
@@ -403,19 +485,25 @@ def normal_test(data: DataFrame, columns: list | str | None = None, method: str
403
485
  ValueError: 메서드가 "n" 또는 "s"가 아닐 경우.
404
486
 
405
487
  Examples:
406
- >>> from hossam.analysis import normal_test
407
- >>> import pandas as pd
408
- >>> import numpy as np
409
- >>> df = pd.DataFrame({
410
- ... 'x': np.random.normal(0, 1, 100),
411
- ... 'y': np.random.exponential(2, 100)
412
- ... })
413
- >>> # 모든 수치형 컬럼 검정
414
- >>> result = normal_test(df, method='n')
415
- >>> # 특정 컬럼만 검정 (리스트)
416
- >>> result = normal_test(df, columns=['x'], method='n')
417
- >>> # 특정 컬럼만 검정 (문자열)
418
- >>> result = normal_test(df, columns='x, y', method='n')
488
+ ```python
489
+ from hossam import *
490
+ from pandas import DataFrame
491
+ import numpy as np
492
+
493
+ df = DataFrame({
494
+ 'x': np.random.normal(0, 1, 100),
495
+ 'y': np.random.exponential(2, 100)
496
+ })
497
+
498
+ # 모든 수치형 컬럼 검정
499
+ result = hs_stats.normal_test(df, method='n')
500
+
501
+ # 특정 컬럼만 검정 (리스트)
502
+ result = hs_stats.normal_test(df, columns=['x'], method='n')
503
+
504
+ # 특정 컬럼만 검정 (문자열)
505
+ result = hs_stats.normal_test(df, columns='x, y', method='n')
506
+ ```
419
507
  """
420
508
  if method not in ["n", "s"]:
421
509
  raise ValueError(f"method는 'n' 또는 's'여야 합니다. 입력값: {method}")
@@ -515,22 +603,29 @@ def equal_var_test(data: DataFrame, columns: list | str | None = None, normal_di
515
603
  ValueError: 수치형 컬럼이 2개 미만일 경우 (검정에 최소 2개 필요).
516
604
 
517
605
  Examples:
518
- >>> from hossam.analysis import equal_var_test
519
- >>> import pandas as pd
520
- >>> import numpy as np
521
- >>> df = pd.DataFrame({
522
- ... 'x': np.random.normal(0, 1, 100),
523
- ... 'y': np.random.normal(0, 1, 100),
524
- ... 'z': np.random.normal(0, 2, 100)
525
- ... })
526
- >>> # 모든 수치형 컬럼 자동 판별
527
- >>> result = equal_var_test(df)
528
- >>> # 특정 컬럼만 검정 (리스트)
529
- >>> result = equal_var_test(df, columns=['x', 'y'])
530
- >>> # 특정 컬럼만 검정 (문자열)
531
- >>> result = equal_var_test(df, columns='x, y')
532
- >>> # 명시적 지정
533
- >>> result = equal_var_test(df, normal_dist=True)
606
+ ```python
607
+ from hossam import *
608
+ from pandas import DataFrame
609
+ import numpy as np
610
+
611
+ df = DataFrame({
612
+ 'x': np.random.normal(0, 1, 100),
613
+ 'y': np.random.normal(0, 1, 100),
614
+ 'z': np.random.normal(0, 2, 100)
615
+ })
616
+
617
+ # 모든 수치형 컬럼 자동 판별
618
+ result = hs_stats.equal_var_test(df)
619
+
620
+ # 특정 컬럼만 검정 (리스트)
621
+ result = hs_stats.equal_var_test(df, columns=['x', 'y'])
622
+
623
+ # 특정 컬럼만 검정 (문자열)
624
+ result = hs_stats.equal_var_test(df, columns='x, y')
625
+
626
+ # 명시적 지정
627
+ result = hs_stats.equal_var_test(df, normal_dist=True)
628
+ ```
534
629
  """
535
630
  # columns가 문자열인 경우 리스트로 변환
536
631
  if isinstance(columns, str):
@@ -627,15 +722,19 @@ def ttest_1samp(data, mean_value: float = 0.0) -> DataFrame:
627
722
  - interpretation (str): 검정 결과 해석 문자열
628
723
 
629
724
  Examples:
630
- >>> from hossam.hs_stats import ttest_1samp
631
- >>> import pandas as pd
632
- >>> import numpy as np
633
- >>> # 리스트 데이터로 검정
634
- >>> data = [5.1, 4.9, 5.3, 5.0, 4.8]
635
- >>> result = ttest_1samp(data, mean_value=5.0)
636
- >>> # Series 데이터로 검정
637
- >>> s = pd.Series(np.random.normal(5, 1, 100))
638
- >>> result = ttest_1samp(s, mean_value=5)
725
+ ```python
726
+ from hossam import *
727
+ from pandas import Series
728
+ import numpy as np
729
+
730
+ # 리스트 데이터로 검정
731
+ data = [5.1, 4.9, 5.3, 5.0, 4.8]
732
+ result = hs_stats.ttest_1samp(data, mean_value=5.0)
733
+
734
+ # Series 데이터로 검정
735
+ s = Series(np.random.normal(5, 1, 100))
736
+ result = hs_stats.ttest_1samp(s, mean_value=5)
737
+ ```
639
738
  """
640
739
  # 데이터를 Series로 변환하고 이름 감지
641
740
  if isinstance(data, Series):
@@ -724,17 +823,21 @@ def ttest_ind(x, y, equal_var: bool | None = None) -> DataFrame:
724
823
  - interpretation (str): 검정 결과 해석
725
824
 
726
825
  Examples:
727
- >>> from hossam.hs_stats import ttest_ind
728
- >>> import pandas as pd
729
- >>> import numpy as np
730
- >>> # 리스트로 검정
731
- >>> group1 = [5.1, 4.9, 5.3, 5.0, 4.8]
732
- >>> group2 = [5.5, 5.7, 5.4, 5.6, 5.8]
733
- >>> result = ttest_ind(group1, group2)
734
- >>> # Series로 검정
735
- >>> s1 = pd.Series(np.random.normal(5, 1, 100))
736
- >>> s2 = pd.Series(np.random.normal(5.5, 1, 100))
737
- >>> result = ttest_ind(s1, s2, equal_var=False)
826
+ ```python
827
+ from hossam import *
828
+ from pandas import Series, DataFrame
829
+ import numpy as np
830
+
831
+ # 리스트로 검정
832
+ group1 = [5.1, 4.9, 5.3, 5.0, 4.8]
833
+ group2 = [5.5, 5.7, 5.4, 5.6, 5.8]
834
+ result = hs_stats.ttest_ind(group1, group2)
835
+
836
+ # Series로 검정
837
+ s1 = Series(np.random.normal(5, 1, 100))
838
+ s2 = Series(np.random.normal(5.5, 1, 100))
839
+ result = hs_stats.ttest_ind(s1, s2, equal_var=False)
840
+ ```
738
841
  """
739
842
  # 데이터를 Series로 변환
740
843
  if isinstance(x, Series):
@@ -835,17 +938,21 @@ def ttest_rel(x, y, parametric: bool | None = None) -> DataFrame:
835
938
  - interpretation (str): 검정 결과 해석
836
939
 
837
940
  Examples:
838
- >>> from hossam.hs_stats import ttest_rel
839
- >>> import pandas as pd
840
- >>> import numpy as np
841
- >>> # 리스트로 검정
842
- >>> before = [5.1, 4.9, 5.3, 5.0, 4.8]
843
- >>> after = [5.5, 5.2, 5.7, 5.3, 5.1]
844
- >>> result = ttest_rel(before, after)
845
- >>> # Series로 검정
846
- >>> s1 = pd.Series(np.random.normal(5, 1, 100))
847
- >>> s2 = pd.Series(np.random.normal(5.3, 1, 100))
848
- >>> result = ttest_rel(s1, s2, parametric=False)
941
+ ```python
942
+ from hossam import *
943
+ from pandas import Series
944
+ import numpy as np
945
+
946
+ # 리스트로 검정
947
+ before = [5.1, 4.9, 5.3, 5.0, 4.8]
948
+ after = [5.5, 5.2, 5.7, 5.3, 5.1]
949
+ result = hs_stats.ttest_rel(before, after)
950
+
951
+ # Series로 검정
952
+ s1 = Series(np.random.normal(5, 1, 100))
953
+ s2 = Series(np.random.normal(5.3, 1, 100))
954
+ result = hs_stats.ttest_rel(s1, s2, parametric=False)
955
+ ```
849
956
  """
850
957
  # 데이터를 Series로 변환
851
958
  if isinstance(x, Series):
@@ -958,11 +1065,11 @@ def vif_filter(
958
1065
  DataFrame: VIF가 threshold 이하인 변수만 남은 데이터프레임 (원본 컬럼 순서 유지)
959
1066
 
960
1067
  Examples:
961
- 기본 사용 예:
962
-
963
- >>> from hossam.analysis import vif_filter
964
- >>> filtered = hs_vif_filter(df, yname="target", ignore=["id"], threshold=10.0)
965
- >>> filtered.head()
1068
+ ```python
1069
+ # 기본 사용 예
1070
+ from hossam import *
1071
+ filtered = hs_stats.vif_filter(df, yname="target", ignore=["id"], threshold=10.0)
1072
+ ```
966
1073
  """
967
1074
 
968
1075
  df = data.copy()
@@ -1038,15 +1145,6 @@ def vif_filter(
1038
1145
 
1039
1146
  return result
1040
1147
 
1041
- # -------------------------------------------------------------------
1042
- # Backward-compatibility alias for describe (typo support)
1043
- # 오타(discribe)로 사용된 경우를 지원하여 혼란을 줄입니다.
1044
- def discribe(data: DataFrame, *fields: str, columns: list = None):
1045
- """Deprecated alias for describe.
1046
-
1047
- 내부적으로 describe를 호출합니다.
1048
- """
1049
- return describe(data, *fields, columns=columns)
1050
1148
 
1051
1149
 
1052
1150
  # ===================================================================
@@ -1065,12 +1163,12 @@ def trend(x: any, y: any, degree: int = 1, value_count: int = 100) -> Tuple[np.n
1065
1163
  tuple: (v_trend, t_trend)
1066
1164
 
1067
1165
  Examples:
1068
- 2차 다항 회귀 추세선:
1069
-
1070
- >>> from hossam.analysis import trend
1071
- >>> vx, vy = hs_trend(x, y, degree=2, value_count=200)
1072
- >>> len(vx), len(vy)
1073
- (200, 200)
1166
+ ```python
1167
+ # 2차 다항 회귀 추세선
1168
+ from hossam import *
1169
+ vx, vy = hs_stats.trend(x, y, degree=2, value_count=200)
1170
+ print(len(vx), len(vy)) # 200, 200
1171
+ ```
1074
1172
  """
1075
1173
  # [ a, b, c ] ==> ax^2 + bx + c
1076
1174
  x_arr = np.asarray(x)
@@ -1116,14 +1214,18 @@ def ols_report(fit, data, full=False, alpha=0.05):
1116
1214
  - 회귀계수 표 (`rdf`, DataFrame)
1117
1215
 
1118
1216
  Examples:
1119
- >>> import statsmodels.api as sm
1120
- >>> y = data['target']
1121
- >>> X = sm.add_constant(data[['x1', 'x2']])
1122
- >>> fit = sm.OLS(y, X).fit()
1123
- >>> # 전체 리포트
1124
- >>> pdf, rdf, result_report, model_report, variable_reports, eq = ols_report(fit, data)
1125
- >>> # 간단한 버전 (회귀계수 테이블만)
1126
- >>> rdf = ols_report(fit, data, full=False)
1217
+ ```python
1218
+ from hossam import *
1219
+
1220
+ df = hs_util.load_data("some_data.csv")
1221
+ fit = hs_stats.ols(df, yname="target")
1222
+
1223
+ # 전체 리포트
1224
+ pdf, rdf, result_report, model_report, variable_reports, eq = hs_stats.ols_report(fit, data, full=True)
1225
+
1226
+ # 간단한 버전 (성능지표, 회귀계수 테이블만)
1227
+ pdf, rdf = hs_stats.ols_report(fit, data)
1228
+ ```
1127
1229
  """
1128
1230
 
1129
1231
  # summary2() 결과에서 실제 회귀계수 DataFrame 추출
@@ -1270,7 +1372,7 @@ def ols_report(fit, data, full=False, alpha=0.05):
1270
1372
  if full:
1271
1373
  return pdf, rdf, result_report, model_report, variable_reports, equation_text
1272
1374
  else:
1273
- return pdf
1375
+ return pdf, rdf
1274
1376
 
1275
1377
 
1276
1378
  # ===================================================================
@@ -1309,23 +1411,26 @@ def ols(df: DataFrame, yname: str, report=False):
1309
1411
  - equation_text: 회귀식 문자열 (str)
1310
1412
 
1311
1413
  Examples:
1312
- >>> from hossam.analysis import linear
1313
- >>> import pandas as pd
1314
- >>> import numpy as np
1315
- >>> df = pd.DataFrame({
1316
- ... 'target': np.random.normal(100, 10, 100),
1317
- ... 'x1': np.random.normal(0, 1, 100),
1318
- ... 'x2': np.random.normal(0, 1, 100)
1319
- ... })
1320
- >>> # 적합 결과만 반환
1321
- >>> fit = hs_ols(df, 'target')
1322
- >>> print(fit.summary())
1323
-
1324
- >>> # 요약 리포트 반환
1325
- >>> fit, result, features = hs_ols(df, 'target', report=1)
1326
-
1327
- >>> # 리포트 반환
1328
- >>> fit, pdf, rdf, result_report, model_report, var_reports, eq = hs_ols(df, 'target', report=2)
1414
+ ```python
1415
+ from hossam import *
1416
+ from pandas import DataFrame
1417
+ import numpy as np
1418
+
1419
+ df = DataFrame({
1420
+ 'target': np.random.normal(100, 10, 100),
1421
+ 'x1': np.random.normal(0, 1, 100),
1422
+ 'x2': np.random.normal(0, 1, 100)
1423
+ })
1424
+
1425
+ # 적합 결과만 반환
1426
+ fit = hs_stats.ols(df, 'target')
1427
+
1428
+ # 요약 리포트 반환
1429
+ fit, pdf, rdf = hs_stats.ols(df, 'target', report=1)
1430
+
1431
+ # 풀 리포트 반환
1432
+ fit, pdf, rdf, result_report, model_report, var_reports, eq = hs_stats.ols(df, 'target', report=2)
1433
+ ```
1329
1434
  """
1330
1435
  x = df.drop(yname, axis=1)
1331
1436
  y = df[yname]
@@ -1340,7 +1445,7 @@ def ols(df: DataFrame, yname: str, report=False):
1340
1445
  return linear_fit
1341
1446
  elif report == 1 or report == 'summary':
1342
1447
  # 요약 리포트 (full=False)
1343
- pdf, rdf, result_report, model_report, variable_reports, equation_text = ols_report(linear_fit, df, full=True, alpha=0.05)
1448
+ pdf, rdf = ols_report(linear_fit, df, full=False, alpha=0.05)
1344
1449
  return linear_fit, pdf, rdf
1345
1450
  elif report == 2 or report == 'full' or report is True:
1346
1451
  # 풀 리포트 (full=True)
@@ -1378,14 +1483,26 @@ def logit_report(fit, data, threshold=0.5, full=False, alpha=0.05):
1378
1483
  - 회귀계수 표 (`rdf`, DataFrame)
1379
1484
 
1380
1485
  Examples:
1381
- >>> import statsmodels.api as sm
1382
- >>> y = data['target']
1383
- >>> X = sm.add_constant(data[['x1', 'x2']])
1384
- >>> fit = sm.Logit(y, X).fit(disp=0)
1385
- >>> # 전체 리포트
1386
- >>> cdf, rdf, result_report, model_report, variable_reports, cm = hs_logit_report(fit, data)
1387
- >>> # 간단한 버전 (주요 테이블만)
1388
- >>> cdf, rdf = hs_logit_report(fit, data, full=False)
1486
+ ```python
1487
+ from hossam import *
1488
+ from pandas import DataFrame
1489
+ import numpy as np
1490
+
1491
+ df = DataFrame({
1492
+ 'target': np.random.binomial(1, 0.5, 100),
1493
+ 'x1': np.random.normal(0, 1, 100),
1494
+ 'x2': np.random.normal(0, 1, 100)
1495
+ })
1496
+
1497
+ # 로지스틱 회귀 적합
1498
+ fit = hs_stats.logit(df, yname="target")
1499
+
1500
+ # 전체 리포트
1501
+ cdf, rdf, result_report, model_report, variable_reports, cm = hs_stats.logit_report(fit, df, full=True)
1502
+
1503
+ # 간단한 버전 (주요 테이블만)
1504
+ cdf, rdf = hs_stats.logit_report(fit, df)
1505
+ ```
1389
1506
  """
1390
1507
 
1391
1508
  # -----------------------------
@@ -1567,23 +1684,26 @@ def logit(df: DataFrame, yname: str, report=False):
1567
1684
  - variable_reports: 변수별 보고 문장 리스트 (list[str])
1568
1685
 
1569
1686
  Examples:
1570
- >>> from hossam.analysis import logit
1571
- >>> import pandas as pd
1572
- >>> import numpy as np
1573
- >>> df = pd.DataFrame({
1574
- ... 'target': np.random.binomial(1, 0.5, 100),
1575
- ... 'x1': np.random.normal(0, 1, 100),
1576
- ... 'x2': np.random.normal(0, 1, 100)
1577
- ... })
1578
- >>> # 적합 결과만 반환
1579
- >>> fit = hs_logit(df, 'target')
1580
- >>> print(fit.summary())
1581
-
1582
- >>> # 요약 리포트 반환
1583
- >>> fit, rdf, result_report, var_reports = hs_logit(df, 'target', report=1)
1584
-
1585
- >>> # 리포트 반환
1586
- >>> fit, cdf, rdf, result_report, model_report, var_reports = hs_logit(df, 'target', report=2)
1687
+ ```python
1688
+ from hossam import *
1689
+ from pandas import DataFrame
1690
+ import numpy as np
1691
+
1692
+ df = DataFrame({
1693
+ 'target': np.random.binomial(1, 0.5, 100),
1694
+ 'x1': np.random.normal(0, 1, 100),
1695
+ 'x2': np.random.normal(0, 1, 100)
1696
+ })
1697
+
1698
+ # 적합 결과만 반환
1699
+ fit = hs_stats.logit(df, 'target')
1700
+
1701
+ # 요약 리포트 반환
1702
+ fit, rdf, result_report, var_reports = hs_stats.logit(df, 'target', report='summary')
1703
+
1704
+ # 풀 리포트 반환
1705
+ fit, cdf, rdf, result_report, model_report, var_reports = hs_stats.logit(df, 'target', report='full')
1706
+ ```
1587
1707
  """
1588
1708
  x = df.drop(yname, axis=1)
1589
1709
  y = df[yname]
@@ -1636,12 +1756,11 @@ def ols_linearity_test(fit, power: int = 2, alpha: float = 0.05) -> DataFrame:
1636
1756
  - 해석: 선형성 판정 (문자열)
1637
1757
 
1638
1758
  Examples:
1639
- >>> import statsmodels.api as sm
1640
- >>> X = sm.add_constant(df[['x1', 'x2']])
1641
- >>> y = df['y']
1642
- >>> fit = sm.OLS(y, X).fit()
1643
- >>> result = linearity_test(fit)
1644
- >>> print(result)
1759
+ ```python
1760
+ from hossam import *
1761
+ fit = hs_stats.logit(df, 'target')
1762
+ result = hs_stats.ols_linearity_test(fit)
1763
+ ```
1645
1764
 
1646
1765
  Notes:
1647
1766
  - p-value > alpha: 선형성 가정을 만족 (귀무가설 채택)
@@ -1736,12 +1855,11 @@ def ols_normality_test(fit, alpha: float = 0.05) -> DataFrame:
1736
1855
  - 해석: 정규성 판정 (문자열)
1737
1856
 
1738
1857
  Examples:
1739
- >>> import statsmodels.api as sm
1740
- >>> X = sm.add_constant(df[['x1', 'x2']])
1741
- >>> y = df['y']
1742
- >>> fit = sm.OLS(y, X).fit()
1743
- >>> result = normality_test(fit)
1744
- >>> print(result)
1858
+ ```python
1859
+ from hossam import *
1860
+ fit = hs_stats.logit(df, 'target')
1861
+ result = hs_stats.ols_normality_test(fit)
1862
+ ```
1745
1863
 
1746
1864
  Notes:
1747
1865
  - Shapiro-Wilk: 샘플 크기가 작을 때 (< 5000) 강력한 검정
@@ -1831,12 +1949,11 @@ def ols_variance_test(fit, alpha: float = 0.05) -> DataFrame:
1831
1949
  - 해석: 등분산성 판정 (문자열)
1832
1950
 
1833
1951
  Examples:
1834
- >>> import statsmodels.api as sm
1835
- >>> X = sm.add_constant(df[['x1', 'x2']])
1836
- >>> y = df['y']
1837
- >>> fit = sm.OLS(y, X).fit()
1838
- >>> result = homoscedasticity_test(fit)
1839
- >>> print(result)
1952
+ ```python
1953
+ from hossam import *
1954
+ fit = hs_stats.logit(df, 'target')
1955
+ result = hs_stats.ols_variance_test(fit)
1956
+ ```
1840
1957
 
1841
1958
  Notes:
1842
1959
  - Breusch-Pagan: 잔차 제곱과 독립변수의 선형관계 검정
@@ -1922,22 +2039,11 @@ def ols_independence_test(fit, alpha: float = 0.05) -> DataFrame:
1922
2039
  - 해석: 검정 결과 해석
1923
2040
 
1924
2041
  Examples:
1925
- >>> import pandas as pd
1926
- >>> import statsmodels.api as sm
1927
- >>> from hossam.hs_stats import ols_independence_test
1928
- >>>
1929
- >>> # 예제 데이터
1930
- >>> df = pd.DataFrame({
1931
- ... 'x': range(100),
1932
- ... 'y': [i + np.random.randn() for i in range(100)]
1933
- ... })
1934
- >>> X = sm.add_constant(df['x'])
1935
- >>> model = sm.OLS(df['y'], X)
1936
- >>> fit = model.fit()
1937
- >>>
1938
- >>> # 독립성 검정
1939
- >>> result = ols_independence_test(fit)
1940
- >>> print(result)
2042
+ ```python
2043
+ from hossam import *
2044
+ fit = hs_stats.logit(df, 'target')
2045
+ result = hs_stats.ols_independence_test(fit)
2046
+ ```
1941
2047
 
1942
2048
  Notes:
1943
2049
  - Durbin-Watson 통계량 해석:
@@ -1975,92 +2081,6 @@ def ols_independence_test(fit, alpha: float = 0.05) -> DataFrame:
1975
2081
 
1976
2082
  return result_df
1977
2083
 
1978
-
1979
- # ===================================================================
1980
- # 상관계수 히트맵
1981
- # ===================================================================
1982
- def corr(data: DataFrame, *fields: str) -> tuple[DataFrame, DataFrame]:
1983
- """데이터프레임의 연속형 변수들에 대한 상관계수 히트맵과 상관계수 종류를 반환한다.
1984
-
1985
- 정규성 검정을 통해 피어슨 또는 스피어만 상관계수를 자동 선택하여 계산한다.
1986
- 선택된 상관계수 종류를 별도의 데이터프레임으로 교차표(행렬) 형태로 반환한다.
1987
-
1988
- Args:
1989
- data (DataFrame): 분석 대상 데이터프레임.
1990
- *fields (str): 분석할 컬럼명 목록. 지정하지 않으면 모든 숫자형 컬럼을 사용.
1991
-
1992
- Returns:
1993
- tuple[DataFrame, DataFrame]: 상관계수 행렬과 사용된 상관계수 종류 정보를 포함한 두 개의 데이터프레임.
1994
-
1995
- - 첫 번째 DataFrame: 상관계수 행렬 (각 변수 쌍의 상관계수 값)
1996
- - 두 번째 DataFrame: 상관계수 종류 (교차표 형태)
1997
- - 행과 열: 변수명
1998
- - 셀의 값: 각 변수 쌍에 사용된 상관계수 종류 ('Pearson' 또는 'Spearman')
1999
-
2000
- Examples:
2001
- >>> import pandas as pd
2002
- >>> import numpy as np
2003
- >>> df = pd.DataFrame({
2004
- ... 'x1': np.random.normal(0, 1, 100),
2005
- ... 'x2': np.random.normal(0, 1, 100),
2006
- ... 'x3': np.random.normal(0, 1, 100),
2007
- ... })
2008
- >>> # 모든 연속형 변수에 대해 상관계수 계산
2009
- >>> corr_matrix, corr_types = corr(df)
2010
- >>> print(corr_matrix)
2011
- >>> x1 x2 x3
2012
- >>> x1 1.00 0.12 -0.05
2013
- >>> x2 0.12 1.00 0.08
2014
- >>> x3 -0.05 0.08 1.00
2015
- >>> print(corr_types)
2016
- >>> x1 x2 x3
2017
- >>> x1 Pearson Pearson Pearson
2018
- >>> x2 Pearson Pearson Pearson
2019
- >>> x3 Pearson Pearson Pearson
2020
-
2021
- >>> # 특정 컬럼만 분석
2022
- >>> corr_matrix, corr_info = corr(df, 'x1', 'x2')
2023
- >>> print(corr_matrix)
2024
- """
2025
- # 분석 대상 컬럼 결정
2026
- if fields:
2027
- # 지정된 컬럼만 사용
2028
- numeric_cols = list(fields)
2029
- else:
2030
- # 모든 숫자형 컬럼 선택
2031
- numeric_cols = data.select_dtypes(include=[np.number]).columns.tolist()
2032
-
2033
- # 분석 데이터 추출
2034
- analysis_data = data[numeric_cols].copy()
2035
-
2036
- # 샘플 크기에 따라 자동으로 shapiro 또는 normaltest 선택
2037
- test_method = 's' if len(analysis_data) <= 5000 else 'n'
2038
- normality_results = normal_test(analysis_data, columns=numeric_cols, method=test_method)
2039
-
2040
- # 정규성 결과를 딕셔너리로 변환
2041
- normality_info = dict(zip(normality_results['column'], normality_results['is_normal']))
2042
-
2043
- # 상관계수 계산: 모든 변수가 정규분포를 따르면 Pearson, 하나라도 아니면 Spearman 사용
2044
- all_normal = all(normality_info.values())
2045
- if all_normal:
2046
- # Pearson 상관계수
2047
- corr_matrix = analysis_data.corr(method='pearson')
2048
- selected_corr_type = 'Pearson'
2049
- else:
2050
- # Spearman 상관계수
2051
- corr_matrix = analysis_data.corr(method='spearman')
2052
- selected_corr_type = 'Spearman'
2053
-
2054
- # 상관계수 정보 데이터프레임 생성 (교차표 형태 - 상관행렬과 동일한 구조)
2055
- corr_info_df = DataFrame(
2056
- selected_corr_type,
2057
- index=numeric_cols,
2058
- columns=numeric_cols
2059
- )
2060
-
2061
- return corr_matrix, corr_info_df
2062
-
2063
-
2064
2084
  # ===================================================================
2065
2085
  # 쌍별 상관분석 (선형성/이상치 점검 후 Pearson/Spearman 자동 선택)
2066
2086
  # ===================================================================
@@ -2099,13 +2119,16 @@ def corr_pairwise(
2099
2119
  [1] corr_matrix: 상관계수 행렬 (행과 열에 변수명, 값에 상관계수)
2100
2120
 
2101
2121
  Examples:
2102
- >>> from hossam.hs_stats import corr_pairwise
2103
- >>> import pandas as pd
2104
- >>> df = pd.DataFrame({'x1': [1,2,3,4,5], 'x2': [2,4,5,4,6], 'x3': [10,20,25,24,30]})
2105
- >>> # 전체 숫자형 컬럼에 대해 상관분석
2106
- >>> result_df, corr_matrix = corr_pairwise(df)
2107
- >>> # 특정 컬럼만 분석
2108
- >>> result_df, corr_matrix = corr_pairwise(df, fields=['x1', 'x2'])
2122
+ ```python
2123
+ from hossam import *
2124
+ from pandas import DataFrame
2125
+
2126
+ df = DataFrame({'x1': [1,2,3,4,5], 'x2': [2,4,5,4,6], 'x3': [10,20,25,24,30]})
2127
+ # 전체 숫자형 컬럼에 대해 상관분석
2128
+ result_df, corr_matrix = hs_stats.corr_pairwise(df)
2129
+ # 특정 컬럼만 분석
2130
+ result_df, corr_matrix = hs_stats.corr_pairwise(df, fields=['x1', 'x2'])
2131
+ ```
2109
2132
  """
2110
2133
 
2111
2134
  # 0) 컬럼 선정 (숫자형만)
@@ -2289,17 +2312,22 @@ def oneway_anova(data: DataFrame, dv: str, between: str, alpha: float = 0.05) ->
2289
2312
  - posthoc_report (str): 사후검정 유무와 유의한 쌍 정보를 요약한 보고 문장.
2290
2313
 
2291
2314
  Examples:
2292
- >>> from hossam import oneway_anova
2293
- >>> import pandas as pd
2294
- >>> df = pd.DataFrame({
2295
- ... 'score': [5.1, 4.9, 5.3, 5.0, 4.8, 5.5, 5.2, 5.7, 5.3, 5.1],
2296
- ... 'group': ['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B']
2297
- ... })
2298
- >>> anova_df, anova_report, posthoc_df, posthoc_report = oneway_anova(df, dv='score', between='group')
2299
- >>> print(anova_report)
2300
- >>> if posthoc_df is not None:
2301
- ... print(posthoc_report)
2302
- ... print(posthoc_df.head())
2315
+ ```python
2316
+ from hossam import *
2317
+ from pandas import DataFrame
2318
+
2319
+ df = DataFrame({
2320
+ 'score': [5.1, 4.9, 5.3, 5.0, 4.8, 5.5, 5.2, 5.7, 5.3, 5.1],
2321
+ 'group': ['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B']
2322
+ })
2323
+
2324
+ anova_df, anova_report, posthoc_df, posthoc_report = hs_stats.oneway_anova(df, dv='score', between='group')
2325
+
2326
+ # 사후검정결과는 ANOVA가 유의할 때만 생성됨
2327
+ if posthoc_df is not None:
2328
+ print(posthoc_report)
2329
+ print(posthoc_df.head())
2330
+ ```
2303
2331
 
2304
2332
  Raises:
2305
2333
  ValueError: dv 또는 between 컬럼이 데이터프레임에 없을 경우.
@@ -2636,20 +2664,19 @@ def predict(fit, data: DataFrame | Series) -> DataFrame | Series | float:
2636
2664
  Exception: 데이터와 모형의 특성 불일치로 인한 predict 실패.
2637
2665
 
2638
2666
  Examples:
2639
- >>> import statsmodels.api as sm
2640
- >>> # 선형회귀 (상수항 자동 추가)
2641
- >>> X = sm.add_constant(df[['x1', 'x2']])
2642
- >>> y = df['y']
2643
- >>> fit_ols = sm.OLS(y, X).fit()
2644
- >>> pred = predict(fit_ols, df_new[['x1', 'x2']]) # DataFrame 반환
2645
-
2646
- >>> # 로지스틱 회귀 (상수항 자동 추가)
2647
- >>> fit_logit = sm.Logit(y_binary, X).fit()
2648
- >>> pred_prob = predict(fit_logit, df_new[['x1', 'x2']]) # DataFrame 반환 (해석 포함)
2649
- """
2650
- from statsmodels.regression.linear_model import RegressionResultsWrapper
2651
- from statsmodels.discrete.discrete_model import BinaryResults
2667
+ ```python
2668
+ from hossam import *
2669
+
2670
+ df = hs_util.load_data("some_data.csv")
2671
+ fit1 = hs_stats.ols(df, yname="target")
2652
2672
 
2673
+ pred = hs_stats.predict(fit1, df_new[['x1', 'x2']]) # DataFrame 반환
2674
+
2675
+ # 로지스틱 회귀 (상수항 자동 추가)
2676
+ fit2 = hs_stats.logit(df, yname="target")
2677
+ pred_prob = hs_stats.predict(fit2, df_new[['x1', 'x2']]) # DataFrame 반환 (해석 포함)
2678
+ ```
2679
+ """
2653
2680
  # fit 객체의 타입 확인
2654
2681
  fit_type = type(fit).__name__
2655
2682
 
@@ -2724,158 +2751,6 @@ def predict(fit, data: DataFrame | Series) -> DataFrame | Series | float:
2724
2751
  )
2725
2752
 
2726
2753
 
2727
- # ===================================================================
2728
- # 확장된 기술통계량 (Extended Descriptive Statistics)
2729
- # ===================================================================
2730
- def describe(data: DataFrame, *fields: str, columns: list = None):
2731
- """데이터프레임의 연속형 변수에 대한 확장된 기술통계량을 반환한다.
2732
-
2733
- 각 연속형(숫자형) 컬럼의 기술통계량(describe)을 구하고, 이에 사분위수 범위(IQR),
2734
- 이상치 경계값(UP, DOWN), 왜도(skew), 이상치 개수 및 비율, 분포 특성, 로그변환 필요성을
2735
- 추가하여 반환한다.
2736
-
2737
- Args:
2738
- data (DataFrame): 분석 대상 데이터프레임.
2739
- *fields (str): 분석할 컬럼명 목록. 지정하지 않으면 모든 숫자형 컬럼을 처리.
2740
- columns (list, optional): 반환할 통계량 컬럼 목록. None이면 모든 통계량 반환.
2741
-
2742
- Returns:
2743
- DataFrame: 각 필드별 확장된 기술통계량을 포함한 데이터프레임.
2744
- 행은 다음과 같은 통계량을 포함:
2745
-
2746
- - count (float): 비결측치의 수
2747
- - mean (float): 평균값
2748
- - std (float): 표준편차
2749
- - min (float): 최소값
2750
- - 25% (float): 제1사분위수 (Q1)
2751
- - 50% (float): 제2사분위수 (중앙값)
2752
- - 75% (float): 제3사분위수 (Q3)
2753
- - max (float): 최대값
2754
- - iqr (float): 사분위 범위 (Q3 - Q1)
2755
- - up (float): 이상치 상한 경계값 (Q3 + 1.5 * IQR)
2756
- - down (float): 이상치 하한 경계값 (Q1 - 1.5 * IQR)
2757
- - skew (float): 왜도
2758
- - outlier_count (int): 이상치 개수
2759
- - outlier_rate (float): 이상치 비율(%)
2760
- - dist (str): 분포 특성 ("극단 우측 꼬리", "거의 대칭" 등)
2761
- - log_need (str): 로그변환 필요성 ("높음", "중간", "낮음")
2762
-
2763
- Examples:
2764
- 전체 숫자형 컬럼에 대한 확장된 기술통계:
2765
-
2766
- >>> from hossam import summary
2767
- >>> import pandas as pd
2768
- >>> df = pd.DataFrame({
2769
- ... 'x': [1, 2, 3, 4, 5, 100],
2770
- ... 'y': [10, 20, 30, 40, 50, 60],
2771
- ... 'z': ['a', 'b', 'c', 'd', 'e', 'f']
2772
- ... })
2773
- >>> result = summary(df)
2774
- >>> print(result)
2775
-
2776
- 특정 컬럼만 분석:
2777
-
2778
- >>> result = summary(df, 'x', 'y')
2779
- >>> print(result)
2780
-
2781
- Notes:
2782
- - 숫자형이 아닌 컬럼은 자동으로 제외됩니다.
2783
- - 결과는 필드(컬럼)가 행으로, 통계량이 열로 구성됩니다.
2784
- - Tukey의 1.5 * IQR 규칙을 사용하여 이상치를 판정합니다.
2785
- - 분포 특성은 왜도 값으로 판정합니다.
2786
- - 로그변환 필요성은 왜도의 절댓값 크기로 판정합니다.
2787
- """
2788
- if not fields:
2789
- fields = data.select_dtypes(include=['int', 'int32', 'int64', 'float', 'float32', 'float64']).columns
2790
-
2791
- # 기술통계량 구하기
2792
- desc = data[list(fields)].describe().T
2793
-
2794
- # 추가 통계량 계산
2795
- additional_stats = []
2796
- for f in fields:
2797
- # 숫자 타입이 아니라면 건너뜀
2798
- if data[f].dtype not in [
2799
- 'int',
2800
- 'int32',
2801
- 'int64',
2802
- 'float',
2803
- 'float32',
2804
- 'float64',
2805
- 'int64',
2806
- 'float64',
2807
- 'float32'
2808
- ]:
2809
- continue
2810
-
2811
- # 사분위수
2812
- q1 = data[f].quantile(q=0.25)
2813
- q3 = data[f].quantile(q=0.75)
2814
-
2815
- # 이상치 경계 (Tukey's fences)
2816
- iqr = q3 - q1
2817
- down = q1 - 1.5 * iqr
2818
- up = q3 + 1.5 * iqr
2819
-
2820
- # 왜도
2821
- skew = data[f].skew()
2822
-
2823
- # 이상치 개수 및 비율
2824
- outlier_count = ((data[f] < down) | (data[f] > up)).sum()
2825
- outlier_rate = (outlier_count / len(data)) * 100
2826
-
2827
- # 분포 특성 판정 (왜도 기준)
2828
- abs_skew = abs(skew)
2829
- if abs_skew < 0.5:
2830
- dist = "거의 대칭"
2831
- elif abs_skew < 1.0:
2832
- if skew > 0:
2833
- dist = "약한 우측 꼬리"
2834
- else:
2835
- dist = "약한 좌측 꼬리"
2836
- elif abs_skew < 2.0:
2837
- if skew > 0:
2838
- dist = "중간 우측 꼬리"
2839
- else:
2840
- dist = "중간 좌측 꼬리"
2841
- else:
2842
- if skew > 0:
2843
- dist = "극단 우측 꼬리"
2844
- else:
2845
- dist = "극단 좌측 꼬리"
2846
-
2847
- # 로그변환 필요성 판정
2848
- if abs_skew < 0.5:
2849
- log_need = "낮음"
2850
- elif abs_skew < 1.0:
2851
- log_need = "중간"
2852
- else:
2853
- log_need = "높음"
2854
-
2855
- additional_stats.append({
2856
- 'field': f,
2857
- 'iqr': iqr,
2858
- 'up': up,
2859
- 'down': down,
2860
- 'outlier_count': outlier_count,
2861
- 'outlier_rate': outlier_rate,
2862
- 'skew': skew,
2863
- 'dist': dist,
2864
- 'log_need': log_need
2865
- })
2866
-
2867
- additional_df = DataFrame(additional_stats).set_index('field')
2868
-
2869
- # 결과 병합
2870
- result = concat([desc, additional_df], axis=1)
2871
-
2872
- # columns 파라미터가 지정된 경우 해당 컬럼만 필터링
2873
- if columns is not None:
2874
- result = result[columns]
2875
-
2876
- return result
2877
-
2878
-
2879
2754
  # ===================================================================
2880
2755
  # 상관계수 및 효과크기 분석 (Correlation & Effect Size)
2881
2756
  # ===================================================================
@@ -2902,13 +2777,16 @@ def corr_effect_size(data: DataFrame, dv: str, *fields: str, alpha: float = 0.05
2902
2777
  - Effect_Size (str): 효과크기 분류 ('Large', 'Medium', 'Small', 'Negligible')
2903
2778
 
2904
2779
  Examples:
2905
- >>> from hossam import hs_stats
2906
- >>> import pandas as pd
2907
- >>> df = pd.DataFrame({'age': [20, 30, 40, 50],
2908
- ... 'bmi': [22, 25, 28, 30],
2909
- ... 'charges': [1000, 2000, 3000, 4000]})
2910
- >>> result = hs_stats.corr_effect_size(df, 'charges', 'age', 'bmi')
2911
- >>> print(result)
2780
+ ```python
2781
+ from hossam import *
2782
+ from pandas import DataFrame
2783
+
2784
+ df = DataFrame({'age': [20, 30, 40, 50],
2785
+ 'bmi': [22, 25, 28, 30],
2786
+ 'charges': [1000, 2000, 3000, 4000]})
2787
+
2788
+ result = hs_stats.corr_effect_size(df, 'charges', 'age', 'bmi')
2789
+ ```
2912
2790
  """
2913
2791
 
2914
2792
  # fields가 지정되지 않으면 수치형 컬럼 중 dv 제외 모두 사용