Spaces:
Paused
Paused
| import pandas as pd, numpy as np | |
| def add_time_features(df, date_col): | |
| """ | |
| [๋ฌด์์ ํ๋์?] | |
| - ๋ ์ง ์ด(date_col)์์ '์ฐ๋/์/์ผ/์์ผ/๋ช ์ฃผ์ฐจ/์ฃผ๋ง ์ฌ๋ถ' ๊ฐ์ | |
| ์ฌ์ด ๋ฌ๋ ฅ ์ ๋ณด๋ฅผ ๋ฝ์ ํ์(๋ฐ์ดํฐํ๋ ์์) ๋ถ์ฌ์ค์. | |
| [์ ํ์ํ์ฃ ?] | |
| - ๊ธฐ๊ณ๋ '2025-01-15' ๊ฐ์ ๋ ์ง ๊ธ์๋ฅผ ์ ๋ชป ์ดํดํด์. | |
| ๋์ '2025๋ ', '1์', '15์ผ', '์์์ผ', '3์ฃผ์ฐจ' ์ฒ๋ผ ์ซ์ ์ ๋ณด๊ฐ ์์ผ๋ฉด | |
| ๊ท์น(๊ณ์ /์์ผ ํจํด)์ ๋ ์ ๋ฐฐ์ธ ์ ์์ด์. | |
| [์ ๋ ฅ] | |
| - df: ์๋ ๋ฐ์ดํฐ ํ (DataFrame) | |
| - date_col: ๋ ์ง๊ฐ ๋ค์ด์๋ ์ด ์ด๋ฆ (์: 'date') | |
| [์ถ๋ ฅ] | |
| - ๋ฌ๋ ฅ ์ ๋ณด ์ด์ด ์ถ๊ฐ๋ ์ ํ (์๋ณธ์ ๊ฑด๋๋ฆฌ์ง ์์์) | |
| """ | |
| df = df.copy() # ์๋ณธ์ ๋ง๊ฐ๋จ๋ฆฌ์ง ์์ผ๋ ค๊ณ ๋ณต์ฌ๋ณธ์ ๋ง๋ค์ด์. | |
| # ๋ ์ง ๊ธ์๋ฅผ ์ง์ง '๋ ์ง'๋ก ๋ฐ๊ฟ์. ์ด์ํ ๊ฐ์ NaT(๋น์ด์์)๋ก ์ฒ๋ฆฌ. | |
| df[date_col] = pd.to_datetime(df[date_col], errors="coerce") | |
| # ๋ ์ง๊ฐ ๋น์ด์๋ ํ์ ๊ณ์ฐ์ด ์ ๋๋ ๋นผ๊ณ , ๋ ์ง์์ผ๋ก ์ ๋ ฌํด์. | |
| df = df.dropna(subset=[date_col]).sort_values(date_col) | |
| # ๋ฌ๋ ฅ์์ ๋ฐ๋ก ๊บผ๋ผ ์ ์๋ ์ ๋ณด๋ค์ ์ ์ด๋ก ๋ง๋ค์ด์. | |
| df["year"] = df[date_col].dt.year # ๋ช ๋ ๋์ธ์ง | |
| df["month"] = df[date_col].dt.month # ๋ช ์์ธ์ง(1~12) | |
| df["day"] = df[date_col].dt.day # ๋ฉฐ์น ์ธ์ง(1~31) | |
| df["dow"] = df[date_col].dt.dayofweek # ์์ผ(์=0 ... ์ผ=6) | |
| # '๋ช ์ฃผ์ฐจ'๋ ISO ๋ฌ๋ ฅ ๊ธฐ์ค์ด์์. ์: 1์์ ์ฒซ ์ฃผ๊ฐ 1์ด ์๋๋ผ 52์ผ ์๋ ์์ด์. | |
| df["week"] = df[date_col].dt.isocalendar().week.astype(int) | |
| # ํ /์ผ์ด๋ฉด ์ฃผ๋ง(1), ์๋๋ฉด 0 | |
| df["is_weekend"] = (df["dow"]>=5).astype(int) | |
| return df | |
| def add_lag_features(df, date_col, target_col, group_keys=None, lags=(1,7,14), rolls=(7,14)): | |
| """ | |
| [๋ฌด์์ ํ๋์?] | |
| - '์ด์ /์ผ์ฃผ์ผ ์ /๋ณด๋ฆ ์ ' ๊ฐ์ ๊ณผ๊ฑฐ ๊ฐ(=์ง์ฐ๊ฐ, lag)์ ๋ง๋ค์ด์ ๋ถ์ด๊ณ , | |
| ์ต๊ทผ 7์ผ/14์ผ์ ํ๊ท ยทํ์คํธ์ฐจ(ํ๋ค๋ฆผ)๋ ๊ฐ์ด ๋ถ์ฌ์ค์. | |
| [์ ํ์ํ์ฃ ?] | |
| - ์์๋ ์ด์ /์ง๋์ฃผ์ ๋น์ทํ๊ฒ ์์ง์ด๋ ๊ฒฝํฅ์ด ์์ด์. | |
| ๊ณผ๊ฑฐ ๊ฐ์ ํํธ๋ก ์ฃผ๋ฉด '๋ด์ผ'์ ๋ง์ถ๊ธฐ ์ฌ์์ ธ์. | |
| - lag7: 7์ผ ์ ๊ฐ โ '์ง๋์ฃผ ๊ฐ์ ์์ผ'์ ํํธ | |
| - rmean7: ์ต๊ทผ 7์ผ ํ๊ท โ ์ต๊ทผ ํ๋ฆ(ํ๊ท ) | |
| - rstd7: ์ต๊ทผ 7์ผ ํ๋ค๋ฆผ(ํ์คํธ์ฐจ) โ ๋ณ๋์ฑ ํฌ๊ธฐ | |
| [group_keys๊ฐ ๋ญ์ฃ ?] | |
| - ์ ํฌ/๋ธ๋๋/์ํ๋ง๋ค ๋ฐ๋ก ๊ณผ๊ฑฐ๋ฅผ ๋ณด๋ผ๊ณ ์ง์ ํ๋ ์ด๋ค์ด์์. | |
| ์) ["region", "item"]์ด๋ฉด ์ง์ญ+์ํ๋ณ๋ก ๊ฐ๊ฐ ์ด์ /์ง๋์ฃผ๋ฅผ ๊ณ์ฐํด์. | |
| (๊ทธ๋ฃน ์์ด ํต์ผ๋ก ๊ณ์ฐํ๋ฉด ์๋ก ๋ค๋ฅธ ์ ํฌ/์ํ์ ๊ฐ์ด ์์ฌ์ ์๋ฏธ๊ฐ ํ๋ ค์ง ์ ์์ด์.) | |
| [์ ๋ ฅ] | |
| - df: ํ | |
| - date_col: ๋ ์ง ์ด ์ด๋ฆ | |
| - target_col: ๋ง์ถ๊ณ ์ถ์ ์ซ์(ํ๋งค๋ ๋ฑ) ์ด | |
| - group_keys: ๊ทธ๋ฃนํํ ์ด ๋ชฉ๋ก(์์ด๋ ๋จ) | |
| - lags: ๋ง๋ค lag ๋ชฉ๋ก(๊ธฐ๋ณธ 1, 7, 14) | |
| - rolls: ๊ตด๋ฆฌ๋ ์ฐฝ ํฌ๊ธฐ(rolling window) ๋ชฉ๋ก(๊ธฐ๋ณธ 7, 14) | |
| [์ถ๋ ฅ] | |
| - lag/rmean/rstd ์ด์ด ์ถ๊ฐ๋ ํ(๋ ์ง์) | |
| """ | |
| df = df.copy() | |
| # group_keys ์ค ํ์ ์ค์ ๋ก ์กด์ฌํ๋ ๊ฒ๋ง ๋จ๊ฒจ์. | |
| group_keys = [c for c in (group_keys or []) if c in df.columns] | |
| # ๊ทธ๋ฃน์ด ์์ผ๋ฉด ๊ทธ๋ฃน๋ณ๋ก, ์์ผ๋ฉด ์ ์ฒด๋ฅผ ํ๋์ ๊ทธ๋ฃน์ฒ๋ผ ์ฒ๋ฆฌํด์. | |
| if group_keys: | |
| g = df.groupby(group_keys, group_keys=False) # group_keys=False: ํค๋ฅผ ์ธ๋ฑ์ค๋ก ์ฌ๋ฆฌ์ง ๋ง๊ธฐ | |
| else: | |
| g = [(None, df)] # '๊ทธ๋ฃน์ด ํ๋'๋ผ๊ณ ๊ฐ์ ํ ๋ฆฌ์คํธ. ์๋ for๋ฌธ๊ณผ ํธํ๋๊ฒ ๋ง๋ค์ด์. | |
| out = [] # ๊ทธ๋ฃน๋ณ๋ก ์ฒ๋ฆฌํ ๊ฒฐ๊ณผ๋ฅผ ๋ชจ์๋ ๋ค, ๋ง์ง๋ง์ ํฉ์ณ์. | |
| # pandas์ groupby๋ (ํค, ๋ถ๋ถํ) ํํ๋ก ๋ฐ๋ณต๋ฉ๋๋ค. | |
| # ์์์ g๋ฅผ ๋ฆฌ์คํธ๋ก ๋ง์ถฐ์คฌ๊ธฐ ๋๋ฌธ์ ๋ ๋ชจ๋ ๊ฐ์ ๋ฐฉ์์ผ๋ก ์ํ ๊ฐ๋ฅํด์. | |
| for _, part in (g if isinstance(g, list) else g): | |
| part = part.sort_values(date_col).copy() # ๋ ์ง์์ผ๋ก ์ ๋ ฌ | |
| # (1) lag ์ด๋ค ๋ง๋ค๊ธฐ: ์) lag1(์ด์ ), lag7(์ง๋์ฃผ), lag14(๋ณด๋ฆ ์ ) | |
| for l in lags: | |
| part[f"lag{l}"] = part[target_col].shift(l) | |
| # shift(l)์ ์์์ l์นธ ๋ฐ์ด์. ์ค๋ ํ์๋ 'l์ผ ์ ๊ฐ'์ด ๋ค์ด๊ฐ. | |
| # (2) rolling ํ๊ท /ํ์คํธ์ฐจ: ์ต๊ทผ w์ผ ํ๊ท /ํ๋ค๋ฆผ | |
| for w in rolls: | |
| # min_periods๋ฅผ w์ ์ ๋ฐ ์ด์(์ต์ 2)์ผ๋ก ์ค์ | |
| # ์ด๋ฐ๋ถ ๋ฐ์ดํฐ๊ฐ ๋๋ฌด ์์ ๋๋ ๊ฐ์ด ์กฐ๊ธ์ด๋ผ๋ ๋์ค๋๋ก ๋ฐฐ๋ ค. | |
| part[f"rmean{w}"] = part[target_col].rolling(w, min_periods=max(2, w//2)).mean() | |
| part[f"rstd{w}"] = part[target_col].rolling(w, min_periods=max(2, w//2)).std() | |
| out.append(part) | |
| # ๊ทธ๋ฃน๋ณ๋ก ๋ง๋ ํ๋ค์ ์์๋๋ก ์ด์ด๋ถ์ด๊ณ , ๋ค์ ๋ ์ง์ ์ ๋ ฌ | |
| return pd.concat(out, axis=0).sort_values(date_col) | |
| def make_matrix(df, mapping): | |
| """ | |
| [๋ฌด์์ ํ๋์?] | |
| - ๋ชจ๋ธ ํ์ต์ฉ '์ ๋ ฅ X'์ '์ ๋ต y'๋ฅผ ๋ง๋๋ ๊ณต์ฅ์ ๋๋ค. | |
| 1) ๋ ์ง/ํ๊น ์ด ์ด๋ฆ์ mapping์์ ์ฝ๊ณ , | |
| 2) add_time_features / add_lag_features๋ก ์ซ์ ํํธ๋ฅผ ์ถ๊ฐํ๊ณ , | |
| 3) (์๋ค๋ฉด) region/brand/item์ '์-ํซ ์ธ์ฝ๋ฉ(๊ฐ์ง ์ด)'์ผ๋ก ๋ฐ๊ฟ์ X์ ๋ถ์ฌ์. | |
| 4) y๋ ํ๊น ๊ฐ(ํ๋งค๋ ๋ฑ)์ผ๋ก ์ค์ ํด์. | |
| [์ ๋ ฅ] | |
| - df: ์๋ณธ ํ | |
| - mapping: {'date':..., 'target':..., 'region':..., 'brand':..., 'item':...} | |
| (region/brand/item์ ์์ด๋ ๋จ) | |
| [์ถ๋ ฅ] | |
| - df: ํผ์ฒ๊ฐ ๋ถ์ ํ(์ด๊ธฐ lag๋ก NaN์ธ ๋งจ ์๋ถ๋ถ์ ์ ๊ฑฐ๋จ) | |
| - X: ๋ชจ๋ธ์ ๋ค์ด๊ฐ ์ซ์ ๋ฐฐ์ด(2์ฐจ์) | |
| - y: ์ ๋ต ๋ฒกํฐ(1์ฐจ์) | |
| - feat_names: X์ ์ด ์ด๋ฆ ๋ชฉ๋ก(๋ชจ๋ธ ํด์/์ฌํ์ ํ์) | |
| """ | |
| df = df.copy() | |
| # ๋งคํ์์ ์ด ์ด๋ฆ ๊บผ๋ด์ค๊ธฐ | |
| date_col = mapping.get("date") | |
| target_col = mapping.get("target") | |
| region_col = mapping.get("region") | |
| brand_col = mapping.get("brand") | |
| item_col = mapping.get("item") | |
| # ๋ ์ง/ํ๊น์ ํ์! ์์ผ๋ฉด ์งํ ๋ชป ํด์. | |
| if not date_col or not target_col: | |
| raise ValueError("date/target ์ปฌ๋ผ ๋งคํ์ด ํ์ํฉ๋๋ค.") | |
| # --- (1) ์ซ์ํ ์ ๋ฆฌ --- | |
| # ํ๊น์ ๋ฐ๋์ ์ซ์์ฌ์ผ ํด์. ๊ธ์๊ฐ ์์ฌ ์์ผ๋ฉด NaN์ผ๋ก ๋ฐ๋ โ 0์ผ๋ก ์ฑ์. | |
| df[target_col] = pd.to_numeric(df[target_col], errors="coerce").fillna(0) | |
| # (์ ํ) ๋ถ๋ฅํ ์ด๋ค์ ๊ธ์(๋ฌธ์์ด)๋ก ํต์ผํด์. | |
| # ์ด๋ ๊ฒ ํด์ผ '์-ํซ ์ธ์ฝ๋ฉ'์ด ์ ๋ฉ๋๋ค. | |
| if region_col and region_col in df: df[region_col] = df[region_col].astype(str) | |
| if brand_col and brand_col in df: df[brand_col] = df[brand_col].astype(str) | |
| if item_col and item_col in df: df[item_col] = df[item_col].astype(str) | |
| # --- (2) ๋ฌ๋ ฅ ํผ์ฒ ๋ถ์ด๊ธฐ --- | |
| df = add_time_features(df, date_col) | |
| # --- (3) ๊ณผ๊ฑฐ/์ต๊ทผ ํต๊ณ ํผ์ฒ ๋ถ์ด๊ธฐ --- | |
| # ๊ทธ๋ฃนํค: ์กด์ฌํ๋ ๊ฒ๋ง ์ฌ์ฉ (์: ['region','brand','item'] ์ค ์ค์ ์๋ ์ด๋ง) | |
| df = add_lag_features( | |
| df, date_col, target_col, | |
| [c for c in [region_col, brand_col, item_col] if c] | |
| ) | |
| # --- (4) lag/rolling ๋๋ฌธ์ ์๋ถ๋ถ์ ์๊ธด ๋น์ด์๋ ํ ์ ๊ฑฐ --- | |
| # ์ฒซ ๋ช ํ์ lag1/lag7 ๊ฐ์ ๊ฒ ์ฑ์ธ ์ ์์ด์ NaN์ด ๋ผ์ โ ํ์ต์ ๋ชป ์ฐ๋ ์ ๊ฑฐ. | |
| drop_cols = [c for c in df.columns if c.startswith("lag") or c.startswith("rmean") or c.startswith("rstd")] | |
| df = df.dropna(subset=drop_cols) | |
| # --- (5) ์ซ์ ํผ์ฒ ๋ชฉ๋ก ๋ง๋ค๊ธฐ --- | |
| # ๋ฌ๋ ฅ ์ซ์ + lag/rolling ์ซ์๋ค์ ๋ชจ์์ X์ ๊ธฐ๋ณธ ๋ผ๋๋ฅผ ๋ง๋ค์ด์. | |
| num_cols = ["year","month","day","dow","week","is_weekend"] + drop_cols | |
| num_cols = [c for c in num_cols if c in df.columns] # ํน์ ๋น ์ง ๊ฒ ์์ผ๋ฉด ๊ฑธ๋ฌ์ค | |
| # ์ซ์ ํผ์ฒ๋ฅผ ๋จผ์ ํ๋ ฌ๋ก ๋ณํ | |
| X_num = df[num_cols].values | |
| feat_names = list(num_cols) # ๋์ค์ ํด์/์ฌํํ ๋ ํ์ | |
| # --- (6) ๋ถ๋ฅํ(๋ฌธ์) โ ์-ํซ ์ธ์ฝ๋ฉ --- | |
| # ์: region์ด '์์ธ','๊ฒฝ๊ธฐ'๋ฉด 'region_์์ธ','region_๊ฒฝ๊ธฐ' ๊ฐ์ ๊ฐ์ง ์ด์ ๋ง๋ค์ด์(0/1) | |
| cat_cols = [c for c in [region_col, brand_col, item_col] if c and c in df.columns] | |
| if cat_cols: | |
| dummies = pd.get_dummies(df[cat_cols].astype(str), dummy_na=False) | |
| # ์ซ์ ํผ์ฒ(X_num) ์ค๋ฅธ์ชฝ์ ์-ํซ ํผ์ฒ๋ฅผ ๋ถ์ฌ์. | |
| X = np.hstack([X_num, dummies.values]) | |
| feat_names += list(dummies.columns) # ์๋ก ์๊ธด ์ด ์ด๋ฆ๋ ๊ธฐ๋ก | |
| else: | |
| X = X_num # ๋ถ๋ฅํ์ด ์์ผ๋ฉด ์ซ์๋ง ์ฌ์ฉ | |
| # --- (7) ์ ๋ต y ๋ง๋ค๊ธฐ --- | |
| y = df[target_col].values # ์ฐ๋ฆฌ๊ฐ ๋ง์ถ๊ณ ์ถ์ ๊ฐ(์: ํ๋งค๋) | |
| return df, X, y, feat_names | |