hossam 0.4.7__tar.gz → 0.4.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hossam-0.4.7/hossam.egg-info → hossam-0.4.9}/PKG-INFO +4 -4
- {hossam-0.4.7 → hossam-0.4.9}/README.md +3 -3
- {hossam-0.4.7 → hossam-0.4.9}/hossam/__init__.py +2 -1
- {hossam-0.4.7 → hossam-0.4.9}/hossam/hs_plot.py +274 -86
- {hossam-0.4.7 → hossam-0.4.9}/hossam/hs_timeserise.py +1 -1
- {hossam-0.4.7 → hossam-0.4.9}/hossam/hs_util.py +40 -0
- {hossam-0.4.7 → hossam-0.4.9/hossam.egg-info}/PKG-INFO +4 -4
- {hossam-0.4.7 → hossam-0.4.9}/pyproject.toml +1 -1
- {hossam-0.4.7 → hossam-0.4.9}/LICENSE +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/MANIFEST.in +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/hossam/NotoSansKR-Regular.ttf +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/hossam/hs_classroom.py +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/hossam/hs_gis.py +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/hossam/hs_prep.py +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/hossam/hs_stats.py +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/hossam/leekh.png +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/hossam.egg-info/SOURCES.txt +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/hossam.egg-info/dependency_links.txt +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/hossam.egg-info/requires.txt +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/hossam.egg-info/top_level.txt +0 -0
- {hossam-0.4.7 → hossam-0.4.9}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hossam
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.9
|
|
4
4
|
Summary: Hossam Data Helper
|
|
5
5
|
Author-email: Lee Kwang-Ho <leekh4232@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -73,7 +73,7 @@ title: 🎓 Hossam Data Helper
|
|
|
73
73
|
pip install hossam
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
**요구사항**: Python 3.
|
|
76
|
+
**요구사항**: Python 3.13.9 이상
|
|
77
77
|
|
|
78
78
|
## 📚 전체 문서
|
|
79
79
|
|
|
@@ -83,9 +83,9 @@ pip install hossam
|
|
|
83
83
|
|
|
84
84
|
- **hs_plot**: 25+ 시각화 함수 (선 그래프, 산점도, 히스토그램, 박스플롯, 히트맵 등)
|
|
85
85
|
- **hs_stats**: 회귀/분류 분석, 교차검증, 정규성 검정, 상관분석 등
|
|
86
|
-
- **hs_prep**: 결측치 처리, 이상치 탐지, 스케일링, 인코딩
|
|
86
|
+
- **hs_prep**: 결측치 처리, 이상치 탐지, 스케일링, 인코딩 등의 데이터 전처리 기능
|
|
87
|
+
- **hs_timeserise**: 시계열 분석 기능 지원
|
|
87
88
|
- **hs_gis**: GIS 데이터 로드 및 시각화 (대한민국 지도 지원)
|
|
88
|
-
- **hs_classroom**: 학습용 이진분류, 다중분류, 회귀 데이터 생성
|
|
89
89
|
- **hs_util**: 예쁜 테이블 출력, 그리드 서치 등
|
|
90
90
|
|
|
91
91
|
자세한 사용법은 [API 문서](https://py.hossam.kr/api/hossam/)를 참고하세요.
|
|
@@ -29,7 +29,7 @@ title: 🎓 Hossam Data Helper
|
|
|
29
29
|
pip install hossam
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
**요구사항**: Python 3.
|
|
32
|
+
**요구사항**: Python 3.13.9 이상
|
|
33
33
|
|
|
34
34
|
## 📚 전체 문서
|
|
35
35
|
|
|
@@ -39,9 +39,9 @@ pip install hossam
|
|
|
39
39
|
|
|
40
40
|
- **hs_plot**: 25+ 시각화 함수 (선 그래프, 산점도, 히스토그램, 박스플롯, 히트맵 등)
|
|
41
41
|
- **hs_stats**: 회귀/분류 분석, 교차검증, 정규성 검정, 상관분석 등
|
|
42
|
-
- **hs_prep**: 결측치 처리, 이상치 탐지, 스케일링, 인코딩
|
|
42
|
+
- **hs_prep**: 결측치 처리, 이상치 탐지, 스케일링, 인코딩 등의 데이터 전처리 기능
|
|
43
|
+
- **hs_timeserise**: 시계열 분석 기능 지원
|
|
43
44
|
- **hs_gis**: GIS 데이터 로드 및 시각화 (대한민국 지도 지원)
|
|
44
|
-
- **hs_classroom**: 학습용 이진분류, 다중분류, 회귀 데이터 생성
|
|
45
45
|
- **hs_util**: 예쁜 테이블 출력, 그리드 서치 등
|
|
46
46
|
|
|
47
47
|
자세한 사용법은 [API 문서](https://py.hossam.kr/api/hossam/)를 참고하세요.
|
|
@@ -8,6 +8,7 @@ from . import hs_timeserise
|
|
|
8
8
|
from . import hs_util
|
|
9
9
|
from .hs_util import load_info
|
|
10
10
|
from .hs_util import _load_data_remote as load_data
|
|
11
|
+
from .hs_plot import visualize_silhouette
|
|
11
12
|
|
|
12
13
|
# py-modules
|
|
13
14
|
import sys
|
|
@@ -24,7 +25,7 @@ except Exception:
|
|
|
24
25
|
|
|
25
26
|
my_dpi = hs_plot.config.dpi
|
|
26
27
|
|
|
27
|
-
__all__ = ["my_dpi", "load_data", "load_info", "hs_classroom", "hs_gis", "hs_plot", "hs_prep", "hs_stats", "hs_timeserise", "hs_util"]
|
|
28
|
+
__all__ = ["my_dpi", "load_data", "load_info", "hs_classroom", "hs_gis", "hs_plot", "hs_prep", "hs_stats", "hs_timeserise", "hs_util", "visualize_silhouette"]
|
|
28
29
|
|
|
29
30
|
# 내부 모듈에서 hs_fig를 사용할 때는 아래와 같이 import 하세요.
|
|
30
31
|
# from hossam import hs_fig
|
|
@@ -22,12 +22,16 @@ from statsmodels.nonparametric.smoothers_lowess import lowess as sm_lowess
|
|
|
22
22
|
from statannotations.Annotator import Annotator
|
|
23
23
|
|
|
24
24
|
# ===================================================================
|
|
25
|
+
from sklearn.cluster._kmeans import KMeans
|
|
26
|
+
|
|
25
27
|
from sklearn.metrics import (
|
|
26
28
|
mean_squared_error,
|
|
27
29
|
ConfusionMatrixDisplay,
|
|
28
30
|
roc_curve,
|
|
29
31
|
auc,
|
|
30
|
-
confusion_matrix
|
|
32
|
+
confusion_matrix,
|
|
33
|
+
silhouette_score,
|
|
34
|
+
silhouette_samples
|
|
31
35
|
)
|
|
32
36
|
|
|
33
37
|
# ===================================================================
|
|
@@ -708,6 +712,8 @@ def scatterplot(
|
|
|
708
712
|
xname: str,
|
|
709
713
|
yname: str,
|
|
710
714
|
hue=None,
|
|
715
|
+
vector: str | None = None,
|
|
716
|
+
outline: bool = False,
|
|
711
717
|
title: str | None = None,
|
|
712
718
|
palette: str | None = None,
|
|
713
719
|
width: int = config.width,
|
|
@@ -726,6 +732,8 @@ def scatterplot(
|
|
|
726
732
|
xname (str): x축 컬럼.
|
|
727
733
|
yname (str): y축 컬럼.
|
|
728
734
|
hue (str|None): 범주 컬럼.
|
|
735
|
+
vector (str|None): 벡터 종류 컬럼.
|
|
736
|
+
outline (bool): 점 외곽선 표시 여부.
|
|
729
737
|
title (str|None): 그래프 제목.
|
|
730
738
|
palette (str|None): 팔레트 이름.
|
|
731
739
|
width (int): 캔버스 가로 픽셀.
|
|
@@ -745,9 +753,32 @@ def scatterplot(
|
|
|
745
753
|
fig, ax = get_default_ax(width, height, 1, 1, dpi) # type: ignore
|
|
746
754
|
outparams = True
|
|
747
755
|
|
|
756
|
+
|
|
757
|
+
if outline and hue is not None:
|
|
758
|
+
# 군집별 값의 종류별로 반복 수행
|
|
759
|
+
for c in df[hue].unique():
|
|
760
|
+
if c == -1:
|
|
761
|
+
continue
|
|
762
|
+
|
|
763
|
+
# 한 종류만 필터링한 결과에서 두 변수만 선택
|
|
764
|
+
df_c = df.loc[df[hue] == c, [xname, yname]]
|
|
765
|
+
|
|
766
|
+
try:
|
|
767
|
+
# 외각선 좌표 계산
|
|
768
|
+
hull = ConvexHull(df_c)
|
|
769
|
+
|
|
770
|
+
# 마지막 좌표 이후에 첫 번째 좌표를 연결
|
|
771
|
+
points = np.append(hull.vertices, hull.vertices[0])
|
|
772
|
+
|
|
773
|
+
ax.plot( # type: ignore
|
|
774
|
+
df_c.iloc[points, 0], df_c.iloc[points, 1], linewidth=linewidth, linestyle=":"
|
|
775
|
+
)
|
|
776
|
+
ax.fill(df_c.iloc[points, 0], df_c.iloc[points, 1], alpha=0.1) # type: ignore
|
|
777
|
+
except:
|
|
778
|
+
pass
|
|
779
|
+
|
|
748
780
|
# hue가 있을 때만 palette 사용, 없으면 color 사용
|
|
749
781
|
scatterplot_kwargs = {
|
|
750
|
-
"data": df,
|
|
751
782
|
"x": xname,
|
|
752
783
|
"y": yname,
|
|
753
784
|
"hue": hue,
|
|
@@ -762,7 +793,30 @@ def scatterplot(
|
|
|
762
793
|
|
|
763
794
|
scatterplot_kwargs.update(params)
|
|
764
795
|
|
|
765
|
-
|
|
796
|
+
# 백터 종류 구분 필드가 전달되지 않은 경우에는 원본 데이터를 그대로 사용
|
|
797
|
+
if vector is None:
|
|
798
|
+
sb.scatterplot(data=df, **scatterplot_kwargs)
|
|
799
|
+
else:
|
|
800
|
+
# 핵심벡터
|
|
801
|
+
scatterplot_kwargs['edgecolor'] = '#ffffff'
|
|
802
|
+
sb.scatterplot(data=df[df[vector] == "core"], **scatterplot_kwargs)
|
|
803
|
+
|
|
804
|
+
# 외곽백터
|
|
805
|
+
scatterplot_kwargs['edgecolor'] = '#000000'
|
|
806
|
+
scatterplot_kwargs['s'] = 25
|
|
807
|
+
scatterplot_kwargs['marker'] = '^'
|
|
808
|
+
scatterplot_kwargs['linewidth'] = 0.8
|
|
809
|
+
sb.scatterplot(data=df[df[vector] == "border"], **scatterplot_kwargs)
|
|
810
|
+
|
|
811
|
+
# 노이즈벡터
|
|
812
|
+
scatterplot_kwargs['edgecolor'] = None
|
|
813
|
+
scatterplot_kwargs['s'] = 25
|
|
814
|
+
scatterplot_kwargs['marker'] = 'x'
|
|
815
|
+
scatterplot_kwargs['linewidth'] = 2
|
|
816
|
+
scatterplot_kwargs['color'] = '#ff0000'
|
|
817
|
+
scatterplot_kwargs['hue'] = None
|
|
818
|
+
sb.scatterplot(data=df[df[vector] == "noise"], **scatterplot_kwargs)
|
|
819
|
+
|
|
766
820
|
|
|
767
821
|
finalize_plot(ax, callback, outparams, save_path, True, title) # type: ignore
|
|
768
822
|
|
|
@@ -1479,79 +1533,6 @@ def heatmap(
|
|
|
1479
1533
|
finalize_plot(ax, callback, outparams, save_path, True, title) # type: ignore
|
|
1480
1534
|
|
|
1481
1535
|
|
|
1482
|
-
# ===================================================================
|
|
1483
|
-
# 클러스터별 볼록 경계막(convex hull)을 그린다
|
|
1484
|
-
# ===================================================================
|
|
1485
|
-
def convex_hull(
|
|
1486
|
-
data: DataFrame,
|
|
1487
|
-
xname: str,
|
|
1488
|
-
yname: str,
|
|
1489
|
-
hue: str | None = None,
|
|
1490
|
-
title: str | None = None,
|
|
1491
|
-
palette: str | None = None,
|
|
1492
|
-
width: int = config.width,
|
|
1493
|
-
height: int = config.height,
|
|
1494
|
-
linewidth: float = config.line_width,
|
|
1495
|
-
dpi: int = config.dpi,
|
|
1496
|
-
save_path: str | None = None,
|
|
1497
|
-
callback: Callable | None = None,
|
|
1498
|
-
ax: Axes | None = None,
|
|
1499
|
-
**params,
|
|
1500
|
-
):
|
|
1501
|
-
"""클러스터별 볼록 껍질(convex hull)과 산점도를 그린다.
|
|
1502
|
-
|
|
1503
|
-
Args:
|
|
1504
|
-
data (DataFrame): 시각화할 데이터.
|
|
1505
|
-
xname (str): x축 컬럼.
|
|
1506
|
-
yname (str): y축 컬럼.
|
|
1507
|
-
hue (str): 클러스터/범주 컬럼.
|
|
1508
|
-
title (str|None): 그래프 제목.
|
|
1509
|
-
palette (str|None): 팔레트 이름.
|
|
1510
|
-
width (int): 캔버스 가로 픽셀.
|
|
1511
|
-
height (int): 캔버스 세로 픽셀.
|
|
1512
|
-
linewidth (float): 선 굵기.
|
|
1513
|
-
dpi (int): 그림 크기 및 해상도.
|
|
1514
|
-
callback (Callable|None): Axes 후처리 콜백.
|
|
1515
|
-
ax (Axes|None): 외부에서 전달한 Axes.
|
|
1516
|
-
**params: seaborn scatterplot 추가 인자.
|
|
1517
|
-
|
|
1518
|
-
Returns:
|
|
1519
|
-
None
|
|
1520
|
-
"""
|
|
1521
|
-
outparams = False
|
|
1522
|
-
|
|
1523
|
-
if ax is None:
|
|
1524
|
-
fig, ax = get_default_ax(width, height, 1, 1, dpi) # type: ignore
|
|
1525
|
-
outparams = True
|
|
1526
|
-
|
|
1527
|
-
# 군집별 값의 종류별로 반복 수행
|
|
1528
|
-
for c in data[hue].unique():
|
|
1529
|
-
if c == -1:
|
|
1530
|
-
continue
|
|
1531
|
-
|
|
1532
|
-
# 한 종류만 필터링한 결과에서 두 변수만 선택
|
|
1533
|
-
df_c = data.loc[data[hue] == c, [xname, yname]]
|
|
1534
|
-
|
|
1535
|
-
try:
|
|
1536
|
-
# 외각선 좌표 계산
|
|
1537
|
-
hull = ConvexHull(df_c)
|
|
1538
|
-
|
|
1539
|
-
# 마지막 좌표 이후에 첫 번째 좌표를 연결
|
|
1540
|
-
points = np.append(hull.vertices, hull.vertices[0])
|
|
1541
|
-
|
|
1542
|
-
ax.plot( # type: ignore
|
|
1543
|
-
df_c.iloc[points, 0], df_c.iloc[points, 1], linewidth=linewidth, linestyle=":"
|
|
1544
|
-
)
|
|
1545
|
-
ax.fill(df_c.iloc[points, 0], df_c.iloc[points, 1], alpha=0.1) # type: ignore
|
|
1546
|
-
except:
|
|
1547
|
-
pass
|
|
1548
|
-
|
|
1549
|
-
# convex_hull은 hue가 필수이므로 palette를 그대로 사용
|
|
1550
|
-
sb.scatterplot(
|
|
1551
|
-
data=data, x=xname, y=yname, hue=hue, palette=palette, ax=ax, **params
|
|
1552
|
-
)
|
|
1553
|
-
finalize_plot(ax, callback, outparams, save_path, True, title) # type: ignore
|
|
1554
|
-
|
|
1555
1536
|
|
|
1556
1537
|
# ===================================================================
|
|
1557
1538
|
# KDE와 신뢰구간을 나타낸 그래프를 그린다
|
|
@@ -2045,16 +2026,8 @@ def scatter_by_class(
|
|
|
2045
2026
|
processed.append([item, yname])
|
|
2046
2027
|
group = processed
|
|
2047
2028
|
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
convex_hull(data=data, xname=v[0], yname=v[1], hue=hue, palette=palette,
|
|
2051
|
-
width=width, height=height, linewidth=linewidth, dpi=dpi, callback=callback,
|
|
2052
|
-
save_path=save_path)
|
|
2053
|
-
else:
|
|
2054
|
-
for v in group:
|
|
2055
|
-
scatterplot(data=data, xname=v[0], yname=v[1], hue=hue, palette=palette,
|
|
2056
|
-
width=width, height=height, linewidth=linewidth, dpi=dpi, callback=callback,
|
|
2057
|
-
save_path=save_path) # type: ignore
|
|
2029
|
+
for v in group:
|
|
2030
|
+
scatterplot(data=data, xname=v[0], yname=v[1], outline=outline, hue=hue, palette=palette, width=width, height=height, linewidth=linewidth, dpi=dpi, callback=callback, save_path=save_path) # type: ignore
|
|
2058
2031
|
|
|
2059
2032
|
|
|
2060
2033
|
# ===================================================================
|
|
@@ -2519,3 +2492,218 @@ def distribution_plot(
|
|
|
2519
2492
|
plt.close()
|
|
2520
2493
|
else:
|
|
2521
2494
|
plt.show()
|
|
2495
|
+
|
|
2496
|
+
|
|
2497
|
+
def silhouette_plot(
|
|
2498
|
+
estimator: KMeans,
|
|
2499
|
+
data: DataFrame,
|
|
2500
|
+
title: str | None = None,
|
|
2501
|
+
width: int = config.width,
|
|
2502
|
+
height: int = config.height,
|
|
2503
|
+
linewidth: float = config.line_width,
|
|
2504
|
+
dpi: int = config.dpi,
|
|
2505
|
+
save_path: str | None = None,
|
|
2506
|
+
callback: Callable | None = None,
|
|
2507
|
+
ax: Axes | None = None,
|
|
2508
|
+
) -> None:
|
|
2509
|
+
"""
|
|
2510
|
+
군집분석 결과의 실루엣 플롯을 시각화함.
|
|
2511
|
+
|
|
2512
|
+
Args:
|
|
2513
|
+
estimator (KMeans): 학습된 KMeans 군집 모델 객체.
|
|
2514
|
+
data (DataFrame): 군집분석에 사용된 입력 데이터 (n_samples, n_features).
|
|
2515
|
+
title (str, optional): 플롯 제목. None이면 자동 생성.
|
|
2516
|
+
width (int, optional): 플롯 가로 크기 (inch 단위).
|
|
2517
|
+
height (int, optional): 플롯 세로 크기 (inch 단위).
|
|
2518
|
+
linewidth (float, optional): 기준선 등 선 두께.
|
|
2519
|
+
dpi (int, optional): 플롯 해상도(DPI).
|
|
2520
|
+
save_path (str, optional): 저장 경로 지정 시 파일로 저장.
|
|
2521
|
+
callback (Callable, optional): 추가 커스텀 콜백 함수.
|
|
2522
|
+
ax (Axes, optional): 기존 matplotlib Axes 객체. None이면 새로 생성.
|
|
2523
|
+
|
|
2524
|
+
Returns:
|
|
2525
|
+
None
|
|
2526
|
+
|
|
2527
|
+
Note:
|
|
2528
|
+
- 각 군집별 실루엣 계수 분포를 막대그래프로 시각화
|
|
2529
|
+
- 군집 품질(응집도/분리도) 평가에 활용
|
|
2530
|
+
- 붉은색 세로선은 전체 평균 실루엣 스코어를 의미
|
|
2531
|
+
"""
|
|
2532
|
+
|
|
2533
|
+
outparams = False
|
|
2534
|
+
if ax is None:
|
|
2535
|
+
fig, ax = get_default_ax(width, height, 1, 1, dpi) # type: ignore
|
|
2536
|
+
outparams = True
|
|
2537
|
+
|
|
2538
|
+
sil_avg = silhouette_score(X=data, labels=estimator.labels_)
|
|
2539
|
+
sil_values = silhouette_samples(X=data, labels=estimator.labels_)
|
|
2540
|
+
|
|
2541
|
+
y_lower = 10
|
|
2542
|
+
|
|
2543
|
+
# 클러스터링 갯수별로 fill_betweenx( )형태의 막대 그래프 표현.
|
|
2544
|
+
for i in range(estimator.n_clusters): # type: ignore
|
|
2545
|
+
ith_cluster_sil_values = sil_values[estimator.labels_ == i] # type: ignore
|
|
2546
|
+
ith_cluster_sil_values.sort() # type: ignore
|
|
2547
|
+
|
|
2548
|
+
size_cluster_i = ith_cluster_sil_values.shape[0] # type: ignore
|
|
2549
|
+
y_upper = y_lower + size_cluster_i
|
|
2550
|
+
|
|
2551
|
+
ax.fill_betweenx( # type: ignore
|
|
2552
|
+
np.arange(y_lower, y_upper),
|
|
2553
|
+
0,
|
|
2554
|
+
ith_cluster_sil_values,
|
|
2555
|
+
alpha=0.7,
|
|
2556
|
+
)
|
|
2557
|
+
ax.text(-0.05, y_lower + 0.5 * size_cluster_i, str(i)) # type: ignore
|
|
2558
|
+
y_lower = y_upper + 10
|
|
2559
|
+
|
|
2560
|
+
ax.axvline(x=sil_avg, color="red", linestyle="--", linewidth=linewidth) # type: ignore
|
|
2561
|
+
|
|
2562
|
+
ax.set_xlabel("The silhouette coefficient values") # type: ignore
|
|
2563
|
+
ax.set_ylabel("Cluster label") # type: ignore
|
|
2564
|
+
ax.set_xlim([-0.1, 1]) # type: ignore
|
|
2565
|
+
ax.set_ylim([0, len(data) + (estimator.n_clusters + 1) * 10]) # type: ignore
|
|
2566
|
+
ax.set_yticks([]) # type: ignore
|
|
2567
|
+
ax.set_xticks([0, 0.2, 0.4, 0.6, 0.8, 1]) # type: ignore
|
|
2568
|
+
|
|
2569
|
+
if title is None:
|
|
2570
|
+
title = "Number of Cluster : " + str(estimator.n_clusters) + ", Silhouette Score :" + str(round(sil_avg, 3)) # type: ignore
|
|
2571
|
+
|
|
2572
|
+
finalize_plot(ax, callback, outparams, save_path, True, title) # type: ignore
|
|
2573
|
+
|
|
2574
|
+
|
|
2575
|
+
def cluster_plot(
|
|
2576
|
+
estimator: KMeans,
|
|
2577
|
+
data: DataFrame,
|
|
2578
|
+
xname: str | None = None,
|
|
2579
|
+
yname: str | None = None,
|
|
2580
|
+
hue: str | None = None,
|
|
2581
|
+
title: str | None = None,
|
|
2582
|
+
palette: str | None = None,
|
|
2583
|
+
outline: bool = False,
|
|
2584
|
+
width: int = config.width,
|
|
2585
|
+
height: int = config.height,
|
|
2586
|
+
linewidth: float = config.line_width,
|
|
2587
|
+
dpi: int = config.dpi,
|
|
2588
|
+
save_path: str | None = None,
|
|
2589
|
+
ax: Axes | None = None,
|
|
2590
|
+
) -> None:
|
|
2591
|
+
|
|
2592
|
+
"""
|
|
2593
|
+
2차원 공간에서 군집분석 결과를 산점도로 시각화함.
|
|
2594
|
+
|
|
2595
|
+
Args:
|
|
2596
|
+
estimator (KMeans): 학습된 KMeans 군집 모델 객체.
|
|
2597
|
+
data (DataFrame): 군집분석에 사용된 입력 데이터 (n_samples, n_features).
|
|
2598
|
+
xname (str, optional): x축에 사용할 컬럼명. None이면 첫 번째 컬럼 사용.
|
|
2599
|
+
yname (str, optional): y축에 사용할 컬럼명. None이면 두 번째 컬럼 사용.
|
|
2600
|
+
hue (str, optional): 군집 구분에 사용할 컬럼명. None이면 'cluster' 자동 생성.
|
|
2601
|
+
title (str, optional): 플롯 제목. None이면 기본값 사용.
|
|
2602
|
+
palette (str, optional): 색상 팔레트.
|
|
2603
|
+
outline (bool, optional): 외곽선 표시 여부.
|
|
2604
|
+
width (int, optional): 플롯 가로 크기 (inch 단위).
|
|
2605
|
+
height (int, optional): 플롯 세로 크기 (inch 단위).
|
|
2606
|
+
linewidth (float, optional): 중심점 등 선 두께.
|
|
2607
|
+
dpi (int, optional): 플롯 해상도(DPI).
|
|
2608
|
+
save_path (str, optional): 저장 경로 지정 시 파일로 저장.
|
|
2609
|
+
ax (Axes, optional): 기존 matplotlib Axes 객체. None이면 새로 생성.
|
|
2610
|
+
|
|
2611
|
+
Returns:
|
|
2612
|
+
None
|
|
2613
|
+
|
|
2614
|
+
Example:
|
|
2615
|
+
```python
|
|
2616
|
+
cluster_plot(estimator, data, xname='Sepal.Length', yname='Sepal.Width')
|
|
2617
|
+
```
|
|
2618
|
+
|
|
2619
|
+
Note:
|
|
2620
|
+
- 각 군집별 산점도와 중심점(빨간색 원/숫자) 표시
|
|
2621
|
+
- 2차원 특성 공간에서 군집 분포와 분리도 시각화
|
|
2622
|
+
"""
|
|
2623
|
+
outparams = False
|
|
2624
|
+
if ax is None:
|
|
2625
|
+
fig, ax = get_default_ax(width, height, 1, 1, dpi) # type: ignore
|
|
2626
|
+
outparams = True
|
|
2627
|
+
|
|
2628
|
+
df = data.copy()
|
|
2629
|
+
|
|
2630
|
+
if not hue:
|
|
2631
|
+
df['cluster'] = estimator.labels_ # type: ignore
|
|
2632
|
+
hue = 'cluster'
|
|
2633
|
+
|
|
2634
|
+
if xname is None:
|
|
2635
|
+
xname = df.columns[0] # type: ignore
|
|
2636
|
+
|
|
2637
|
+
if yname is None:
|
|
2638
|
+
yname = df.columns[1] # type: ignore
|
|
2639
|
+
|
|
2640
|
+
xindex = df.columns.get_loc(xname) # type: ignore
|
|
2641
|
+
yindex = df.columns.get_loc(yname) # type: ignore
|
|
2642
|
+
|
|
2643
|
+
def callback(ax: Axes) -> None:
|
|
2644
|
+
# 클러스터 중심점 표시
|
|
2645
|
+
centers = estimator.cluster_centers_ # type: ignore
|
|
2646
|
+
ax.scatter( # type: ignore
|
|
2647
|
+
centers[:, xindex],
|
|
2648
|
+
centers[:, yindex],
|
|
2649
|
+
marker="o",
|
|
2650
|
+
color="white",
|
|
2651
|
+
alpha=1,
|
|
2652
|
+
s=200,
|
|
2653
|
+
edgecolor="r",
|
|
2654
|
+
linewidth=linewidth
|
|
2655
|
+
)
|
|
2656
|
+
|
|
2657
|
+
for i, c in enumerate(centers):
|
|
2658
|
+
ax.scatter(c[xindex], c[yindex], marker="$%d$" % i, alpha=1, s=50, edgecolor="k")
|
|
2659
|
+
|
|
2660
|
+
ax.set_xlabel("Feature space for the " + xname)
|
|
2661
|
+
ax.set_ylabel("Feature space for the " + yname)
|
|
2662
|
+
|
|
2663
|
+
scatterplot(
|
|
2664
|
+
df=df,
|
|
2665
|
+
xname=xname,
|
|
2666
|
+
yname=yname,
|
|
2667
|
+
hue=hue,
|
|
2668
|
+
title="The visualization of the clustered data." if title is None else title,
|
|
2669
|
+
outline=outline,
|
|
2670
|
+
palette=palette,
|
|
2671
|
+
width=width,
|
|
2672
|
+
height=height,
|
|
2673
|
+
linewidth=linewidth,
|
|
2674
|
+
dpi=dpi,
|
|
2675
|
+
save_path=save_path,
|
|
2676
|
+
callback=callback,
|
|
2677
|
+
ax=ax
|
|
2678
|
+
)
|
|
2679
|
+
|
|
2680
|
+
def visualize_silhouette(estimator: KMeans, data: DataFrame) -> None:
|
|
2681
|
+
"""
|
|
2682
|
+
군집분석 결과의 실루엣 플롯과 군집 산점도를 한 화면에 함께 시각화함.
|
|
2683
|
+
|
|
2684
|
+
Args:
|
|
2685
|
+
estimator (KMeans): 학습된 KMeans 군집 모델 객체.
|
|
2686
|
+
data (DataFrame): 군집분석에 사용된 입력 데이터 (n_samples, n_features).
|
|
2687
|
+
|
|
2688
|
+
Returns:
|
|
2689
|
+
None
|
|
2690
|
+
|
|
2691
|
+
Note:
|
|
2692
|
+
- 실루엣 플롯(왼쪽)과 2차원 군집 산점도(오른쪽)를 동시에 확인 가능
|
|
2693
|
+
- 군집 품질과 분포를 한눈에 비교·분석할 때 유용
|
|
2694
|
+
"""
|
|
2695
|
+
fig, ax = get_default_ax(rows=1, cols=2)
|
|
2696
|
+
|
|
2697
|
+
silhouette_plot(
|
|
2698
|
+
estimator=estimator,
|
|
2699
|
+
data=data,
|
|
2700
|
+
ax=ax[0],
|
|
2701
|
+
)
|
|
2702
|
+
|
|
2703
|
+
cluster_plot(
|
|
2704
|
+
estimator=estimator,
|
|
2705
|
+
data=data,
|
|
2706
|
+
ax=ax[1],
|
|
2707
|
+
)
|
|
2708
|
+
|
|
2709
|
+
finalize_plot(ax)
|
|
@@ -123,7 +123,7 @@ def diff(
|
|
|
123
123
|
ardict["기각값(Critical Values) %s" % key] = value
|
|
124
124
|
|
|
125
125
|
stationarity = ar[1] <= 0.05
|
|
126
|
-
ardict["데이터 정상성 여부"] = "정상" if stationarity else "비정상"
|
|
126
|
+
ardict["데이터 정상성 여부"] = "정상" if stationarity else "비정상" # type: ignore
|
|
127
127
|
|
|
128
128
|
ardf = DataFrame(ardict, index=["ADF Test"]).T
|
|
129
129
|
pretty_table(ardf)
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
# -------------------------------------------------------------
|
|
3
3
|
import requests
|
|
4
4
|
import json
|
|
5
|
+
import tempfile
|
|
6
|
+
import zipfile
|
|
7
|
+
import shutil
|
|
8
|
+
from pathlib import Path
|
|
5
9
|
from typing import TYPE_CHECKING
|
|
6
10
|
from importlib.metadata import distributions
|
|
7
11
|
import pandas as pd
|
|
@@ -21,6 +25,42 @@ def __get_df(path: str, index_col=None) -> DataFrame:
|
|
|
21
25
|
p = path.rfind(".")
|
|
22
26
|
exec = path[p+1:].lower()
|
|
23
27
|
|
|
28
|
+
# 파일 확장자가 압축파일인 경우 로컬에 파일을 다운로드 후 압축 해제
|
|
29
|
+
if exec == "zip":
|
|
30
|
+
tmp_dir = Path(tempfile.mkdtemp())
|
|
31
|
+
zip_path = tmp_dir / "data.zip"
|
|
32
|
+
|
|
33
|
+
# 원격 URL인 경우 파일 다운로드
|
|
34
|
+
if path.lower().startswith(('http://', 'https://')):
|
|
35
|
+
path = path.replace("\\", "/")
|
|
36
|
+
with requests.Session() as session:
|
|
37
|
+
r = session.get(path)
|
|
38
|
+
|
|
39
|
+
if r.status_code != 200:
|
|
40
|
+
raise Exception(f"HTTP {r.status_code} Error - {r.reason} > {path}")
|
|
41
|
+
|
|
42
|
+
with open(zip_path, "wb") as f:
|
|
43
|
+
f.write(r.content)
|
|
44
|
+
else:
|
|
45
|
+
zip_path = Path(path)
|
|
46
|
+
|
|
47
|
+
# 압축 해제
|
|
48
|
+
with zipfile.ZipFile(zip_path, 'r') as zip_ref:
|
|
49
|
+
zip_ref.extractall(tmp_dir)
|
|
50
|
+
|
|
51
|
+
# 압축 해제된 파일 중 첫 번째 파일을 데이터로 로드
|
|
52
|
+
extracted_files = list(tmp_dir.glob('*'))
|
|
53
|
+
if not extracted_files:
|
|
54
|
+
raise FileNotFoundError("압축 파일 내에 데이터 파일이 없습니다.")
|
|
55
|
+
|
|
56
|
+
path = str(extracted_files[0])
|
|
57
|
+
p = path.rfind(".")
|
|
58
|
+
exec = path[p+1:].lower()
|
|
59
|
+
|
|
60
|
+
# 생성된 임시 디렉토리 삭제
|
|
61
|
+
shutil.rmtree(tmp_dir)
|
|
62
|
+
|
|
63
|
+
|
|
24
64
|
if exec == 'xlsx':
|
|
25
65
|
# If path is a remote URL, fetch the file once and reuse the bytes
|
|
26
66
|
if path.lower().startswith(('http://', 'https://')):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hossam
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.9
|
|
4
4
|
Summary: Hossam Data Helper
|
|
5
5
|
Author-email: Lee Kwang-Ho <leekh4232@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -73,7 +73,7 @@ title: 🎓 Hossam Data Helper
|
|
|
73
73
|
pip install hossam
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
**요구사항**: Python 3.
|
|
76
|
+
**요구사항**: Python 3.13.9 이상
|
|
77
77
|
|
|
78
78
|
## 📚 전체 문서
|
|
79
79
|
|
|
@@ -83,9 +83,9 @@ pip install hossam
|
|
|
83
83
|
|
|
84
84
|
- **hs_plot**: 25+ 시각화 함수 (선 그래프, 산점도, 히스토그램, 박스플롯, 히트맵 등)
|
|
85
85
|
- **hs_stats**: 회귀/분류 분석, 교차검증, 정규성 검정, 상관분석 등
|
|
86
|
-
- **hs_prep**: 결측치 처리, 이상치 탐지, 스케일링, 인코딩
|
|
86
|
+
- **hs_prep**: 결측치 처리, 이상치 탐지, 스케일링, 인코딩 등의 데이터 전처리 기능
|
|
87
|
+
- **hs_timeserise**: 시계열 분석 기능 지원
|
|
87
88
|
- **hs_gis**: GIS 데이터 로드 및 시각화 (대한민국 지도 지원)
|
|
88
|
-
- **hs_classroom**: 학습용 이진분류, 다중분류, 회귀 데이터 생성
|
|
89
89
|
- **hs_util**: 예쁜 테이블 출력, 그리드 서치 등
|
|
90
90
|
|
|
91
91
|
자세한 사용법은 [API 문서](https://py.hossam.kr/api/hossam/)를 참고하세요.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|