hossam 0.4.2__py3-none-any.whl → 0.4.4__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_plot.py CHANGED
@@ -35,12 +35,12 @@ if pd.__version__ > "2.0.0":
35
35
 
36
36
  config = SimpleNamespace(
37
37
  dpi=200,
38
- width=800,
39
- height=520,
40
- font_size=10,
38
+ width=600,
39
+ height=350,
40
+ font_size=7,
41
41
  font_weight="normal",
42
- frame_width=0.7,
43
- line_width=1.5,
42
+ frame_width=0.5,
43
+ line_width=1,
44
44
  grid_alpha=0.3,
45
45
  grid_width=0.5,
46
46
  fill_alpha=0.3
@@ -49,7 +49,7 @@ config = SimpleNamespace(
49
49
  # ===================================================================
50
50
  # 기본 크기가 설정된 Figure와 Axes를 생성한다
51
51
  # ===================================================================
52
- def get_default_ax(width: int = config.width, height: int = config.height, rows: int = 1, cols: int = 1, dpi: int = config.dpi, flatten: bool = False, ws: int | None = None, hs: int | None = None):
52
+ def get_default_ax(width: int = config.width, height: int = config.height, rows: int = 1, cols: int = 1, dpi: int = config.dpi, flatten: bool = False, ws: int | None = None, hs: int | None = None, title: str = None):
53
53
  """기본 크기의 Figure와 Axes를 생성한다.
54
54
 
55
55
  Args:
@@ -61,6 +61,7 @@ def get_default_ax(width: int = config.width, height: int = config.height, rows:
61
61
  flatten (bool): Axes 배열을 1차원 리스트로 평탄화할지 여부.
62
62
  ws (int|None): 서브플롯 가로 간격(`wspace`). rows/cols가 1보다 클 때만 적용.
63
63
  hs (int|None): 서브플롯 세로 간격(`hspace`). rows/cols가 1보다 클 때만 적용.
64
+ title (str|None): Figure 제목.
64
65
 
65
66
  Returns:
66
67
  tuple[Figure, Axes]: 생성된 matplotlib Figure와 Axes 객체.
@@ -68,9 +69,15 @@ def get_default_ax(width: int = config.width, height: int = config.height, rows:
68
69
  figsize = (width * cols / 100, height * rows / 100)
69
70
  fig, ax = plt.subplots(rows, cols, figsize=figsize, dpi=dpi)
70
71
 
71
- if (rows > 1 or cols > 1) and (ws != None and hs != None):
72
+ # ax가 배열 (subplots)인지 단일 Axes인지 확인
73
+ is_array = isinstance(ax, (np.ndarray, list))
74
+
75
+ if is_array and (ws != None and hs != None):
72
76
  fig.subplots_adjust(wspace=ws, hspace=hs)
73
77
 
78
+ if title and not is_array:
79
+ fig.suptitle(title, fontsize=config.font_size * 1.5, fontweight='bold')
80
+
74
81
  if flatten == True:
75
82
  # 단일 Axes인 경우 리스트로 변환
76
83
  if rows == 1 and cols == 1:
@@ -94,19 +101,43 @@ def get_default_ax(width: int = config.width, height: int = config.height, rows:
94
101
  return fig, ax
95
102
 
96
103
 
104
+ # ===================================================================
105
+ # 기본 크기가 설정된 Figure와 Axes를 생성한다
106
+ # ===================================================================
107
+ def create_figure(width: int = config.width, height: int = config.height, rows: int = 1, cols: int = 1, dpi: int = config.dpi, flatten: bool = False, ws: int | None = None, hs: int | None = None, title: str = None):
108
+ """기본 크기의 Figure와 Axes를 생성한다. get_default_ax의 래퍼 함수.
109
+
110
+ Args:
111
+ width (int): 가로 픽셀 크기.
112
+ height (int): 세로 픽셀 크기.
113
+ rows (int): 서브플롯 행 개수.
114
+ cols (int): 서브플롯 열 개수.
115
+ dpi (int): 해상도(DPI).
116
+ flatten (bool): Axes 배열을 1차원 리스트로 평탄화할지 여부.
117
+ ws (int|None): 서브플롯 가로 간격(`wspace`). rows/cols가 1보다 클 때만 적용.
118
+ hs (int|None): 서브플롯 세로 간격(`hspace`). rows/cols가 1보다 클 때만 적용.
119
+ title (str): Figure 제목.
120
+
121
+ Returns:
122
+ tuple[Figure, Axes]: 생성된 matplotlib Figure와 Axes 객체.
123
+ """
124
+ fig, ax = get_default_ax(width, height, rows, cols, dpi, flatten, ws, hs, title)
125
+ return fig, ax
126
+
127
+
97
128
  # ===================================================================
98
129
  # 그래프의 그리드, 레이아웃을 정리하고 필요 시 저장 또는 표시한다
99
130
  # ===================================================================
100
- def finalize_plot(ax: Axes, callback: any = None, outparams: bool = False, save_path: str = None, grid: bool = True) -> None:
131
+ def finalize_plot(ax: Axes | np.ndarray, callback: any = None, outparams: bool = False, save_path: str = None, grid: bool = True, title: str = None) -> None:
101
132
  """공통 후처리를 수행한다: 콜백 실행, 레이아웃 정리, 필요 시 표시/종료.
102
133
 
103
134
  Args:
104
- ax (Axes|ndarray|list): 대상 Axes (단일 Axes 또는 subplots 배열).
135
+ ax (Axes|np.ndarray): 대상 Axes (단일 Axes 또는 subplots 배열).
105
136
  callback (Callable|None): 추가 설정을 위한 사용자 콜백.
106
137
  outparams (bool): 내부에서 생성한 Figure인 경우 True.
107
138
  save_path (str|None): 이미지 저장 경로. None이 아니면 해당 경로로 저장.
108
139
  grid (bool): 그리드 표시 여부. 기본값은 True입니다.
109
-
140
+ title (str|None): 그래프 제목.
110
141
  Returns:
111
142
  None
112
143
  """
@@ -131,6 +162,9 @@ def finalize_plot(ax: Axes, callback: any = None, outparams: bool = False, save_
131
162
 
132
163
  plt.tight_layout()
133
164
 
165
+ if title and not is_array:
166
+ ax.set_title(title, fontsize=config.font_size * 1.3, pad=7, fontweight='bold')
167
+
134
168
  if save_path is not None:
135
169
  plt.savefig(save_path, dpi=config.dpi * 2, bbox_inches='tight')
136
170
 
@@ -139,6 +173,27 @@ def finalize_plot(ax: Axes, callback: any = None, outparams: bool = False, save_
139
173
  plt.close()
140
174
 
141
175
 
176
+ # ===================================================================
177
+ # 그래프의 그리드, 레이아웃을 정리하고 필요 시 저장 또는 표시한다
178
+ # ===================================================================
179
+ def show_figure(ax: Axes | np.ndarray, callback: any = None, outparams: bool = False, save_path: str = None, grid: bool = True, title: str = None) -> None:
180
+ """공통 후처리를 수행한다: 콜백 실행, 레이아웃 정리, 필요 시 표시/종료.
181
+ finalize_plot의 래퍼 함수.
182
+
183
+ Args:
184
+ ax (Axes|np.ndarray): 대상 Axes (단일 Axes 또는 subplots 배열).
185
+ callback (Callable|None): 추가 설정을 위한 사용자 콜백.
186
+ outparams (bool): 내부에서 생성한 Figure인 경우 True.
187
+ save_path (str|None): 이미지 저장 경로. None이 아니면 해당 경로로 저장.
188
+ grid (bool): 그리드 표시 여부. 기본값은 True입니다.
189
+ title (str|None): 그래프 제목.
190
+
191
+ Returns:
192
+ None
193
+ """
194
+ finalize_plot(ax, callback, outparams, save_path, grid, title)
195
+
196
+
142
197
  # ===================================================================
143
198
  # 선 그래프를 그린다
144
199
  # ===================================================================
@@ -147,6 +202,7 @@ def lineplot(
147
202
  xname: str = None,
148
203
  yname: str = None,
149
204
  hue: str = None,
205
+ title: str | None = None,
150
206
  marker: str = None,
151
207
  palette: str = None,
152
208
  width: int = config.width,
@@ -165,6 +221,7 @@ def lineplot(
165
221
  xname (str|None): x축 컬럼명.
166
222
  yname (str|None): y축 컬럼명.
167
223
  hue (str|None): 범주 구분 컬럼명.
224
+ title (str|None): 그래프 제목.
168
225
  marker (str|None): 마커 모양.
169
226
  palette (str|None): 팔레트 이름.
170
227
  width (int): 캔버스 가로 픽셀.
@@ -203,7 +260,7 @@ def lineplot(
203
260
  lineplot_kwargs.update(params)
204
261
 
205
262
  sb.lineplot(**lineplot_kwargs, linewidth=linewidth)
206
- finalize_plot(ax, callback, outparams, save_path)
263
+ finalize_plot(ax, callback, outparams, save_path, True, title)
207
264
 
208
265
 
209
266
  # ===================================================================
@@ -213,6 +270,7 @@ def boxplot(
213
270
  df: DataFrame,
214
271
  xname: str = None,
215
272
  yname: str = None,
273
+ title: str | None = None,
216
274
  orient: str = "v",
217
275
  palette: str = None,
218
276
  width: int = config.width,
@@ -230,6 +288,7 @@ def boxplot(
230
288
  df (DataFrame): 시각화할 데이터.
231
289
  xname (str|None): x축 범주 컬럼명.
232
290
  yname (str|None): y축 값 컬럼명.
291
+ title (str|None): 그래프 제목.
233
292
  orient (str): 'v' 또는 'h' 방향.
234
293
  palette (str|None): 팔레트 이름.
235
294
  width (int): 캔버스 가로 픽셀.
@@ -272,7 +331,7 @@ def boxplot(
272
331
  else:
273
332
  sb.boxplot(data=df, orient=orient, ax=ax, linewidth=linewidth, **params)
274
333
 
275
- finalize_plot(ax, callback, outparams, save_path)
334
+ finalize_plot(ax, callback, outparams, save_path, True, title)
276
335
 
277
336
 
278
337
  # ===================================================================
@@ -283,6 +342,7 @@ def kdeplot(
283
342
  xname: str = None,
284
343
  yname: str = None,
285
344
  hue: str = None,
345
+ title: str | None = None,
286
346
  palette: str = None,
287
347
  fill: bool = False,
288
348
  fill_alpha: float = config.fill_alpha,
@@ -306,6 +366,7 @@ def kdeplot(
306
366
  xname (str|None): x축 컬럼명.
307
367
  yname (str|None): y축 컬럼명.
308
368
  hue (str|None): 범주 컬럼명.
369
+ title (str|None): 그래프 제목.
309
370
  palette (str|None): 팔레트 이름.
310
371
  fill (bool): 면적 채우기 여부.
311
372
  fill_alpha (float): 채움 투명도.
@@ -369,7 +430,7 @@ def kdeplot(
369
430
  axes[idx].set_title(f"Q{idx+1}: [{lo:.3g}, {hi:.3g}]")
370
431
  axes[idx].grid(True, alpha=config.grid_alpha, linewidth=config.grid_width)
371
432
 
372
- finalize_plot(axes[0], callback, outparams, save_path)
433
+ finalize_plot(axes[0], callback, outparams, save_path, True, title)
373
434
  return
374
435
 
375
436
  if ax is None:
@@ -403,7 +464,7 @@ def kdeplot(
403
464
 
404
465
  sb.kdeplot(**kdeplot_kwargs)
405
466
 
406
- finalize_plot(ax, callback, outparams, save_path)
467
+ finalize_plot(ax, callback, outparams, save_path, True, title)
407
468
 
408
469
 
409
470
  # ===================================================================
@@ -412,8 +473,9 @@ def kdeplot(
412
473
  def histplot(
413
474
  df: DataFrame,
414
475
  xname: str,
415
- hue=None,
416
- bins=None,
476
+ hue: str | None = None,
477
+ title: str | None = None,
478
+ bins: int | None = None,
417
479
  kde: bool = True,
418
480
  palette: str = None,
419
481
  width: int = config.width,
@@ -431,6 +493,7 @@ def histplot(
431
493
  df (DataFrame): 시각화할 데이터.
432
494
  xname (str): 히스토그램 대상 컬럼명.
433
495
  hue (str|None): 범주 컬럼명.
496
+ title (str|None): 그래프 제목.
434
497
  bins (int|sequence|None): 구간 수 또는 경계.
435
498
  kde (bool): KDE 표시 여부.
436
499
  palette (str|None): 팔레트 이름.
@@ -487,7 +550,7 @@ def histplot(
487
550
  histplot_kwargs.update(params)
488
551
  sb.histplot(**histplot_kwargs)
489
552
 
490
- finalize_plot(ax, callback, outparams, save_path)
553
+ finalize_plot(ax, callback, outparams, save_path, True, title)
491
554
 
492
555
 
493
556
  # ===================================================================
@@ -497,6 +560,7 @@ def stackplot(
497
560
  df: DataFrame,
498
561
  xname: str,
499
562
  hue: str,
563
+ title: str | None = None,
500
564
  palette: str = None,
501
565
  width: int = config.width,
502
566
  height: int = config.height,
@@ -513,6 +577,7 @@ def stackplot(
513
577
  df (DataFrame): 시각화할 데이터.
514
578
  xname (str): x축 기준 컬럼.
515
579
  hue (str): 클래스 컬럼.
580
+ title (str|None): 그래프 제목.
516
581
  palette (str|None): 팔레트 이름.
517
582
  width (int): 캔버스 가로 픽셀.
518
583
  height (int): 캔버스 세로 픽셀.
@@ -571,7 +636,7 @@ def stackplot(
571
636
  ax.set_xticks(xticks)
572
637
  ax.set_xticklabels(xticks)
573
638
 
574
- finalize_plot(ax, callback, outparams, save_path)
639
+ finalize_plot(ax, callback, outparams, save_path, True, title)
575
640
 
576
641
 
577
642
  # ===================================================================
@@ -582,6 +647,7 @@ def scatterplot(
582
647
  xname: str,
583
648
  yname: str,
584
649
  hue=None,
650
+ title: str | None = None,
585
651
  palette: str = None,
586
652
  width: int = config.width,
587
653
  height: int = config.height,
@@ -599,6 +665,7 @@ def scatterplot(
599
665
  xname (str): x축 컬럼.
600
666
  yname (str): y축 컬럼.
601
667
  hue (str|None): 범주 컬럼.
668
+ title (str|None): 그래프 제목.
602
669
  palette (str|None): 팔레트 이름.
603
670
  width (int): 캔버스 가로 픽셀.
604
671
  height (int): 캔버스 세로 픽셀.
@@ -636,7 +703,7 @@ def scatterplot(
636
703
 
637
704
  sb.scatterplot(**scatterplot_kwargs)
638
705
 
639
- finalize_plot(ax, callback, outparams, save_path)
706
+ finalize_plot(ax, callback, outparams, save_path, True, title)
640
707
 
641
708
 
642
709
  # ===================================================================
@@ -646,6 +713,7 @@ def regplot(
646
713
  df: DataFrame,
647
714
  xname: str,
648
715
  yname: str,
716
+ title: str | None = None,
649
717
  palette: str = None,
650
718
  width: int = config.width,
651
719
  height: int = config.height,
@@ -662,6 +730,7 @@ def regplot(
662
730
  df (DataFrame): 시각화할 데이터.
663
731
  xname (str): 독립변수 컬럼.
664
732
  yname (str): 종속변수 컬럼.
733
+ title (str|None): 그래프 제목.
665
734
  palette (str|None): 선/점 색상.
666
735
  width (int): 캔버스 가로 픽셀.
667
736
  height (int): 캔버스 세로 픽셀.
@@ -702,7 +771,7 @@ def regplot(
702
771
 
703
772
  sb.regplot(**regplot_kwargs)
704
773
 
705
- finalize_plot(ax, callback, outparams, save_path)
774
+ finalize_plot(ax, callback, outparams, save_path, True, title)
706
775
 
707
776
 
708
777
  # ===================================================================
@@ -713,6 +782,7 @@ def lmplot(
713
782
  xname: str,
714
783
  yname: str,
715
784
  hue=None,
785
+ title: str | None = None,
716
786
  palette: str = None,
717
787
  width: int = config.width,
718
788
  height: int = config.height,
@@ -728,6 +798,7 @@ def lmplot(
728
798
  xname (str): 독립변수 컬럼.
729
799
  yname (str): 종속변수 컬럼.
730
800
  hue (str|None): 범주 컬럼.
801
+ title (str|None): 그래프 제목.
731
802
  palette (str|None): 팔레트 이름.
732
803
  width (int): 캔버스 가로 픽셀.
733
804
  height (int): 캔버스 세로 픽셀.
@@ -766,6 +837,9 @@ def lmplot(
766
837
 
767
838
  g.fig.grid(True, alpha=config.grid_alpha, linewidth=config.grid_width)
768
839
 
840
+ if title:
841
+ g.fig.suptitle(title, fontsize=config.font_size * 1.5, fontweight='bold')
842
+
769
843
  plt.tight_layout()
770
844
 
771
845
  if save_path is not None:
@@ -781,6 +855,7 @@ def lmplot(
781
855
  def pairplot(
782
856
  df: DataFrame,
783
857
  xnames=None,
858
+ title: str | None = None,
784
859
  diag_kind: str = "kde",
785
860
  hue=None,
786
861
  palette: str = None,
@@ -800,6 +875,7 @@ def pairplot(
800
875
  - str: 해당 컬럼에 대해서만 처리.
801
876
  - list: 주어진 컬럼들에 대해서만 처리.
802
877
  기본값은 None.
878
+ title (str|None): 그래프 제목.
803
879
  diag_kind (str): 대각선 플롯 종류('kde' 등).
804
880
  hue (str|None): 범주 컬럼.
805
881
  palette (str|None): 팔레트 이름.
@@ -852,6 +928,10 @@ def pairplot(
852
928
  scale = len(target_cols)
853
929
  g.fig.set_size_inches(w=(width / dpi) * scale, h=(height / dpi) * scale)
854
930
  g.fig.set_dpi(dpi)
931
+
932
+ if title:
933
+ g.fig.suptitle(title, fontsize=config.font_size * 1.5, fontweight='bold')
934
+
855
935
  g.map_lower(func=sb.kdeplot, fill=True, alpha=config.fill_alpha, linewidth=linewidth)
856
936
  g.map_upper(func=sb.scatterplot, linewidth=linewidth)
857
937
 
@@ -876,6 +956,7 @@ def countplot(
876
956
  df: DataFrame,
877
957
  xname: str,
878
958
  hue=None,
959
+ title: str | None = None,
879
960
  palette: str = None,
880
961
  order: int = 1,
881
962
  width: int = config.width,
@@ -893,6 +974,7 @@ def countplot(
893
974
  df (DataFrame): 시각화할 데이터.
894
975
  xname (str): 범주 컬럼.
895
976
  hue (str|None): 보조 범주 컬럼.
977
+ title (str|None): 그래프 제목.
896
978
  palette (str|None): 팔레트 이름.
897
979
  order (int): 숫자형일 때 정렬 방식(1: 값 기준, 기타: 빈도 기준).
898
980
  width (int): 캔버스 가로 픽셀.
@@ -938,7 +1020,7 @@ def countplot(
938
1020
 
939
1021
  sb.countplot(**countplot_kwargs)
940
1022
 
941
- finalize_plot(ax, callback, outparams, save_path)
1023
+ finalize_plot(ax, callback, outparams, save_path, True, title)
942
1024
 
943
1025
 
944
1026
  # ===================================================================
@@ -949,6 +1031,7 @@ def barplot(
949
1031
  xname: str,
950
1032
  yname: str,
951
1033
  hue=None,
1034
+ title: str | None = None,
952
1035
  palette: str = None,
953
1036
  width: int = config.width,
954
1037
  height: int = config.height,
@@ -966,6 +1049,7 @@ def barplot(
966
1049
  xname (str): 범주 컬럼.
967
1050
  yname (str): 값 컬럼.
968
1051
  hue (str|None): 보조 범주 컬럼.
1052
+ title (str|None): 그래프 제목.
969
1053
  palette (str|None): 팔레트 이름.
970
1054
  width (int): 캔버스 가로 픽셀.
971
1055
  height (int): 캔버스 세로 픽셀.
@@ -1002,7 +1086,7 @@ def barplot(
1002
1086
  barplot_kwargs.update(params)
1003
1087
 
1004
1088
  sb.barplot(**barplot_kwargs)
1005
- finalize_plot(ax, callback, outparams, save_path)
1089
+ finalize_plot(ax, callback, outparams, save_path, True, title)
1006
1090
 
1007
1091
 
1008
1092
  # ===================================================================
@@ -1013,6 +1097,7 @@ def boxenplot(
1013
1097
  xname: str,
1014
1098
  yname: str,
1015
1099
  hue=None,
1100
+ title: str | None = None,
1016
1101
  palette: str = None,
1017
1102
  width: int = config.width,
1018
1103
  height: int = config.height,
@@ -1030,6 +1115,7 @@ def boxenplot(
1030
1115
  xname (str): 범주 컬럼.
1031
1116
  yname (str): 값 컬럼.
1032
1117
  hue (str|None): 보조 범주 컬럼.
1118
+ title (str|None): 그래프 제목.
1033
1119
  palette (str|None): 팔레트 이름.
1034
1120
  width (int): 캔버스 가로 픽셀.
1035
1121
  height (int): 캔버스 세로 픽셀.
@@ -1064,7 +1150,7 @@ def boxenplot(
1064
1150
  boxenplot_kwargs.update(params)
1065
1151
 
1066
1152
  sb.boxenplot(**boxenplot_kwargs)
1067
- finalize_plot(ax, callback, outparams, save_path)
1153
+ finalize_plot(ax, callback, outparams, save_path, True, title)
1068
1154
 
1069
1155
 
1070
1156
  # ===================================================================
@@ -1075,6 +1161,7 @@ def violinplot(
1075
1161
  xname: str,
1076
1162
  yname: str,
1077
1163
  hue=None,
1164
+ title: str | None = None,
1078
1165
  palette: str = None,
1079
1166
  width: int = config.width,
1080
1167
  height: int = config.height,
@@ -1092,6 +1179,7 @@ def violinplot(
1092
1179
  xname (str): 범주 컬럼.
1093
1180
  yname (str): 값 컬럼.
1094
1181
  hue (str|None): 보조 범주 컬럼.
1182
+ title (str|None): 그래프 제목.
1095
1183
  palette (str|None): 팔레트 이름.
1096
1184
  width (int): 캔버스 가로 픽셀.
1097
1185
  height (int): 캔버스 세로 픽셀.
@@ -1125,7 +1213,7 @@ def violinplot(
1125
1213
 
1126
1214
  violinplot_kwargs.update(params)
1127
1215
  sb.violinplot(**violinplot_kwargs)
1128
- finalize_plot(ax, callback, outparams, save_path)
1216
+ finalize_plot(ax, callback, outparams, save_path, True, title)
1129
1217
 
1130
1218
 
1131
1219
  # ===================================================================
@@ -1136,6 +1224,7 @@ def pointplot(
1136
1224
  xname: str,
1137
1225
  yname: str,
1138
1226
  hue=None,
1227
+ title: str | None = None,
1139
1228
  palette: str = None,
1140
1229
  width: int = config.width,
1141
1230
  height: int = config.height,
@@ -1153,6 +1242,7 @@ def pointplot(
1153
1242
  xname (str): 범주 컬럼.
1154
1243
  yname (str): 값 컬럼.
1155
1244
  hue (str|None): 보조 범주 컬럼.
1245
+ title (str|None): 그래프 제목.
1156
1246
  palette (str|None): 팔레트 이름.
1157
1247
  width (int): 캔버스 가로 픽셀.
1158
1248
  height (int): 캔버스 세로 픽셀.
@@ -1188,7 +1278,7 @@ def pointplot(
1188
1278
 
1189
1279
  pointplot_kwargs.update(params)
1190
1280
  sb.pointplot(**pointplot_kwargs)
1191
- finalize_plot(ax, callback, outparams, save_path)
1281
+ finalize_plot(ax, callback, outparams, save_path, True, title)
1192
1282
 
1193
1283
 
1194
1284
  # ===================================================================
@@ -1199,6 +1289,7 @@ def jointplot(
1199
1289
  xname: str,
1200
1290
  yname: str,
1201
1291
  hue=None,
1292
+ title: str | None = None,
1202
1293
  palette: str = None,
1203
1294
  width: int = config.width,
1204
1295
  height: int = config.height,
@@ -1214,6 +1305,7 @@ def jointplot(
1214
1305
  xname (str): x축 컬럼.
1215
1306
  yname (str): y축 컬럼.
1216
1307
  hue (str|None): 범주 컬럼.
1308
+ title (str|None): 그래프 제목.
1217
1309
  palette (str|None): 팔레트 이름.
1218
1310
  width (int): 캔버스 가로 픽셀.
1219
1311
  height (int): 캔버스 세로 픽셀.
@@ -1243,6 +1335,9 @@ def jointplot(
1243
1335
  g.fig.set_size_inches(width / dpi, height / dpi)
1244
1336
  g.fig.set_dpi(dpi)
1245
1337
 
1338
+ if title:
1339
+ g.fig.suptitle(title, fontsize=config.font_size * 1.5, fontweight='bold')
1340
+
1246
1341
  # 중앙 및 주변 플롯에 grid 추가
1247
1342
  g.ax_joint.grid(True, alpha=config.grid_alpha, linewidth=config.grid_width)
1248
1343
  g.ax_marg_x.grid(True, alpha=config.grid_alpha, linewidth=config.grid_width)
@@ -1262,6 +1357,7 @@ def jointplot(
1262
1357
  # ===================================================================
1263
1358
  def heatmap(
1264
1359
  data: DataFrame,
1360
+ title: str | None = None,
1265
1361
  palette: str = None,
1266
1362
  width: int | None = None,
1267
1363
  height: int | None = None,
@@ -1276,6 +1372,7 @@ def heatmap(
1276
1372
 
1277
1373
  Args:
1278
1374
  data (DataFrame): 행렬 형태 데이터.
1375
+ title (str|None): 그래프 제목.
1279
1376
  palette (str|None): 컬러맵 이름.
1280
1377
  width (int|None): 캔버스 가로 픽셀. None이면 자동 계산.
1281
1378
  height (int|None): 캔버스 세로 픽셀. None이면 자동 계산.
@@ -1313,7 +1410,7 @@ def heatmap(
1313
1410
  # heatmap은 hue를 지원하지 않으므로 cmap에 palette 사용
1314
1411
  sb.heatmap(**heatmatp_kwargs)
1315
1412
 
1316
- finalize_plot(ax, callback, outparams, save_path, False)
1413
+ finalize_plot(ax, callback, outparams, save_path, True, title)
1317
1414
 
1318
1415
 
1319
1416
  # ===================================================================
@@ -1324,6 +1421,7 @@ def convex_hull(
1324
1421
  xname: str,
1325
1422
  yname: str,
1326
1423
  hue: str,
1424
+ title: str | None = None,
1327
1425
  palette: str = None,
1328
1426
  width: int = config.width,
1329
1427
  height: int = config.height,
@@ -1341,6 +1439,7 @@ def convex_hull(
1341
1439
  xname (str): x축 컬럼.
1342
1440
  yname (str): y축 컬럼.
1343
1441
  hue (str): 클러스터/범주 컬럼.
1442
+ title (str|None): 그래프 제목.
1344
1443
  palette (str|None): 팔레트 이름.
1345
1444
  width (int): 캔버스 가로 픽셀.
1346
1445
  height (int): 캔버스 세로 픽셀.
@@ -1385,7 +1484,7 @@ def convex_hull(
1385
1484
  sb.scatterplot(
1386
1485
  data=data, x=xname, y=yname, hue=hue, palette=palette, ax=ax, **params
1387
1486
  )
1388
- finalize_plot(ax, callback, outparams, save_path)
1487
+ finalize_plot(ax, callback, outparams, save_path, True, title)
1389
1488
 
1390
1489
 
1391
1490
  # ===================================================================
@@ -1394,10 +1493,12 @@ def convex_hull(
1394
1493
  def kde_confidence_interval(
1395
1494
  data: DataFrame,
1396
1495
  xnames=None,
1496
+ title: str | None = None,
1397
1497
  clevel=0.95,
1398
1498
  width: int = config.width,
1399
1499
  height: int = config.height,
1400
1500
  linewidth: float = config.line_width,
1501
+ fill: bool = False,
1401
1502
  dpi: int = config.dpi,
1402
1503
  save_path: str = None,
1403
1504
  callback: any = None,
@@ -1412,10 +1513,12 @@ def kde_confidence_interval(
1412
1513
  - str: 해당 컬럼에 대해서만 처리.
1413
1514
  - list: 주어진 컬럼들에 대해서만 처리.
1414
1515
  기본값은 None.
1516
+ title (str|None): 그래프 제목.
1415
1517
  clevel (float): 신뢰수준(0~1).
1416
1518
  width (int): 캔버스 가로 픽셀.
1417
1519
  height (int): 캔버스 세로 픽셀.
1418
1520
  linewidth (float): 선 굵기.
1521
+ fill (bool): KDE 채우기 여부.
1419
1522
  dpi (int): 그림 크기 및 해상도.
1420
1523
  callback (Callable|None): Axes 후처리 콜백.
1421
1524
  ax (Axes|None): 외부에서 전달한 Axes.
@@ -1469,7 +1572,7 @@ def kde_confidence_interval(
1469
1572
  cmin, cmax = t.interval(clevel, dof, loc=sample_mean, scale=sample_std_error)
1470
1573
 
1471
1574
  # 현재 컬럼에 대한 커널밀도추정
1472
- sb.kdeplot(data=column, linewidth=linewidth, ax=current_ax)
1575
+ sb.kdeplot(data=column, linewidth=linewidth, ax=current_ax, fill=fill, alpha=config.fill_alpha)
1473
1576
 
1474
1577
  # 그래프 축의 범위
1475
1578
  xmin, xmax, ymin, ymax = current_ax.get_position().bounds
@@ -1494,7 +1597,7 @@ def kde_confidence_interval(
1494
1597
 
1495
1598
  current_ax.grid(True, alpha=config.grid_alpha, linewidth=config.grid_width)
1496
1599
 
1497
- finalize_plot(axes[0] if isinstance(axes, list) and len(axes) > 0 else ax, callback, outparams, save_path)
1600
+ finalize_plot(axes[0] if isinstance(axes, list) and len(axes) > 0 else ax, callback, outparams, save_path, True, title)
1498
1601
 
1499
1602
 
1500
1603
  # ===================================================================
@@ -1504,6 +1607,7 @@ def pvalue1_anotation(
1504
1607
  data: DataFrame,
1505
1608
  target: str,
1506
1609
  hue: str,
1610
+ title: str | None = None,
1507
1611
  pairs: list = None,
1508
1612
  test: str = "t-test_ind",
1509
1613
  text_format: str = "star",
@@ -1523,6 +1627,7 @@ def pvalue1_anotation(
1523
1627
  data (DataFrame): 시각화할 데이터.
1524
1628
  target (str): 값 컬럼명.
1525
1629
  hue (str): 그룹 컬럼명.
1630
+ title (str|None): 그래프 제목.
1526
1631
  pairs (list|None): 비교할 (group_a, group_b) 튜플 목록. None이면 hue 컬럼의 모든 고유값 조합을 자동 생성.
1527
1632
  test (str): 적용할 통계 검정 이름.
1528
1633
  text_format (str): 주석 형식('star' 등).
@@ -1574,7 +1679,7 @@ def pvalue1_anotation(
1574
1679
  annotator.apply_and_annotate()
1575
1680
 
1576
1681
  sb.despine()
1577
- finalize_plot(ax, callback, outparams, save_path)
1682
+ finalize_plot(ax, callback, outparams, save_path, True, title)
1578
1683
 
1579
1684
 
1580
1685
 
@@ -1583,6 +1688,7 @@ def pvalue1_anotation(
1583
1688
  # ===================================================================
1584
1689
  def ols_residplot(
1585
1690
  fit,
1691
+ title: str | None = None,
1586
1692
  lowess: bool = False,
1587
1693
  mse: bool = False,
1588
1694
  width: int = config.width,
@@ -1603,6 +1709,7 @@ def ols_residplot(
1603
1709
  Args:
1604
1710
  fit: 회귀 모형 객체 (statsmodels의 RegressionResultsWrapper).
1605
1711
  fit.resid와 fit.fittedvalues를 통해 잔차와 적합값을 추출한다.
1712
+ title (str|None): 그래프 제목.
1606
1713
  lowess (bool): LOWESS 스무딩 적용 여부.
1607
1714
  mse (bool): √MSE, 2√MSE, 3√MSE 대역선과 비율 표시 여부.
1608
1715
  width (int): 캔버스 가로 픽셀.
@@ -1632,7 +1739,7 @@ def ols_residplot(
1632
1739
  y = y_pred + resid # 실제값 = 적합값 + 잔차
1633
1740
 
1634
1741
  if ax is None:
1635
- fig, ax = get_default_ax(width, height, 1, 1, dpi)
1742
+ fig, ax = get_default_ax(width + 150 if mse else width, height, 1, 1, dpi)
1636
1743
  outparams = True
1637
1744
 
1638
1745
  # 산점도 직접 그리기 (seaborn.residplot보다 훨씬 빠름)
@@ -1702,7 +1809,7 @@ def ols_residplot(
1702
1809
  color=c,
1703
1810
  )
1704
1811
 
1705
- finalize_plot(ax, callback, outparams, save_path)
1812
+ finalize_plot(ax, callback, outparams, save_path, True, title)
1706
1813
 
1707
1814
 
1708
1815
  # ===================================================================
@@ -1710,6 +1817,7 @@ def ols_residplot(
1710
1817
  # ===================================================================
1711
1818
  def ols_qqplot(
1712
1819
  fit,
1820
+ title: str | None = None,
1713
1821
  line: str = 's',
1714
1822
  width: int = config.width,
1715
1823
  height: int = config.height,
@@ -1728,6 +1836,7 @@ def ols_qqplot(
1728
1836
  Args:
1729
1837
  fit: 회귀 모형 객체 (statsmodels의 RegressionResultsWrapper 등).
1730
1838
  fit.resid 속성을 통해 잔차를 추출하여 정규성을 확인한다.
1839
+ title (str|None): 그래프 제목.
1731
1840
  line (str): 참조선의 유형. 기본값 's' (standardized).
1732
1841
  - 's': 표본의 표준편차와 평균을 기반으로 조정된 선 (권장)
1733
1842
  - 'r': 실제 점들에 대한 회귀선 (데이터 추세 반영)
@@ -1788,7 +1897,7 @@ def ols_qqplot(
1788
1897
  if line.get_linestyle() == '--' or line.get_color() == 'r':
1789
1898
  line.set_linewidth(linewidth)
1790
1899
 
1791
- finalize_plot(ax, callback, outparams, save_path)
1900
+ finalize_plot(ax, callback, outparams, save_path, True, title)
1792
1901
 
1793
1902
 
1794
1903
  # ===================================================================
@@ -1796,6 +1905,7 @@ def ols_qqplot(
1796
1905
  # ===================================================================
1797
1906
  def distribution_by_class(
1798
1907
  data: DataFrame,
1908
+ title: str | None = None,
1799
1909
  xnames: list = None,
1800
1910
  hue: str = None,
1801
1911
  type: str = "kde",
@@ -1815,6 +1925,7 @@ def distribution_by_class(
1815
1925
  data (DataFrame): 시각화할 데이터.
1816
1926
  xnames (list|None): 대상 컬럼 목록(None이면 전 컬럼).
1817
1927
  hue (str|None): 클래스 컬럼.
1928
+ title (str|None): 그래프 제목.
1818
1929
  type (str): 'kde' | 'hist' | 'histkde'.
1819
1930
  bins (int|sequence|None): 히스토그램 구간.
1820
1931
  palette (str|None): 팔레트 이름.
@@ -1897,6 +2008,7 @@ def scatter_by_class(
1897
2008
  yname: str,
1898
2009
  group: list | None = None,
1899
2010
  hue: str | None = None,
2011
+ title: str | None = None,
1900
2012
  palette: str | None = None,
1901
2013
  outline: bool = False,
1902
2014
  width: int = config.width,
@@ -1913,6 +2025,7 @@ def scatter_by_class(
1913
2025
  yname (str): 종속변수 컬럼명(필수).
1914
2026
  group (list|None): x 컬럼 목록 또는 [[x, y], ...] 형태. None이면 자동 생성.
1915
2027
  hue (str|None): 클래스 컬럼.
2028
+ title (str|None): 그래프 제목.
1916
2029
  palette (str|None): 팔레트 이름.
1917
2030
  outline (bool): 볼록 껍질을 표시할지 여부.
1918
2031
  width (int): 캔버스 가로 픽셀.
@@ -1968,6 +2081,7 @@ def categorical_target_distribution(
1968
2081
  data: DataFrame,
1969
2082
  yname: str,
1970
2083
  hue: list | str | None = None,
2084
+ title: str | None = None,
1971
2085
  kind: str = "box",
1972
2086
  kde_fill: bool = True,
1973
2087
  palette: str | None = None,
@@ -1985,6 +2099,7 @@ def categorical_target_distribution(
1985
2099
  data (DataFrame): 시각화할 데이터.
1986
2100
  yname (str): 종속변수 컬럼명(연속형 추천).
1987
2101
  hue (list|str|None): 명목형 독립변수 목록. None이면 자동 탐지.
2102
+ title (str|None): 그래프 제목.
1988
2103
  kind (str): 'box', 'violin', 'kde'.
1989
2104
  kde_fill (bool): kind='kde'일 때 영역 채우기 여부.
1990
2105
  palette (str|None): 팔레트 이름.
@@ -2043,7 +2158,7 @@ def categorical_target_distribution(
2043
2158
  for j in range(n_plots, len(axes)):
2044
2159
  axes[j].set_visible(False)
2045
2160
 
2046
- finalize_plot(axes[0], callback, outparams, save_path)
2161
+ finalize_plot(axes[0], callback, outparams, save_path, True, title)
2047
2162
 
2048
2163
 
2049
2164
  # ===================================================================
@@ -2053,6 +2168,7 @@ def roc_curve_plot(
2053
2168
  fit,
2054
2169
  y: np.ndarray | pd.Series = None,
2055
2170
  X: pd.DataFrame | np.ndarray = None,
2171
+ title: str | None = None,
2056
2172
  width: int = config.height,
2057
2173
  height: int = config.height,
2058
2174
  linewidth: float = config.line_width,
@@ -2067,6 +2183,7 @@ def roc_curve_plot(
2067
2183
  fit: statsmodels Logit 결과 객체 (`fit.predict()`로 예측 확률을 계산 가능해야 함).
2068
2184
  y (array-like|None): 외부 데이터의 실제 레이블. 제공 시 이를 실제값으로 사용.
2069
2185
  X (array-like|None): 외부 데이터의 설계행렬(독립변수). 제공 시 해당 데이터로 예측 확률 계산.
2186
+ title (str|None): 그래프 제목.
2070
2187
  width (int): 캔버스 가로 픽셀.
2071
2188
  height (int): 캔버스 세로 픽셀.
2072
2189
  linewidth (float): 선 굵기.
@@ -2113,7 +2230,7 @@ def roc_curve_plot(
2113
2230
  ax.set_ylabel('재현율 (True Positive Rate)', fontsize=8)
2114
2231
  ax.set_title('ROC 곡선', fontsize=10, fontweight='bold')
2115
2232
  ax.legend(loc="lower right", fontsize=7)
2116
- finalize_plot(ax, callback, outparams, save_path)
2233
+ finalize_plot(ax, callback, outparams, save_path, True, title)
2117
2234
 
2118
2235
 
2119
2236
  # ===================================================================
@@ -2121,6 +2238,7 @@ def roc_curve_plot(
2121
2238
  # ===================================================================
2122
2239
  def confusion_matrix_plot(
2123
2240
  fit,
2241
+ title: str | None = None,
2124
2242
  threshold: float = 0.5,
2125
2243
  width: int = config.width,
2126
2244
  height: int = config.height,
@@ -2133,6 +2251,7 @@ def confusion_matrix_plot(
2133
2251
 
2134
2252
  Args:
2135
2253
  fit: statsmodels Logit 결과 객체 (`fit.predict()`로 예측 확률을 계산 가능해야 함).
2254
+ title (str|None): 그래프 제목.
2136
2255
  threshold (float): 예측 확률을 이진 분류로 변환할 임계값. 기본값 0.5.
2137
2256
  width (int): 캔버스 가로 픽셀.
2138
2257
  height (int): 캔버스 세로 픽셀.
@@ -2163,7 +2282,7 @@ def confusion_matrix_plot(
2163
2282
 
2164
2283
  ax.set_title(f'혼동행렬 (임계값: {threshold})', fontsize=8, fontweight='bold')
2165
2284
 
2166
- finalize_plot(ax, callback, outparams, save_path, False)
2285
+ finalize_plot(ax, callback, outparams, save_path, False, title)
2167
2286
 
2168
2287
 
2169
2288
  # ===================================================================
@@ -2173,6 +2292,7 @@ def radarplot(
2173
2292
  df: DataFrame,
2174
2293
  columns: list = None,
2175
2294
  hue: str = None,
2295
+ title: str | None = None,
2176
2296
  normalize: bool = True,
2177
2297
  fill: bool = True,
2178
2298
  fill_alpha: float = 0.25,
@@ -2192,6 +2312,7 @@ def radarplot(
2192
2312
  df (DataFrame): 시각화할 데이터.
2193
2313
  columns (list|None): 레이더 차트에 표시할 컬럼 목록. None이면 모든 숫자형 컬럼 사용.
2194
2314
  hue (str|None): 집단 구분 컬럼. None이면 각 행을 개별 객체로 표시.
2315
+ title (str|None): 그래프 제목.
2195
2316
  normalize (bool): 0-1 범위로 정규화 여부. 기본값 True.
2196
2317
  fill (bool): 영역 채우기 여부.
2197
2318
  fill_alpha (float): 채움 투명도.
@@ -2293,7 +2414,7 @@ def radarplot(
2293
2414
  else:
2294
2415
  ax.set_title('Radar Chart', pad=20)
2295
2416
 
2296
- finalize_plot(ax, callback, outparams, save_path)
2417
+ finalize_plot(ax, callback, outparams, save_path, True, title)
2297
2418
 
2298
2419
 
2299
2420
  # ===================================================================
@@ -2302,6 +2423,7 @@ def radarplot(
2302
2423
  def distribution_plot(
2303
2424
  data: DataFrame,
2304
2425
  column: str,
2426
+ title: str | None = None,
2305
2427
  clevel: float = 0.95,
2306
2428
  orient: str = "h",
2307
2429
  hue: str | None = None,
@@ -2322,6 +2444,7 @@ def distribution_plot(
2322
2444
  Args:
2323
2445
  data (DataFrame): 시각화할 데이터.
2324
2446
  column (str): 분석할 컬럼명.
2447
+ title (str|None): 그래프 제목.
2325
2448
  clevel (float): KDE 신뢰수준 (0~1). 기본값 0.95.
2326
2449
  orient (str): Boxplot 방향 ('v' 또는 'h'). 기본값 'h'.
2327
2450
  hue (str|None): 명목형 컬럼명. 지정하면 각 범주별로 행을 늘려 KDE와 boxplot을 그림.
hossam/hs_prep.py CHANGED
@@ -158,16 +158,23 @@ def minmax_scaler(
158
158
  # ===================================================================
159
159
  # 지정된 컬럼들을 범주형 데이터로 설정한다
160
160
  # ===================================================================
161
- def set_category(data: DataFrame, *args: str) -> DataFrame:
161
+ def set_category(data: DataFrame, *args: str, columns: list = None) -> DataFrame:
162
162
  """카테고리 데이터를 설정한다.
163
163
 
164
164
  Args:
165
165
  data (DataFrame): 데이터프레임 객체
166
166
  *args (str): 컬럼명 목록
167
+ columns (list, optional): 변환할 컬럼명 목록. args와 중복 사용 불가.
167
168
 
168
169
  Returns:
169
170
  DataFrame: 카테고리 설정된 데이터프레임
170
171
  """
172
+ # columns 인자가 있으면 args보다 우선한다.
173
+ if columns is not None:
174
+ if args:
175
+ raise ValueError("args와 columns 인자는 중복 사용할 수 없습니다.")
176
+ args = columns
177
+
171
178
  df = data.copy()
172
179
 
173
180
  for k in args:
@@ -219,7 +226,7 @@ def unmelt(
219
226
  # ===================================================================
220
227
  # 지정된 변수의 이상치 테이블로 반환한다
221
228
  # ===================================================================
222
- def outlier_table(data: DataFrame, *fields: str) -> DataFrame:
229
+ def outlier_table(data: DataFrame, *fields: str, columns: list = None) -> DataFrame:
223
230
  """수치형 컬럼에 대한 사분위수 및 IQR 기반 이상치 경계를 계산한다.
224
231
 
225
232
  전달된 `fields`가 없으면 데이터프레임의 모든 수치형 컬럼을 대상으로 한다.
@@ -228,6 +235,7 @@ def outlier_table(data: DataFrame, *fields: str) -> DataFrame:
228
235
  Args:
229
236
  data (DataFrame): 분석할 데이터프레임.
230
237
  *fields (str): 대상 컬럼명(들). 생략 시 모든 수치형 컬럼 대상.
238
+ columns (list, optional): 변환할 컬럼명 목록. args와 중복 사용 불가.
231
239
 
232
240
  Returns:
233
241
  DataFrame: Q1, Q2(중앙값), Q3, IQR, 하한, 상한을 포함한 통계표.
@@ -236,6 +244,11 @@ def outlier_table(data: DataFrame, *fields: str) -> DataFrame:
236
244
  from hossam import *
237
245
  hs_prep.outlier_table(df, "value")
238
246
  """
247
+ # columns 인자가 있으면 args보다 우선한다.
248
+ if columns is not None:
249
+ if args:
250
+ raise ValueError("args와 columns 인자는 중복 사용할 수 없습니다.")
251
+ args = columns
239
252
 
240
253
  target_fields = list(fields) if fields else list(data.select_dtypes(include=[np.number]).columns)
241
254
  result = []
@@ -273,7 +286,7 @@ def outlier_table(data: DataFrame, *fields: str) -> DataFrame:
273
286
  # ===================================================================
274
287
  # 이상치를 대체값(NaN, 0) 또는 중앙값으로 교체한다
275
288
  # ===================================================================
276
- def replace_outliner(data: DataFrame, method: str = "nan", *fields: str) -> DataFrame:
289
+ def replace_outliner(data: DataFrame, method: str = "nan", *fields: str, columns: list = None) -> DataFrame:
277
290
  """이상치 경계값을 넘어가는 데이터를 경계값으로 대체한다.
278
291
 
279
292
  Args:
@@ -285,10 +298,16 @@ def replace_outliner(data: DataFrame, method: str = "nan", *fields: str) -> Data
285
298
  - most: 최빈값 대체
286
299
  - median: 중앙값 대체
287
300
  *fields (str): 컬럼명 목록
301
+ columns (list, optional): 변환할 컬럼명 목록. args와 중복 사용 불가.
288
302
 
289
303
  Returns:
290
304
  DataFrame: 이상치가 경계값으로 대체된 데이터 프레임
291
305
  """
306
+ # columns 인자가 있으면 args보다 우선한다.
307
+ if columns is not None:
308
+ if args:
309
+ raise ValueError("args와 columns 인자는 중복 사용할 수 없습니다.")
310
+ args = columns
292
311
 
293
312
  # 원본 데이터 프레임 복사
294
313
  df = data.copy()
@@ -335,16 +354,22 @@ def replace_outliner(data: DataFrame, method: str = "nan", *fields: str) -> Data
335
354
  # ===================================================================
336
355
  # 중빈 이상치를 제거한 연처리된 데이터프레임을 반환한다
337
356
  # ===================================================================
338
- def drop_outliner(data: DataFrame, *fields: str) -> DataFrame:
357
+ def drop_outliner(data: DataFrame, *fields: str, columns: list = None) -> DataFrame:
339
358
  """이상치를 결측치로 변환한 후 모두 삭제한다.
340
359
 
341
360
  Args:
342
361
  data (DataFrame): 데이터프레임
343
362
  *fields (str): 컬럼명 목록
363
+ columns (list, optional): 변환할 컬럼명 목록. args와 중복 사용 불가.
344
364
 
345
365
  Returns:
346
366
  DataFrame: 이상치가 삭제된 데이터프레임
347
367
  """
368
+ # columns 인자가 있으면 args보다 우선한다.
369
+ if columns is not None:
370
+ if args:
371
+ raise ValueError("args와 columns 인자는 중복 사용할 수 없습니다.")
372
+ args = columns
348
373
 
349
374
  df = replace_outliner(data, "nan", *fields)
350
375
  return df.dropna()
@@ -353,7 +378,7 @@ def drop_outliner(data: DataFrame, *fields: str) -> DataFrame:
353
378
  # ===================================================================
354
379
  # 범주 변수를 더미 변수(One-Hot 인코딩)로 변환한다
355
380
  # ===================================================================
356
- def get_dummies(data: DataFrame, *args: str, drop_first=True, dtype="int") -> DataFrame:
381
+ def get_dummies(data: DataFrame, *args: str, columns: list = None, drop_first: bool = True, dtype: str = "int") -> DataFrame:
357
382
  """명목형 변수를 더미 변수로 변환한다.
358
383
 
359
384
  컬럼명을 지정하면 그 컬럼들만 더미 변수로 변환하고,
@@ -362,6 +387,7 @@ def get_dummies(data: DataFrame, *args: str, drop_first=True, dtype="int") -> Da
362
387
  Args:
363
388
  data (DataFrame): 데이터프레임
364
389
  *args (str): 변환할 컬럼명 목록. 지정하지 않으면 숫자형이 아닌 모든 컬럼 자동 선택.
390
+ columns (list, optional): 변환할 컬럼명 목록. args와 중복 사용 불가.
365
391
  drop_first (bool, optional): 첫 번째 더미 변수 제거 여부. 기본값 True.
366
392
  dtype (str, optional): 더미 변수 데이터 타입. 기본값 "int".
367
393
 
@@ -379,6 +405,12 @@ def get_dummies(data: DataFrame, *args: str, drop_first=True, dtype="int") -> Da
379
405
  result = hs_prep.get_dummies(df, 'col1', drop_first=False, dtype='bool')
380
406
  ```
381
407
  """
408
+ # columns 인자가 있으면 args보다 우선한다.
409
+ if columns is not None:
410
+ if args:
411
+ raise ValueError("args와 columns 인자는 중복 사용할 수 없습니다.")
412
+ args = columns
413
+
382
414
  if not args:
383
415
  # args가 없으면 숫자 타입이 아닌 모든 컬럼 자동 선택
384
416
  cols_to_convert = []
hossam/hs_stats.py CHANGED
@@ -1,5 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
+
2
3
  from __future__ import annotations
4
+ from typing import overload, Tuple, Literal, Union
3
5
 
4
6
  # -------------------------------------------------------------
5
7
  import numpy as np
@@ -28,6 +30,7 @@ from scipy.stats import (
28
30
  wilcoxon,
29
31
  pearsonr,
30
32
  spearmanr,
33
+ chi2
31
34
  )
32
35
 
33
36
  import statsmodels.api as sm
@@ -36,10 +39,71 @@ from statsmodels.stats.outliers_influence import variance_inflation_factor
36
39
  from statsmodels.stats.multitest import multipletests
37
40
  from statsmodels.stats.stattools import durbin_watson
38
41
  from statsmodels.regression.linear_model import RegressionResultsWrapper
42
+ from statsmodels.discrete.discrete_model import BinaryResultsWrapper
39
43
  from statsmodels.discrete.discrete_model import BinaryResults
40
44
 
41
45
  from pingouin import anova, pairwise_tukey, welch_anova, pairwise_gameshowell
42
46
 
47
+ from .hs_plot import ols_residplot, ols_qqplot
48
+
49
+ # ===================================================================
50
+ # MCAR(결측치 무작위성) 검정
51
+ # ===================================================================
52
+ def mcar_test(data: DataFrame, columns: list | str | None = None) -> DataFrame:
53
+ if isinstance(columns, str):
54
+ columns = [c.strip() for c in columns.split(",")]
55
+
56
+ cols = data.columns if columns is None else columns
57
+ df = data[cols]
58
+
59
+ # 결측치가 있는 컬럼만 사용
60
+ cols_with_na = [c for c in df.columns if df[c].isna().any()]
61
+ if len(cols_with_na) < 2:
62
+ raise ValueError("MCAR 검정은 결측치가 있는 변수가 최소 2개 이상 필요합니다.")
63
+
64
+ X = df[cols_with_na].to_numpy()
65
+ n, p = X.shape
66
+
67
+ # complete cases로 평균·공분산 추정
68
+ complete = ~np.isnan(X).any(axis=1)
69
+ if complete.sum() < p + 1:
70
+ raise ValueError("완전관측치(complete cases)가 부족하여 MCAR 검정을 수행할 수 없습니다.")
71
+
72
+ mu = X[complete].mean(axis=0)
73
+ S = np.cov(X[complete], rowvar=False)
74
+ S_inv = np.linalg.pinv(S)
75
+
76
+ chi_sq = 0.0
77
+ dfree = 0
78
+
79
+ for i in range(n):
80
+ obs = ~np.isnan(X[i])
81
+ if obs.sum() == p:
82
+ continue # complete case는 제외
83
+ diff = X[i, obs] - mu[obs]
84
+ S_obs = S[np.ix_(obs, obs)]
85
+ S_obs_inv = np.linalg.pinv(S_obs)
86
+
87
+ chi_sq += diff @ S_obs_inv @ diff
88
+ dfree += obs.sum()
89
+
90
+ dfree -= p # Little's adjustment
91
+
92
+ p_value = 1 - chi2.cdf(chi_sq, dfree)
93
+ is_mcar = p_value > 0.05
94
+
95
+ return DataFrame([{
96
+ "statistic": chi_sq,
97
+ "dof": dfree,
98
+ "p-value": p_value,
99
+ "is_mcar": is_mcar,
100
+ "interpretation": (
101
+ "결측치는 완전 무작위(MCAR)로 판단됨 → 결측치 삭제 가능"
102
+ if is_mcar else
103
+ "결측치는 완전 무작위(MCAR)가 아님 → 삭제 시 편향 가능"
104
+ )
105
+ }])
106
+
43
107
  # ===================================================================
44
108
  # 결측치 분석 (Missing Values Analysis)
45
109
  # ===================================================================
@@ -219,6 +283,8 @@ def describe(data: DataFrame, *fields: str, columns: list | None = None):
219
283
  행은 다음과 같은 통계량을 포함:
220
284
 
221
285
  - count (float): 비결측치의 수
286
+ - na_count (int): 결측치의 수
287
+ - na_rate (float): 결측치 비율(%)
222
288
  - mean (float): 평균값
223
289
  - std (float): 표준편차
224
290
  - min (float): 최소값
@@ -267,9 +333,13 @@ def describe(data: DataFrame, *fields: str, columns: list | None = None):
267
333
 
268
334
  # 기술통계량 구하기
269
335
  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)
336
+
337
+ # 컬럼별 결측치 수(na_count) 추가
338
+ na_counts = data[list(fields)].isnull().sum()
339
+ desc.insert(1, 'na_count', na_counts)
340
+
341
+ # 결측치 비율(na_rate) 추가
342
+ desc.insert(2, 'na_rate', (na_counts / len(data)) * 100)
273
343
 
274
344
  # 추가 통계량 계산
275
345
  additional_stats = []
@@ -1192,7 +1262,10 @@ def trend(x: any, y: any, degree: int = 1, value_count: int = 100) -> Tuple[np.n
1192
1262
  # ===================================================================
1193
1263
  # 선형회귀 요약 리포트
1194
1264
  # ===================================================================
1195
- def ols_report(fit, data, full=False, alpha=0.05):
1265
+ def ols_report(fit, data, full=False, alpha=0.05) -> Union[
1266
+ Tuple[DataFrame, DataFrame],
1267
+ Tuple[DataFrame, DataFrame, str, str, list[str], str]
1268
+ ]:
1196
1269
  """선형회귀 적합 결과를 요약 리포트로 변환한다.
1197
1270
 
1198
1271
  Args:
@@ -1211,6 +1284,7 @@ def ols_report(fit, data, full=False, alpha=0.05):
1211
1284
  - 회귀식 문자열 (`equation_text`, str): 상수항과 계수를 포함한 회귀식 표현.
1212
1285
 
1213
1286
  full=False일 때:
1287
+ - 성능 지표 표 (`pdf`, DataFrame): R, R², Adj. R², F, p-value, Durbin-Watson.
1214
1288
  - 회귀계수 표 (`rdf`, DataFrame)
1215
1289
 
1216
1290
  Examples:
@@ -1378,7 +1452,19 @@ def ols_report(fit, data, full=False, alpha=0.05):
1378
1452
  # ===================================================================
1379
1453
  # 선형회귀
1380
1454
  # ===================================================================
1381
- def ols(df: DataFrame, yname: str, report=False):
1455
+ def ols(df: DataFrame, yname: str, report: bool | str | int = False) -> Union[
1456
+ RegressionResultsWrapper,
1457
+ Tuple[RegressionResultsWrapper, DataFrame, DataFrame],
1458
+ Tuple[
1459
+ RegressionResultsWrapper,
1460
+ DataFrame,
1461
+ DataFrame,
1462
+ str,
1463
+ str,
1464
+ list[str],
1465
+ str
1466
+ ]
1467
+ ]:
1382
1468
  """선형회귀분석을 수행하고 적합 결과를 반환한다.
1383
1469
 
1384
1470
  OLS(Ordinary Least Squares) 선형회귀분석을 실시한다.
@@ -1387,7 +1473,7 @@ def ols(df: DataFrame, yname: str, report=False):
1387
1473
  Args:
1388
1474
  df (DataFrame): 종속변수와 독립변수를 모두 포함한 데이터프레임.
1389
1475
  yname (str): 종속변수 컬럼명.
1390
- report: 리포트 모드 설정. 다음 값 중 하나:
1476
+ report (bool | str | int): 리포트 모드 설정. 다음 값 중 하나:
1391
1477
  - False (기본값): 리포트 미사용. fit 객체만 반환.
1392
1478
  - 1 또는 'summary': 요약 리포트 반환 (full=False).
1393
1479
  - 2 또는 'full': 풀 리포트 반환 (full=True).
@@ -1426,10 +1512,10 @@ def ols(df: DataFrame, yname: str, report=False):
1426
1512
  fit = hs_stats.ols(df, 'target')
1427
1513
 
1428
1514
  # 요약 리포트 반환
1429
- fit, pdf, rdf = hs_stats.ols(df, 'target', report=1)
1515
+ fit, pdf, rdf = hs_stats.ols(df, 'target', report='summary')
1430
1516
 
1431
1517
  # 풀 리포트 반환
1432
- fit, pdf, rdf, result_report, model_report, var_reports, eq = hs_stats.ols(df, 'target', report=2)
1518
+ fit, pdf, rdf, result_report, model_report, var_reports, eq = hs_stats.ols(df, 'target', report='full')
1433
1519
  ```
1434
1520
  """
1435
1521
  x = df.drop(yname, axis=1)
@@ -1459,15 +1545,31 @@ def ols(df: DataFrame, yname: str, report=False):
1459
1545
  # ===================================================================
1460
1546
  # 로지스틱 회귀 요약 리포트
1461
1547
  # ===================================================================
1462
- def logit_report(fit, data, threshold=0.5, full=False, alpha=0.05):
1548
+ def logit_report(
1549
+ fit: BinaryResultsWrapper,
1550
+ data: DataFrame,
1551
+ threshold: float = 0.5,
1552
+ full: Union[bool, str, int] = False,
1553
+ alpha: float = 0.05
1554
+ ) -> Union[
1555
+ Tuple[DataFrame, DataFrame],
1556
+ Tuple[
1557
+ DataFrame,
1558
+ DataFrame,
1559
+ str,
1560
+ str,
1561
+ list[str],
1562
+ np.ndarray
1563
+ ]
1564
+ ]:
1463
1565
  """로지스틱 회귀 적합 결과를 상세 리포트로 변환한다.
1464
1566
 
1465
1567
  Args:
1466
1568
  fit: statsmodels Logit 결과 객체 (`fit.summary()`와 예측 확률을 지원해야 함).
1467
- data: 종속변수와 독립변수를 모두 포함한 DataFrame.
1468
- threshold: 예측 확률을 이진 분류로 변환할 임계값. 기본값 0.5.
1469
- full: True이면 6개 값 반환, False이면 주요 2개(cdf, rdf)만 반환. 기본값 False.
1470
- alpha: 유의수준. 기본값 0.05.
1569
+ data (DataFrame): 종속변수와 독립변수를 모두 포함한 DataFrame.
1570
+ threshold (float): 예측 확률을 이진 분류로 변환할 임계값. 기본값 0.5.
1571
+ full (bool | str | int): True이면 6개 값 반환, False이면 주요 2개(cdf, rdf)만 반환. 기본값 False.
1572
+ alpha (float): 유의수준. 기본값 0.05.
1471
1573
 
1472
1574
  Returns:
1473
1575
  tuple: full=True일 때 다음 요소를 포함한다.
@@ -1652,7 +1754,25 @@ def logit_report(fit, data, threshold=0.5, full=False, alpha=0.05):
1652
1754
  # ===================================================================
1653
1755
  # 로지스틱 회귀
1654
1756
  # ===================================================================
1655
- def logit(df: DataFrame, yname: str, report=False):
1757
+ def logit(
1758
+ df: DataFrame,
1759
+ yname: str,
1760
+ report: Union[bool, str, int] = False
1761
+ ) -> Union[
1762
+ BinaryResultsWrapper,
1763
+ Tuple[
1764
+ BinaryResultsWrapper,
1765
+ DataFrame
1766
+ ],
1767
+ Tuple[
1768
+ BinaryResultsWrapper,
1769
+ DataFrame,
1770
+ DataFrame,
1771
+ str,
1772
+ str,
1773
+ List[str]
1774
+ ]
1775
+ ]:
1656
1776
  """로지스틱 회귀분석을 수행하고 적합 결과를 반환한다.
1657
1777
 
1658
1778
  종속변수가 이항(binary) 형태일 때 로지스틱 회귀분석을 실시한다.
@@ -1734,7 +1854,7 @@ def logit(df: DataFrame, yname: str, report=False):
1734
1854
  # ===================================================================
1735
1855
  # 선형성 검정 (Linearity Test)
1736
1856
  # ===================================================================
1737
- def ols_linearity_test(fit, power: int = 2, alpha: float = 0.05) -> DataFrame:
1857
+ def ols_linearity_test(fit, power: int = 2, alpha: float = 0.05, plot: bool = False, title: str = None, save_path: str = None) -> DataFrame:
1738
1858
  """회귀모형의 선형성을 Ramsey RESET 검정으로 평가한다.
1739
1859
 
1740
1860
  적합된 회귀모형에 대해 Ramsey RESET(Regression Specification Error Test) 검정을 수행하여
@@ -1747,6 +1867,9 @@ def ols_linearity_test(fit, power: int = 2, alpha: float = 0.05) -> DataFrame:
1747
1867
  power=2일 때 예측값의 제곱항이 추가됨.
1748
1868
  power가 클수록 더 높은 차수의 비선형성을 감지.
1749
1869
  alpha (float, optional): 유의수준. 기본값 0.05.
1870
+ plot (bool, optional): True이면 잔차 플롯을 출력. 기본값 False.
1871
+ title (str, optional): 플롯 제목. 기본값 None.
1872
+ save_path (str, optional): 플롯을 저장할 경로. 기본값 None
1750
1873
 
1751
1874
  Returns:
1752
1875
  DataFrame: 선형성 검정 결과를 포함한 데이터프레임.
@@ -1829,13 +1952,16 @@ def ols_linearity_test(fit, power: int = 2, alpha: float = 0.05) -> DataFrame:
1829
1952
  "해석": [interpretation]
1830
1953
  })
1831
1954
 
1955
+ if plot:
1956
+ ols_residplot(fit, lowess=True, mse=True, title=title, save_path=save_path)
1957
+
1832
1958
  return result_df
1833
1959
 
1834
1960
 
1835
1961
  # ===================================================================
1836
1962
  # 정규성 검정 (Normality Test)
1837
1963
  # ===================================================================
1838
- def ols_normality_test(fit, alpha: float = 0.05) -> DataFrame:
1964
+ def ols_normality_test(fit, alpha: float = 0.05, plot: bool = False, title: str = None, save_path: str = None) -> DataFrame:
1839
1965
  """회귀모형 잔차의 정규성을 검정한다.
1840
1966
 
1841
1967
  회귀모형의 잔차가 정규분포를 따르는지 Shapiro-Wilk 검정과 Jarque-Bera 검정으로 평가한다.
@@ -1844,6 +1970,9 @@ def ols_normality_test(fit, alpha: float = 0.05) -> DataFrame:
1844
1970
  Args:
1845
1971
  fit: 회귀 모형 객체 (statsmodels의 RegressionResultsWrapper).
1846
1972
  alpha (float, optional): 유의수준. 기본값 0.05.
1973
+ plot (bool, optional): True이면 Q-Q 플롯을 출력. 기본값 False.
1974
+ title (str, optional): 플롯 제목. 기본값 None.
1975
+ save_path (str, optional): 플롯을 저장할 경로. 기본값 None
1847
1976
 
1848
1977
  Returns:
1849
1978
  DataFrame: 정규성 검정 결과를 포함한 데이터프레임.
@@ -1922,6 +2051,10 @@ def ols_normality_test(fit, alpha: float = 0.05) -> DataFrame:
1922
2051
  if not results:
1923
2052
  raise ValueError("정규성 검정을 수행할 수 없습니다.")
1924
2053
 
2054
+
2055
+ if plot:
2056
+ ols_qqplot(fit, title=title, save_path=save_path)
2057
+
1925
2058
  result_df = DataFrame(results)
1926
2059
  return result_df
1927
2060
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hossam
3
- Version: 0.4.2
3
+ Version: 0.4.4
4
4
  Summary: Hossam Data Helper
5
5
  Author-email: Lee Kwang-Ho <leekh4232@gmail.com>
6
6
  License-Expression: MIT
@@ -3,14 +3,14 @@ hossam/__init__.py,sha256=OkMeP15jt6aCy7QNXMtkO0YRVvgOQYumkb7GuVKrbcs,2712
3
3
  hossam/data_loader.py,sha256=oUIsqbHQoRiHA_1tdElDaYo1ipmUB5fYSXYMB5gLOl0,6395
4
4
  hossam/hs_classroom.py,sha256=rgayol3U5PSo4rLfdbClfiAtG21bFrASaSW56PUsjus,27144
5
5
  hossam/hs_gis.py,sha256=DLogaf5nxJBbG-d8QoH2g8UfZ1omMtmEXDYgNg8jtT0,11410
6
- hossam/hs_plot.py,sha256=-ByDla2La34l6zI_T_e-FHAT3d8hLVo5J-pLBP8PixE,78285
7
- hossam/hs_prep.py,sha256=2ptFFxV4G1IFmy-B89TqXaPkA8jROZutr2XIkaXNHW4,36006
8
- hossam/hs_stats.py,sha256=qAor-RE5qNsytoZW1mriK3yql9PVif5bBGyG64YC2PM,110780
6
+ hossam/hs_plot.py,sha256=tsJMi2q9SzHRSs25dXsHkkImW-Jk7su1M6TbKwX9koU,83887
7
+ hossam/hs_prep.py,sha256=ocZNGzHzqgasVNLcb_LClTZaAeTYiIg4mzrixeEzBQU,37693
8
+ hossam/hs_stats.py,sha256=LpUG8U9ybnh6qSMW2SKCSDJZTeMhLH2xH2Pj4i7U6TU,114889
9
9
  hossam/hs_timeserise.py,sha256=gSj3cPgOGLOZEXhfW1anXbwpoJja847ZY9F8l9piJPE,42601
10
10
  hossam/hs_util.py,sha256=8byLj_VR93vS__lyf0xgQKArgMy9qFm2VvZVSCxfQX0,8444
11
11
  hossam/leekh.png,sha256=1PB5NQ24SDoHA5KMiBBsWpSa3iniFcwFTuGwuOsTHfI,6395
12
- hossam-0.4.2.dist-info/licenses/LICENSE,sha256=nIqzhlcFY_2D6QtFsYjwU7BWkafo-rUJOQpDZ-DsauI,941
13
- hossam-0.4.2.dist-info/METADATA,sha256=IKZmX6E8biC7B8I7HdGsCopOizJu_SgYmOiDTSXcKX4,3676
14
- hossam-0.4.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
- hossam-0.4.2.dist-info/top_level.txt,sha256=_-7bwjhthHplWhywEaHIJX2yL11CQCaLjCNSBlk6wiQ,7
16
- hossam-0.4.2.dist-info/RECORD,,
12
+ hossam-0.4.4.dist-info/licenses/LICENSE,sha256=nIqzhlcFY_2D6QtFsYjwU7BWkafo-rUJOQpDZ-DsauI,941
13
+ hossam-0.4.4.dist-info/METADATA,sha256=R6qOrcnZhbTzUrRK2x9vNksDjw8rVK1DVZrbRIPSPQQ,3676
14
+ hossam-0.4.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
15
+ hossam-0.4.4.dist-info/top_level.txt,sha256=_-7bwjhthHplWhywEaHIJX2yL11CQCaLjCNSBlk6wiQ,7
16
+ hossam-0.4.4.dist-info/RECORD,,
File without changes