콘텐츠로 이동

hossam.prep

hossam.prep

hs_standard_scaler

hs_standard_scaler(
    data, yname=None, save_path=None, load_path=None
)

연속형 변수에 대해 Standard Scaling을 수행한다.

  • DataFrame 입력 시: 비수치형/종속변수를 분리한 후 스케일링하고 다시 합칩니다.
  • 배열 입력 시: 그대로 스케일링된 ndarray를 반환합니다.
  • load_path가 주어지면 기존 스케일러를 재사용하고, save_path가 주어지면 학습된 스케일러를 저장합니다.

Parameters:

Name Type Description Default
data DataFrame | ndarray

스케일링할 데이터.

required
yname str | None

종속변수 컬럼명. 분리하지 않으려면 None.

None
save_path str | None

학습된 스케일러 저장 경로.

None
load_path str | None

기존 스케일러 로드 경로.

None

Returns:

Type Description
DataFrame

DataFrame | ndarray: 스케일링된 데이터(입력 타입과 동일).

Examples:

>>> from hossam.prep import hs_standard_scaler
>>> std_df = hs_standard_scaler(df, yname="y", save_path="std.pkl")
Source code in hossam/prep.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
def hs_standard_scaler(
    data: any, yname: str | None = None, save_path: str | None = None, load_path: str | None = None
) -> DataFrame:
    """연속형 변수에 대해 Standard Scaling을 수행한다.

    - DataFrame 입력 시: 비수치형/종속변수를 분리한 후 스케일링하고 다시 합칩니다.
    - 배열 입력 시: 그대로 스케일링된 ndarray를 반환합니다.
    - `load_path`가 주어지면 기존 스케일러를 재사용하고, `save_path`가 주어지면 학습된 스케일러를 저장합니다.

    Args:
        data (DataFrame | ndarray): 스케일링할 데이터.
        yname (str | None): 종속변수 컬럼명. 분리하지 않으려면 None.
        save_path (str | None): 학습된 스케일러 저장 경로.
        load_path (str | None): 기존 스케일러 로드 경로.

    Returns:
        DataFrame | ndarray: 스케일링된 데이터(입력 타입과 동일).

    Examples:
        >>> from hossam.prep import hs_standard_scaler
        >>> std_df = hs_standard_scaler(df, yname="y", save_path="std.pkl")
    """

    is_df = isinstance(data, DataFrame)

    # ndarray 처리 분기
    if not is_df:
        arr = np.asarray(data)
        if arr.ndim == 1:
            arr = arr.reshape(-1, 1)
        scaler = joblib.load(load_path) if load_path else StandardScaler()
        sdata = scaler.transform(arr) if load_path else scaler.fit_transform(arr)
        if save_path:
            joblib.dump(value=scaler, filename=save_path)
        return sdata

    df = data.copy()

    y = None
    if yname and yname in df.columns:
        y = df[yname]
        df = df.drop(columns=[yname])

    category_cols = df.select_dtypes(exclude=[np.number]).columns.tolist()
    cate = df[category_cols] if category_cols else DataFrame(index=df.index)
    X = df.drop(columns=category_cols)

    if X.shape[1] == 0:
        return data

    scaler = joblib.load(load_path) if load_path else StandardScaler()
    sdata = scaler.transform(X) if load_path else scaler.fit_transform(X)

    if save_path:
        joblib.dump(value=scaler, filename=save_path)

    std_df = DataFrame(data=sdata, index=data.index, columns=X.columns)

    if category_cols:
        std_df[category_cols] = cate
    if yname and y is not None:
        std_df[yname] = y

    return std_df

hs_minmax_scaler

hs_minmax_scaler(
    data, yname=None, save_path=None, load_path=None
)

연속형 변수에 대해 MinMax Scaling을 수행한다.

DataFrame은 비수치/종속변수를 분리 후 스케일링하고 재결합하며, 배열 입력은 그대로 ndarray를 반환한다. load_path 제공 시 기존 스케일러를 사용하고, save_path 제공 시 학습 스케일러를 저장한다.

Parameters:

Name Type Description Default
data DataFrame | ndarray

스케일링할 데이터.

required
yname str | None

종속변수 컬럼명. 분리하지 않으려면 None.

None
save_path str | None

학습된 스케일러 저장 경로.

None
load_path str | None

기존 스케일러 로드 경로.

None

Returns:

Type Description
DataFrame

DataFrame | ndarray: 스케일링된 데이터(입력 타입과 동일).

Examples:

>>> from hossam.prep import hs_minmax_scaler
>>> mm_df = hs_minmax_scaler(df, yname="y")
Source code in hossam/prep.py
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
def hs_minmax_scaler(
    data: any, yname: str | None = None, save_path: str | None = None, load_path: str | None = None
) -> DataFrame:
    """연속형 변수에 대해 MinMax Scaling을 수행한다.

    DataFrame은 비수치/종속변수를 분리 후 스케일링하고 재결합하며, 배열 입력은 그대로 ndarray를 반환한다.
    `load_path` 제공 시 기존 스케일러를 사용하고, `save_path` 제공 시 학습 스케일러를 저장한다.

    Args:
        data (DataFrame | ndarray): 스케일링할 데이터.
        yname (str | None): 종속변수 컬럼명. 분리하지 않으려면 None.
        save_path (str | None): 학습된 스케일러 저장 경로.
        load_path (str | None): 기존 스케일러 로드 경로.

    Returns:
        DataFrame | ndarray: 스케일링된 데이터(입력 타입과 동일).

    Examples:
        >>> from hossam.prep import hs_minmax_scaler
        >>> mm_df = hs_minmax_scaler(df, yname="y")
    """

    is_df = isinstance(data, DataFrame)

    if not is_df:
        arr = np.asarray(data)
        if arr.ndim == 1:
            arr = arr.reshape(-1, 1)
        scaler = joblib.load(load_path) if load_path else MinMaxScaler()
        sdata = scaler.transform(arr) if load_path else scaler.fit_transform(arr)
        if save_path:
            joblib.dump(scaler, save_path)
        return sdata

    df = data.copy()

    y = None
    if yname and yname in df.columns:
        y = df[yname]
        df = df.drop(columns=[yname])

    category_cols = df.select_dtypes(exclude=[np.number]).columns.tolist()
    cate = df[category_cols] if category_cols else DataFrame(index=df.index)
    X = df.drop(columns=category_cols)

    if X.shape[1] == 0:
        return data

    scaler = joblib.load(load_path) if load_path else MinMaxScaler()
    sdata = scaler.transform(X) if load_path else scaler.fit_transform(X)

    if save_path:
        joblib.dump(scaler, save_path)

    std_df = DataFrame(data=sdata, index=data.index, columns=X.columns)

    if category_cols:
        std_df[category_cols] = cate
    if yname and y is not None:
        std_df[yname] = y

    return std_df

hs_set_category

hs_set_category(data, *args)

카테고리 데이터를 설정한다.

Parameters:

Name Type Description Default
data DataFrame

데이터프레임 객체

required
*args str

컬럼명 목록

()

Returns:

Name Type Description
DataFrame DataFrame

카테고리 설정된 데이터프레임

Source code in hossam/prep.py
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
def hs_set_category(data: DataFrame, *args: str) -> DataFrame:
    """카테고리 데이터를 설정한다.

    Args:
        data (DataFrame): 데이터프레임 객체
        *args (str): 컬럼명 목록

    Returns:
        DataFrame: 카테고리 설정된 데이터프레임
    """
    df = data.copy()

    for k in args:
        df[k] = df[k].astype("category")

    return df

hs_unmelt

hs_unmelt(data, id_vars='class', value_vars='values')

두 개의 컬럼으로 구성된 데이터프레임에서 하나는 명목형, 나머지는 연속형일 경우 명목형 변수의 값에 따라 고유한 변수를 갖는 데이터프레임으로 변환한다.

Parameters:

Name Type Description Default
data DataFrame

데이터프레임

required
id_vars str

명목형 변수의 컬럼명. Defaults to 'class'.

'class'
value_vars str

연속형 변수의 컬럼명. Defaults to 'values'.

'values'

Returns:

Name Type Description
DataFrame DataFrame

변환된 데이터프레임

Source code in hossam/prep.py
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
def hs_unmelt(
    data: DataFrame, id_vars: str = "class", value_vars: str = "values"
) -> DataFrame:
    """두 개의 컬럼으로 구성된 데이터프레임에서 하나는 명목형, 나머지는 연속형일 경우
    명목형 변수의 값에 따라 고유한 변수를 갖는 데이터프레임으로 변환한다.

    Args:
        data (DataFrame): 데이터프레임
        id_vars (str, optional): 명목형 변수의 컬럼명. Defaults to 'class'.
        value_vars (str, optional): 연속형 변수의 컬럼명. Defaults to 'values'.

    Returns:
        DataFrame: 변환된 데이터프레임
    """
    result = data.groupby(id_vars)[value_vars].apply(list)
    mydict = {}

    for i in result.index:
        mydict[i] = result[i]

    return DataFrame(mydict)

hs_replace_missing_value

hs_replace_missing_value(data, strategy='mean')

SimpleImputer로 결측치를 대체한다.

Parameters:

Name Type Description Default
data DataFrame

결측치가 포함된 데이터프레임

required
strategy str

결측치 대체 방식(mean, median, most_frequent, constant). Defaults to "mean".

'mean'

Returns:

Name Type Description
DataFrame DataFrame

결측치가 대체된 데이터프레임

Examples:

>>> from hossam.prep import hs_replace_missing_value
>>> out = hs_replace_missing_value(df.select_dtypes(include="number"), strategy="median")
Source code in hossam/prep.py
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
def hs_replace_missing_value(data: DataFrame, strategy: str = "mean") -> DataFrame:
    """SimpleImputer로 결측치를 대체한다.

    Args:
        data (DataFrame): 결측치가 포함된 데이터프레임
        strategy (str, optional): 결측치 대체 방식(mean, median, most_frequent, constant). Defaults to "mean".

    Returns:
        DataFrame: 결측치가 대체된 데이터프레임

    Examples:
        >>> from hossam.prep import hs_replace_missing_value
        >>> out = hs_replace_missing_value(df.select_dtypes(include="number"), strategy="median")
    """

    allowed = {"mean", "median", "most_frequent", "constant"}
    if strategy not in allowed:
        raise ValueError(f"strategy는 {allowed} 중 하나여야 합니다.")

    imr = SimpleImputer(missing_values=np.nan, strategy=strategy)
    df_imr = imr.fit_transform(data.values)
    return DataFrame(df_imr, index=data.index, columns=data.columns)

hs_outlier_table

hs_outlier_table(data, *fields)

수치형 컬럼에 대한 사분위수 및 IQR 기반 이상치 경계를 계산한다.

전달된 fields가 없으면 데이터프레임의 모든 수치형 컬럼을 대상으로 한다. 결측치는 제외하고 사분위수를 계산한다.

Parameters:

Name Type Description Default
data DataFrame

분석할 데이터프레임.

required
*fields str

대상 컬럼명(들). 생략 시 모든 수치형 컬럼 대상.

()

Returns:

Name Type Description
DataFrame DataFrame

Q1, Q2(중앙값), Q3, IQR, 하한, 상한을 포함한 통계표.

Examples:

>>> from hossam.prep import hs_outlier_table
>>> hs_outlier_table(df, "value")
Source code in hossam/prep.py
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
def hs_outlier_table(data: DataFrame, *fields: str) -> DataFrame:
    """수치형 컬럼에 대한 사분위수 및 IQR 기반 이상치 경계를 계산한다.

    전달된 `fields`가 없으면 데이터프레임의 모든 수치형 컬럼을 대상으로 한다.
    결측치는 제외하고 사분위수를 계산한다.

    Args:
        data (DataFrame): 분석할 데이터프레임.
        *fields (str): 대상 컬럼명(들). 생략 시 모든 수치형 컬럼 대상.

    Returns:
        DataFrame: Q1, Q2(중앙값), Q3, IQR, 하한, 상한을 포함한 통계표.

    Examples:
        >>> from hossam.prep import hs_outlier_table
        >>> hs_outlier_table(df, "value")
    """

    target_fields = list(fields) if fields else list(data.select_dtypes(include=[np.number]).columns)
    result = []
    for f in target_fields:
        if f not in data.columns:
            continue

        series = data[f].dropna()
        if series.empty:
            continue

        q1 = series.quantile(q=0.25)
        q2 = series.quantile(q=0.5)
        q3 = series.quantile(q=0.75)

        iqr = q3 - q1
        down = q1 - 1.5 * iqr
        up = q3 + 1.5 * iqr

        result.append(
            {
                "FIELD": f,
                "Q1": q1,
                "Q2": q2,
                "Q3": q3,
                "IQR": iqr,
                "UP": up,
                "DOWN": down,
            }
        )

    return DataFrame(result).set_index("FIELD") if result else DataFrame()

hs_replace_outliner

hs_replace_outliner(data, method='nan', *fields)

이상치 경계값을 넘어가는 데이터를 경계값으로 대체한다.

Parameters:

Name Type Description Default
data DataFrame

데이터프레임

required
method str

대체 방법 - nan: 결측치 대체 - outline: 경계값 대체 - mean: 평균 대체 - most: 최빈값 대체 - median: 중앙값 대체

'nan'
*fields str

컬럼명 목록

()

Returns:

Name Type Description
DataFrame DataFrame

이상치가 경계값으로 대체된 데이터 프레임

Source code in hossam/prep.py
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
def hs_replace_outliner(data: DataFrame, method: str = "nan", *fields: str) -> DataFrame:
    """이상치 경계값을 넘어가는 데이터를 경계값으로 대체한다.

    Args:
        data (DataFrame): 데이터프레임
        method (str): 대체 방법
            - nan: 결측치 대체
            - outline: 경계값 대체
            - mean: 평균 대체
            - most: 최빈값 대체
            - median: 중앙값 대체
        *fields (str): 컬럼명 목록

    Returns:
        DataFrame: 이상치가 경계값으로 대체된 데이터 프레임
    """

    # 원본 데이터 프레임 복사
    df = data.copy()

    # 카테고리 타입만 골라냄
    category_fields = []
    for f in df.columns:
        if df[f].dtypes not in ["int", "int32", "int64", "float", "float32", "float64"]:
            category_fields.append(f)

    cate = df[category_fields]
    df = df.drop(category_fields, axis=1)

    # 이상치 경계값을 구한다.
    outliner_table = hs_outlier_table(df, *fields)

    if outliner_table.empty:
        return data.copy()

    # 이상치가 발견된 필드에 대해서만 처리
    for f in outliner_table.index:
        if method == "outline":
            df.loc[df[f] < outliner_table.loc[f, "DOWN"], f] = outliner_table.loc[f, "DOWN"]
            df.loc[df[f] > outliner_table.loc[f, "UP"], f] = outliner_table.loc[f, "UP"]
        else:
            df.loc[df[f] < outliner_table.loc[f, "DOWN"], f] = np.nan
            df.loc[df[f] > outliner_table.loc[f, "UP"], f] = np.nan

    # NaN으로 표시된 이상치를 지정한 방법으로 대체
    if method in {"mean", "median", "most"}:
        strategy_map = {"mean": "mean", "median": "median", "most": "most_frequent"}
        imr = SimpleImputer(missing_values=np.nan, strategy=strategy_map[method])
        df_imr = imr.fit_transform(df.values)
        df = DataFrame(df_imr, index=data.index, columns=df.columns)
    elif method not in {"nan", "outline"}:
        raise ValueError("method는 'nan', 'outline', 'mean', 'median', 'most' 중 하나여야 합니다.")

    # 분리했던 카테고리 타입을 다시 병합
    if category_fields:
        df[category_fields] = cate

    return df

hs_drop_outliner

hs_drop_outliner(data, *fields)

이상치를 결측치로 변환한 후 모두 삭제한다.

Parameters:

Name Type Description Default
data DataFrame

데이터프레임

required
*fields str

컬럼명 목록

()

Returns:

Name Type Description
DataFrame DataFrame

이상치가 삭제된 데이터프레임

Source code in hossam/prep.py
327
328
329
330
331
332
333
334
335
336
337
338
339
def hs_drop_outliner(data: DataFrame, *fields: str) -> DataFrame:
    """이상치를 결측치로 변환한 후 모두 삭제한다.

    Args:
        data (DataFrame): 데이터프레임
        *fields (str): 컬럼명 목록

    Returns:
        DataFrame: 이상치가 삭제된 데이터프레임
    """

    df = hs_replace_outliner(data, "nan", *fields)
    return df.dropna()

hs_dummies

hs_dummies(data, drop_first=True, dtype='int', *args)

명목형 변수를 더미 변수로 변환한다.

Parameters:

Name Type Description Default
data DataFrame

데이터프레임

required
*args str

명목형 컬럼 목록

()

Returns:

Name Type Description
DataFrame DataFrame

더미 변수로 변환된 데이터프레임

Source code in hossam/prep.py
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
def hs_dummies(data: DataFrame, drop_first=True, dtype="int", *args: str) -> DataFrame:
    """명목형 변수를 더미 변수로 변환한다.

    Args:
        data (DataFrame): 데이터프레임
        *args (str): 명목형 컬럼 목록

    Returns:
        DataFrame: 더미 변수로 변환된 데이터프레임
    """
    if not args:
        args = []

        for f in data.columns:
            if data[f].dtypes == "category":
                args.append(f)
    else:
        args = list(args)

    return get_dummies(data, columns=args, drop_first=drop_first, dtype=dtype)

hs_labelling

hs_labelling(data, *fields)

명목형 변수를 라벨링한다.

Parameters:

Name Type Description Default
data DataFrame

데이터프레임

required
*fields str

명목형 컬럼 목록

()

Returns:

Name Type Description
DataFrame DataFrame

라벨링된 데이터프레임

Source code in hossam/prep.py
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
def hs_labelling(data: DataFrame, *fields: str) -> DataFrame:
    """명목형 변수를 라벨링한다.

    Args:
        data (DataFrame): 데이터프레임
        *fields (str): 명목형 컬럼 목록

    Returns:
        DataFrame: 라벨링된 데이터프레임
    """
    df = data.copy()

    for f in fields:
        vc = sorted(list(df[f].unique()))
        label = {v: i for i, v in enumerate(vc)}
        df[f] = df[f].map(label).astype("int")

        # 라벨링 상황을 출력한다.
        i = []
        v = []
        for k in label:
            i.append(k)
            v.append(label[k])

        label_df = DataFrame({"label": v}, index=i)
        label_df.index.name = f
        hs_pretty_table(label_df)

    return df