반응형
제로베이스 데이터 분석 스쿨 내용에 대한 기록이다.
28번째는 개인 프로젝트 내용이다.
일주일 동안은 강의는 잠시 멈춰두고 개인 프로젝트를 왕창 했다.
산업군별 10개의 프로젝트를 진행했고 실전 감각을 익혔다.
실전 분석에 사용할 베이스라인을 세우고 감을 익혔다.
과정에서 아주 만족스러운 부분 중 하나이다.
[분석 코드 baseline]
[데이터 전처리 4단계]
- 데이터 형태 확인
- df.shape
- 데이터 타입 확인
- df.info()
- 숫자로 보이는데 문자인 경우 확인
- 문자로 보이는데 숫자인 경우 확인
- object 타입(스트링) 확인
- 인트 플롯 확인
- NULL 값 확인
- df.isnull().sum()
- outlier 확인
- df.describe()
- 특히 min, max에 음수값 있는지 확인
- 도메인 지식 기반으로 처리
[EDA baseline]
- 데이터 유형 분리
cols_categorical = df.select_dtypes(include=object).columns cols_numerical = df.select_dtypes(exclude=object).columns
- Boolian 처리
-
cols_bool = ['col1'] for col in cols_bool: cols_numerical = cols_numerical.drop(col) cols_categorical = cols_categorical.append(pd.Index([col]))
-
- categorical
- 구성 비율 테이블(카운트)
-
[print(f'{col}: {df[col].nunique()}') for col in cols_categorical] for col in cols_categorical: print(f'-'*50) print(f'##### {col} Distribution #####') labels = df[col].unique() cnts = [(df[col] == label).sum() for label in labels] table = pd.DataFrame({col: labels, 'Count': cnts}) table['Ratio'] = table['Count'] / table['Count'].sum() * 100 table = table.sort_values(by='Ratio', ascending=False).reset_index(drop=True) # head(10) styled_table = table.style.background_gradient(subset=['Ratio'], cmap='Blues').format({'Ratio': '{:.2f}%'}) display(styled_table) print(f'-'*50)
-
- 구성 비율 테이블(y 집계)
-
for col in cols_categorical: print(f'-'*50) print(f'##### {col} Distribution #####') df_temp = df.groupby(col).agg({'y': 'sum'}) df_temp['Ratio'] = df_temp['y'] / df_temp['y'].sum() * 100 table = df_temp.sort_values(by='Ratio', ascending=False) # head(10) styled_table = table.style.background_gradient(subset=['Ratio'], cmap='Blues').format({'Ratio': '{:.2f}%'}) display(styled_table) print(f'-'*50)
-
- 바 플랏
- y가 연속형
-
plt.style.use(['dark_background']) for col in cols_categorical: print(f'-'*50) print(f'##### {col} Distribution #####') sns.barplot(x=col, y="y", data=df, color="skyblue", edgecolor=".6", label="Sales") plt.gcf().set_size_inches(25, 3) plt.xticks(fontsize=16) plt.legend() plt.show() print(f'-'*50)
-
- y가 이산형
-
plt.style.use(['dark_background']) for col in cols_categorical: print(f'-'*50) print(f'##### {col} Distribution #####') sns.catplot(x=col, hue="y", data=df, kind="count", palette="pastel", edgecolor=".6") plt.gcf().set_size_inches(25, 3) plt.xticks(fontsize=16) plt.legend() plt.show() print(f'-'*50)
-
- y가 연속형
- 구성 비율 테이블(카운트)
- numerical
- 상관계수 히트맵
-
plt.style.use(['seaborn']) sns.heatmap(df[cols_numerical].corr(), annot=True, cmap='coolwarm', fmt='.2f', linewidths=0.5) plt.show()
-
- 히스토그램
-
plt.style.use(['seaborn']) for col in cols_numerical: print(f'-'*50) print(f'##### {col} Histogram #####') sns.histplot(df[col], bins=20, alpha=0.5) plt.xlabel(col) plt.ylabel('Frequency') plt.grid(axis='y', alpha=0.75) plt.show() print(f'-'*50)
-
- 산점도
- y가 연속형
-
plt.style.use(['seaborn']) for col in cols_numerical: print(f'-'*50) print(f'##### {col} Scatter #####') sns.scatterplot(x=col, y='y', data=df) plt.show() print(f'-'*50)
-
- y가 이산형
-
plt.style.use(['seaborn']) print(f'-'*50) cols = ['y'] + cols_numerical sns.pairplot(df[cols], hue='y') plt.show() print(f'-'*50)
-
- y가 연속형
- 라인 그래프
- y가 연속형
- (불가능, 선이 꼬인다.)
- y가 이산형
-
plt.style.use(['seaborn']) for col in cols_numerical: print(f'-'*50) print(f'##### {col} Line #####') df_temp = df.groupby(['y', col]).size().unstack() df_temp.T.plot() plt.ylabel(f"Cnt of {col}") plt.xlabel(col) plt.grid(True) plt.legend(title='y') plt.show() print(f'-'*50)
-
- y가 연속형
- 상관계수 히트맵
- 시계열
- categorical
- 라인 그래프 (카운트, y 집계)
-
df['Date_1'] = df["Date"].dt.strftime("%Y-%m") plt.style.use(['seaborn']) for col in cols_categorical: print(f'-'*50) print(f'##### {col} Line #####') df_temp = pd.DataFrame(df.groupby([col, 'Date_1'], as_index=False)['UniqueID'].count()) # sum, mean sns.lineplot(x='Date_1', y='UniqueID', hue=col, data = df_temp) plt.xticks(rotation=90) plt.show() print(f'-'*50)
-
- 히스토그램 (카운트, y 집계)
-
df['Date_1'] = df["Date"].dt.strftime("%Y-%m") plt.style.use(['seaborn']) for col in cols_categorical: print(f'-'*50) print(f'##### {col} Line #####') df_temp = pd.DataFrame(df.groupby([col, 'Date_1'], as_index=False)['UniqueID'].count()) # sum, mean sns.barplot(x='Date_1', y='UniqueID', hue=col, data = df_temp) plt.xticks(rotation=90) plt.show() print(f'-'*50)
-
- 라인 그래프 (카운트, y 집계)
- numerical
- 라인 그래프 (값 그대로)
-
df['Date_1'] = df["Date"].dt.strftime("%Y-%m") plt.style.use(['seaborn']) for col in cols_numerical: print(f'-'*50) print(f'##### {col} Line #####') plt.plot(df['Date_1'], df[col]) plt.xlabel('Date_1') plt.ylabel(col) plt.show() print(f'-'*50)
-
- 라인 그래프 (y랑 같이 보기)
-
df['Date_1'] = df["Date"].dt.strftime("%Y-%m") plt.style.use(['seaborn']) for col in cols_numerical: print(f'-'*50) print(f'##### {col} Line #####') fig, ax1 = plt.subplots() ax1.plot(df['Date'], df['y'], color='blue') ax2 = ax1.twinx() ax2.plot(df['Date'], df[col], color='red') fig.legend() plt.show() print(f'-'*50)
-
- 라인 그래프 (값 그대로)
- 연별 월별 히스토그램
-
df['Date_year'] = df["Date"].dt.strftime("%Y") df['Date_month'] = df["Date"].dt.strftime("%m") plt.style.use(['seaborn']) df_temp = pd.DataFrame(df.groupby(['Date_year', 'Date_month'], as_index=False)['UniqueID'].count()) sns.barplot(x='Date_month', y='UniqueID', hue='Date_year', data = df_temp) plt.show()
-
- 히트맵
-
df['Date_year'] = df["Date"].dt.strftime("%Y") df['Date_month'] = df["Date"].dt.strftime("%m") df_pivot = df.pivot_table(index='Date_month', columns='Date_year', values='CPI') sns.heatmap(df_pivot, cmap="Blues", cbar=True) plt.show()
-
- categorical
[머신러닝 baseline]
- 모델링
- 분류
-
from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder from sklearn.ensemble import RandomForestClassifier df_temp = df.copy() X = df_temp.drop('y', axis=1) Y = df_temp['y'] cols_drop = ['id'] for col in cols_drop: X.drop(col, axis=1, inplace=True) cols_date = ['date_1', 'date_2'] for col in cols_date: X[f'week_{col}'] = X[col].dt.dayofweek X[f'month_{col}'] = X[col].dt.month X[col] = pd.to_datetime(X[col]).astype(int) / 10**9 for column in X.columns: if X[column].dtype == object: le = LabelEncoder() X[column] = le.fit_transform(X[column]) x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.2, stratify=Y) model = RandomForestClassifier(random_state=42) model.fit(x_train, y_train)
-
- 회귀
-
from sklearn.model_selection import train_test_split from sklearn.preprocessing import LabelEncoder from sklearn.ensemble import RandomForestClassifier df_temp = df.copy() X = df_temp.drop('y', axis=1) Y = df_temp['y'] cols_drop = ['id'] for col in cols_drop: X.drop(col, axis=1, inplace=True) cols_date = ['date_1', 'date_2'] for col in cols_date: X[f'week_{col}'] = X[col].dt.dayofweek X[f'month_{col}'] = X[col].dt.month X[col] = pd.to_datetime(X[col]).astype(int) / 10**9 for column in X.columns: if X[column].dtype == object: le = LabelEncoder() X[column] = le.fit_transform(X[column]) x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.2) model = RandomForestRegressor(n_estimators=500, max_depth=4, random_state=42) model.fit(x_train, y_train)
-
- 분류
- 평가
- 분류
- acc
-
from sklearn.metrics import accuracy_score y_pred_test = model.predict(x_test) accuracy = accuracy_score(y_test, y_pred_test) print(f"Accuracy: {accuracy*100:.2f}%")
-
- report
-
from sklearn.metrics import classification_report y_pred_train = model.predict(x_train) print(classification_report(y_train, y_pred_train)) y_pred_test = model.predict(x_test) print(classification_report(y_test, y_pred_test))
-
- acc
- 회귀
- r^2, mse
-
from sklearn.metrics import r2_score, mean_squared_error y_pred_train = model.predict(x_train) y_pred_test = model.predict(x_test) r2_train = r2_score(y_train, y_pred_train) r2_test = r2_score(y_test, y_pred_test) print('r^2_score(train): ', r2_train) print('r^2_score(test): ', r2_test) print('') mae_train = mean_squared_error(y_train, y_pred_train) mae_test = mean_squared_error(y_test, y_pred_test) print('mae_train(train): ', mae_train) print('mae_test(test): ', mae_test)
-
- r^2, mse
- 분류
- 해석
- feature importance
-
sns.set(style="darkgrid") palette = sns.color_palette("bright", 20) ftr_importances_values = model.feature_importances_ ftr_importances = pd.Series(ftr_importances_values, index = x_train.columns) ftr_top20 = ftr_importances.sort_values(ascending=False)[:20] sns.barplot(x=ftr_top20, y=ftr_top20.index, palette=palette) plt.show()
-
- PCA 차원 축소
- 높을수록 좋은 값
- 낮은 경우 표준화, 정규화, 이상치 제거, 상관계수 높은 특성 제거
-
from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler N = 2 scaler = StandardScaler() X_scaled = scaler.fit_transform(X) pca = PCA(n_components=N) X_pca = pca.fit_transform(X_scaled) for i in range(N): component_str = [f'{value:.2f}' for value in pca.components_[i]] ratio_str = f'{pca.explained_variance_ratio_[i]:.2f}' print(f'Comp {i+1} config: {component_str}') print(f'Comp {i+1} ratio: {ratio_str}') plt.style.use(['seaborn']) plt.scatter(X_pca[:, 0], X_pca[:, 1]) plt.xlabel('Principal Comp 1') plt.ylabel('Principal Comp 2') plt.show()
- AUROC (분류)
-
from sklearn.metrics import roc_auc_score y_pred_proba = model.predict_proba(x_test) auroc_ovo = roc_auc_score(y_test, y_pred_proba, multi_class='ovo') print(f"AUROC (ovo): {auroc_ovo:.4f}")
-
- ROC Curve (분류)
-
from sklearn.metrics import roc_curve, auc from sklearn.preprocessing import label_binarize y_test_bin = label_binarize(y_test, classes=model.classes_) n_classes = y_test_bin.shape[1] plt.style.use(['seaborn']) plt.figure() for i in range(n_classes): fpr, tpr, _ = roc_curve(y_test_bin[:, i], y_pred_proba[:, i]) roc_auc = auc(fpr, tpr) plt.plot(fpr, tpr, label=f'Class {model.classes_[i]} (AUC = {roc_auc:.2f})') plt.plot([0, 1], [0, 1], 'k--', lw=1) plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate') plt.title('ROC Curve') plt.legend(loc="lower right") plt.show()
-
- 시각화 (회귀)
-
pd.options.display.float_format = '{:.2f}'.format result = pd.DataFrame({'Real Values':y_test, 'Predicted Values':y_pred_test}) result['diff'] = result['Real Values'] - result['Predicted Values'] sns.set(style="darkgrid") sns.scatterplot(x=result['Real Values'], y=result['Predicted Values']) lim_min = min(result['Real Values'].min(), result['Predicted Values'].min()) lim_max = max(result['Real Values'].max(), result['Predicted Values'].max()) plt.xlim(lim_min, lim_max) plt.ylim(lim_min, lim_max) x = [lim_min, lim_max] y = [lim_min, lim_max] plt.plot(x, y, color='red') plt.show() result = result.reset_index(drop=True) plt.plot(result.index, result['Real Values'], label='Real') plt.plot(result.index, result['Predicted Values'], label='Pred') plt.legend() plt.show()
-
- confusion matrix (다중분류)
-
from sklearn.metrics import confusion_matrix plt.style.use(['seaborn']) cm = confusion_matrix(y_test, y_pred_test) plt.figure() sns.heatmap(cm, annot=True, fmt='d', cmap='Blues') plt.xlabel('Predicted Label') plt.ylabel('True Label') plt.title('Confusion Matrix') plt.show()
-
- feature importance
- 개선
- 자동 튜닝
-
from sklearn.model_selection import GridSearchCV param_grid = { 'n_estimators': [50, 100, 200], # 트리 개수 'max_depth': [None, 10, 20, 30], # 트리의 최대 깊이 'min_samples_split': [2, 5, 10], # 노드를 분할하기 위한 최소 샘플 수 'min_samples_leaf': [1, 2, 4], # 리프 노드의 최소 샘플 수 'max_features': ['auto', 'sqrt', 'log2'] # 최적의 분할을 위해 고려할 기능 수 } grid_cv = GridSearchCV(model, param_grid, cv=3, n_jobs=-1, scoring='f1') grid_cv.fit(x_train, y_train) print(f'The best params: {grid_cv.best_params_}') print(f'The best score: {grid_cv.best_score_:.4f}')
-
- 자동 튜닝
반응형
'데이터분석 교육 (제로베이스)' 카테고리의 다른 글
[스터디 노트] 30번째 SQL 분석 Power BI (241108), 제로베이스 데이터 분석 스쿨 내용 (1) | 2024.11.08 |
---|---|
[스터디 노트] 29번째 SQL 분석 (241106), 제로베이스 데이터 분석 스쿨 내용 (2) | 2024.11.06 |
[스터디 노트] 27번째 SQL 분석 Power BI (241023), 제로베이스 데이터 분석 스쿨 내용 (0) | 2024.10.23 |
[스터디 노트] 26번째 SQL 분석 디비버 (241021), 제로베이스 데이터 분석 스쿨 내용 (0) | 2024.10.21 |
[스터디 노트] 25번째 SQL 분석 빅쿼리 태블로 루커 (241020), 제로베이스 데이터 분석 스쿨 내용 (0) | 2024.10.21 |