{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":88400,"databundleVersionId":10121331,"sourceType":"competition"}],"dockerImageVersionId":30786,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:16:39.789114Z","iopub.execute_input":"2024-11-19T14:16:39.789535Z","iopub.status.idle":"2024-11-19T14:16:39.801294Z","shell.execute_reply.started":"2024-11-19T14:16:39.789502Z","shell.execute_reply":"2024-11-19T14:16:39.800081Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train = pd.read_csv('/kaggle/input/aiffel-ds-3-credit-card-fraud-detection/train.csv')\ntest = pd.read_csv('/kaggle/input/aiffel-ds-3-credit-card-fraud-detection/test.csv')\nsample_submission = pd.read_csv('/kaggle/input/aiffel-ds-3-credit-card-fraud-detection/sample_submission.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:16:42.919829Z","iopub.execute_input":"2024-11-19T14:16:42.920237Z","iopub.status.idle":"2024-11-19T14:16:45.422232Z","shell.execute_reply.started":"2024-11-19T14:16:42.920200Z","shell.execute_reply":"2024-11-19T14:16:45.420911Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np \nimport matplotlib.pyplot as plt\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n%matplotlib inline","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:16:48.640190Z","iopub.execute_input":"2024-11-19T14:16:48.641219Z","iopub.status.idle":"2024-11-19T14:16:48.648168Z","shell.execute_reply.started":"2024-11-19T14:16:48.641174Z","shell.execute_reply":"2024-11-19T14:16:48.647134Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.shape\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:16:50.336047Z","iopub.execute_input":"2024-11-19T14:16:50.336901Z","iopub.status.idle":"2024-11-19T14:16:50.344018Z","shell.execute_reply.started":"2024-11-19T14:16:50.336854Z","shell.execute_reply":"2024-11-19T14:16:50.342874Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test.shape\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:16:52.176302Z","iopub.execute_input":"2024-11-19T14:16:52.176707Z","iopub.status.idle":"2024-11-19T14:16:52.183059Z","shell.execute_reply.started":"2024-11-19T14:16:52.176670Z","shell.execute_reply":"2024-11-19T14:16:52.182024Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_submission.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:16:53.975924Z","iopub.execute_input":"2024-11-19T14:16:53.976345Z","iopub.status.idle":"2024-11-19T14:16:53.983044Z","shell.execute_reply.started":"2024-11-19T14:16:53.976307Z","shell.execute_reply":"2024-11-19T14:16:53.982019Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('Columns before processing:', train.columns)\nif 'Time' in train.columns:\n    print(\"Time column found and removed.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:16:55.800748Z","iopub.execute_input":"2024-11-19T14:16:55.801166Z","iopub.status.idle":"2024-11-19T14:16:55.809544Z","shell.execute_reply.started":"2024-11-19T14:16:55.801128Z","shell.execute_reply":"2024-11-19T14:16:55.808329Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\ndef get_preprocessed_df(df=None):\n    return df.drop('Time', axis=1, errors='ignore')\n\ntrain = get_preprocessed_df(train)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:16:57.743896Z","iopub.execute_input":"2024-11-19T14:16:57.744296Z","iopub.status.idle":"2024-11-19T14:16:57.778223Z","shell.execute_reply.started":"2024-11-19T14:16:57.744261Z","shell.execute_reply":"2024-11-19T14:16:57.777122Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:17:00.160439Z","iopub.execute_input":"2024-11-19T14:17:00.160852Z","iopub.status.idle":"2024-11-19T14:17:00.192181Z","shell.execute_reply.started":"2024-11-19T14:17:00.160817Z","shell.execute_reply":"2024-11-19T14:17:00.191041Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_train_test_dataset(df=None):\n    df_copy = get_preprocessed_df(df)\n    X_features = df_copy.drop(columns=['Class'])\n    y_target = df_copy['Class']\n\n    # print(\"y_target 고유값 개수:\", y_target.nunique())\n    # print(\"y_target 결측값 개수:\", y_target.isnull().sum())\n\n    # 학습 및 데이터 세트 분할\n    X_train, X_test, y_train, y_test = \\\n    train_test_split(X_features, y_target, test_size=0.3, random_state=0, stratify=y_target)\n    return X_train, X_test, y_train, y_test\n\nX_train, X_test, y_train, y_test = get_train_test_dataset(train)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:17:02.586086Z","iopub.execute_input":"2024-11-19T14:17:02.586471Z","iopub.status.idle":"2024-11-19T14:17:02.730636Z","shell.execute_reply.started":"2024-11-19T14:17:02.586437Z","shell.execute_reply":"2024-11-19T14:17:02.729696Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('학습 데이터 레이블 값 비율')\nprint(y_train.value_counts()/y_train.shape[0] * 100)\nprint('테스트 데이터 레이블 값 비율')\nprint(y_test.value_counts()/y_test.shape[0] * 100)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:17:05.879950Z","iopub.execute_input":"2024-11-19T14:17:05.880356Z","iopub.status.idle":"2024-11-19T14:17:05.892558Z","shell.execute_reply.started":"2024-11-19T14:17:05.880323Z","shell.execute_reply":"2024-11-19T14:17:05.891491Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.linear_model import LogisticRegression\n\nlr_clf = LogisticRegression(max_iter=1000)\nlr_clf.fit(X_train, y_train)\nlr_pred = lr_clf.predict(X_test)\nlr_pred_proba = lr_clf.predict_proba(X_test)[:, 1]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:17:08.688476Z","iopub.execute_input":"2024-11-19T14:17:08.688902Z","iopub.status.idle":"2024-11-19T14:17:15.466537Z","shell.execute_reply.started":"2024-11-19T14:17:08.688865Z","shell.execute_reply":"2024-11-19T14:17:15.465442Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score\n\n# Define the get_clf_eval function\ndef get_clf_eval(y_test, pred, pred_proba):\n    accuracy = accuracy_score(y_test, pred)\n    precision = precision_score(y_test, pred)\n    recall = recall_score(y_test, pred)\n    f1 = f1_score(y_test, pred)\n    roc_auc = roc_auc_score(y_test, pred_proba)\n    \n    print(f'Accuracy: {accuracy:.4f}')\n    print(f'Precision: {precision:.4f}')\n    print(f'Recall: {recall:.4f}')\n    print(f'F1 Score: {f1:.4f}')\n    print(f'ROC AUC: {roc_auc:.4f}')\n\n# Train Logistic Regression model\nlr_clf = LogisticRegression(max_iter=1000)\nlr_clf.fit(X_train, y_train)\n\n# Predict and evaluate\nlr_pred = lr_clf.predict(X_test)\nlr_pred_proba = lr_clf.predict_proba(X_test)[:, 1]\nget_clf_eval(y_test, lr_pred, lr_pred_proba)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:17:18.801067Z","iopub.execute_input":"2024-11-19T14:17:18.801448Z","iopub.status.idle":"2024-11-19T14:17:25.710243Z","shell.execute_reply.started":"2024-11-19T14:17:18.801415Z","shell.execute_reply":"2024-11-19T14:17:25.709010Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 인자로 사이킷런의 Estimator객체와, 학습/테스트 데이터 세트를 입력 받아서 학습/예측/평가 수행.\ndef get_model_train_eval(model, ftr_train=None, ftr_test=None, tgt_train=None, tgt_test=None):\n    model.fit(ftr_train, tgt_train)\n    pred = model.predict(ftr_test)\n    pred_proba = model.predict_proba(ftr_test)[:, 1]\n    get_clf_eval(tgt_test, pred, pred_proba)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:17:34.496508Z","iopub.execute_input":"2024-11-19T14:17:34.497329Z","iopub.status.idle":"2024-11-19T14:17:34.505428Z","shell.execute_reply.started":"2024-11-19T14:17:34.497284Z","shell.execute_reply":"2024-11-19T14:17:34.504350Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from lightgbm import LGBMClassifier\n\nlgbm_clf = LGBMClassifier(n_estimators=1000, num_leaves=64, n_jobs=-1, boost_from_average=False)\nget_model_train_eval(lgbm_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:17:39.496119Z","iopub.execute_input":"2024-11-19T14:17:39.496480Z","iopub.status.idle":"2024-11-19T14:17:59.726826Z","shell.execute_reply.started":"2024-11-19T14:17:39.496449Z","shell.execute_reply":"2024-11-19T14:17:59.725786Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"데이터 분포도 변환 후 모델의 학습, 예측과 평가","metadata":{}},{"cell_type":"code","source":"import seaborn as sns\n\nplt.figure(figsize=(8, 4))\nplt.xticks(range(0, 30000, 1000), rotation=60)\nsns.histplot(train['Amount'], bins=100, kde=True)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:18:53.826101Z","iopub.execute_input":"2024-11-19T14:18:53.826522Z","iopub.status.idle":"2024-11-19T14:18:55.045395Z","shell.execute_reply.started":"2024-11-19T14:18:53.826486Z","shell.execute_reply":"2024-11-19T14:18:55.044104Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.preprocessing import StandardScaler\n# 사이킷런의 StandardScaler를 이용하여 정규분포 형태로 Amount 피처값 변환하는 로직으로 수정. \ndef get_preprocessed_df(df=None):\n    df_copy = df.copy()\n    scaler = StandardScaler()\n    amount_n = scaler.fit_transform(df_copy['Amount'].values.reshape(-1, 1))\n    # 변환된 Amount를 Amount_Scaled로 피처명 변경후 DataFrame맨 앞 컬럼으로 입력\n    df_copy.insert(0, 'Amount_Scaled', amount_n)\n    # 기존 Time, Amount 피처 삭제\n    df_copy.drop(['Time','Amount'], axis=1, inplace=True)\n    return df_copy","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:18:59.120508Z","iopub.execute_input":"2024-11-19T14:18:59.120898Z","iopub.status.idle":"2024-11-19T14:18:59.127436Z","shell.execute_reply.started":"2024-11-19T14:18:59.120860Z","shell.execute_reply":"2024-11-19T14:18:59.126192Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_train_test_dataset(df):\n    # 안전하게 Time 열 제거\n    df = df.drop('Time', axis=1, errors='ignore')\n    X = df.drop('Class', axis=1)\n    y = df['Class']\n    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42)\n    return X_train, X_test, y_train, y_test\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:19:05.968081Z","iopub.execute_input":"2024-11-19T14:19:05.968457Z","iopub.status.idle":"2024-11-19T14:19:05.974472Z","shell.execute_reply.started":"2024-11-19T14:19:05.968423Z","shell.execute_reply":"2024-11-19T14:19:05.973345Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Amount를 정규분포 형태로 변환 후 로지스틱 회귀 및 LightGBM 수행. \nX_train, X_test, y_train, y_test = get_train_test_dataset(train)\n\nprint('### 로지스틱 회귀 예측 성능 ###')\nlr_clf = LogisticRegression(max_iter=1000)\nget_model_train_eval(lr_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)\n\nprint('### LightGBM 예측 성능 ###')\nlgbm_clf = LGBMClassifier(n_estimators=1000, num_leaves=64, n_jobs=-1, boost_from_average=False)\nget_model_train_eval(lgbm_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:19:11.009128Z","iopub.execute_input":"2024-11-19T14:19:11.009510Z","iopub.status.idle":"2024-11-19T14:19:39.194546Z","shell.execute_reply.started":"2024-11-19T14:19:11.009475Z","shell.execute_reply":"2024-11-19T14:19:39.193422Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_preprocessed_df(df=None):\n    df_copy = df.copy()\n    # 넘파이의 log1p( )를 이용하여 Amount를 로그 변환 \n    amount_n = np.log1p(df_copy['Amount'])\n    df_copy.insert(0, 'Amount_Scaled', amount_n)\n    df_copy.drop(['Time','Amount'], axis=1, inplace=True)\n    return df_copy\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:20:14.433959Z","iopub.execute_input":"2024-11-19T14:20:14.434387Z","iopub.status.idle":"2024-11-19T14:20:14.440129Z","shell.execute_reply.started":"2024-11-19T14:20:14.434350Z","shell.execute_reply":"2024-11-19T14:20:14.438944Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_train, X_test, y_train, y_test = get_train_test_dataset(train)\n\nprint('### 로지스틱 회귀 예측 성능 ###')\nget_model_train_eval(lr_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)\n\nprint('### LightGBM 예측 성능 ###')\nget_model_train_eval(lgbm_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:20:19.479946Z","iopub.execute_input":"2024-11-19T14:20:19.480395Z","iopub.status.idle":"2024-11-19T14:20:48.491344Z","shell.execute_reply.started":"2024-11-19T14:20:19.480358Z","shell.execute_reply":"2024-11-19T14:20:48.490253Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"이상치 데이터 제거 후 모델 학습, 예측과 평가","metadata":{}},{"cell_type":"code","source":"import seaborn as sns\n\nplt.figure(figsize=(9, 9))\ncorr = train.corr()\nsns.heatmap(corr, cmap='RdBu')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:21:11.827207Z","iopub.execute_input":"2024-11-19T14:21:11.828221Z","iopub.status.idle":"2024-11-19T14:21:12.950439Z","shell.execute_reply.started":"2024-11-19T14:21:11.828176Z","shell.execute_reply":"2024-11-19T14:21:12.949279Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"outlier_index = get_outlier(df=train, column='V14', weight=1.5)\nprint('이상치 데이터 인덱스:', outlier_index)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:21:25.154347Z","iopub.execute_input":"2024-11-19T14:21:25.155227Z","iopub.status.idle":"2024-11-19T14:21:25.164538Z","shell.execute_reply.started":"2024-11-19T14:21:25.155184Z","shell.execute_reply":"2024-11-19T14:21:25.163542Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_outlier(df=None, column=None, weight=1.5):\n    # fraud에 해당하는 column 데이터만 추출, 1/4 분위와 3/4 분위 지점을 np.percentile로 구함. \n    fraud = df[df['Class']==1][column]\n    quantile_25 = np.percentile(fraud.values, 25)\n    quantile_75 = np.percentile(fraud.values, 75)\n    # IQR을 구하고, IQR에 1.5를 곱하여 최대값과 최소값 지점 구함. \n    iqr = quantile_75 - quantile_25\n    iqr_weight = iqr * weight\n    lowest_val = quantile_25 - iqr_weight\n    highest_val = quantile_75 + iqr_weight\n    # 최대값 보다 크거나, 최소값 보다 작은 값을 아웃라이어로 설정하고 DataFrame index 반환. \n    outlier_index = fraud[(fraud < lowest_val) | (fraud > highest_val)].index\n    return outlier_index","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:21:40.227835Z","iopub.execute_input":"2024-11-19T14:21:40.228753Z","iopub.status.idle":"2024-11-19T14:21:40.234872Z","shell.execute_reply.started":"2024-11-19T14:21:40.228710Z","shell.execute_reply":"2024-11-19T14:21:40.233610Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# get_processed_df( )를 로그 변환 후 V14 피처의 이상치 데이터를 삭제하는 로직으로 변경. \ndef get_preprocessed_df(df=None):\n    df_copy = df.copy()\n    amount_n = np.log1p(df_copy['Amount'])\n    df_copy.insert(0, 'Amount_Scaled', amount_n)\n    df_copy.drop(['Time','Amount'], axis=1, inplace=True)\n    # 이상치 데이터 삭제하는 로직 추가\n    outlier_index = get_outlier(df=df_copy, column='V14', weight=1.5)\n    df_copy.drop(outlier_index, axis=0, inplace=True)\n    return df_copy\n\nX_train, X_test, y_train, y_test = get_train_test_dataset(train)\nprint('### 로지스틱 회귀 예측 성능 ###')\nget_model_train_eval(lr_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)\nprint('### LightGBM 예측 성능 ###')\nget_model_train_eval(lgbm_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:21:49.251060Z","iopub.execute_input":"2024-11-19T14:21:49.251437Z","iopub.status.idle":"2024-11-19T14:22:17.401084Z","shell.execute_reply.started":"2024-11-19T14:21:49.251402Z","shell.execute_reply":"2024-11-19T14:22:17.400026Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"SMOTE 오버 샘플링 적용 후 모델 학습, 예측과 평가","metadata":{}},{"cell_type":"code","source":"from imblearn.over_sampling import SMOTE\n\nsmote = SMOTE(random_state=0)\nX_train_over, y_train_over = smote.fit_resample(X_train, y_train)\nprint('SMOTE 적용 전 학습용 피처/레이블 데이터 세트: ', X_train.shape, y_train.shape)\nprint('SMOTE 적용 후 학습용 피처/레이블 데이터 세트: ', X_train_over.shape, y_train_over.shape)\nprint('SMOTE 적용 후 레이블 값 분포: \\n', pd.Series(y_train_over).value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:23:04.139660Z","iopub.execute_input":"2024-11-19T14:23:04.140090Z","iopub.status.idle":"2024-11-19T14:23:04.376377Z","shell.execute_reply.started":"2024-11-19T14:23:04.140051Z","shell.execute_reply":"2024-11-19T14:23:04.375168Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"lr_clf = LogisticRegression()\nget_model_train_eval(lr_clf, ftr_train=X_train_over, ftr_test=X_test, tgt_train=y_train_over, tgt_test=y_test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:23:09.963853Z","iopub.execute_input":"2024-11-19T14:23:09.964907Z","iopub.status.idle":"2024-11-19T14:23:11.913224Z","shell.execute_reply.started":"2024-11-19T14:23:09.964856Z","shell.execute_reply":"2024-11-19T14:23:11.911375Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport matplotlib.ticker as ticker\nfrom sklearn.metrics import precision_recall_curve\n%matplotlib inline\n\ndef precision_recall_curve_plot(y_test , pred_proba_c1):\n    precisions, recalls, thresholds = precision_recall_curve( y_test, pred_proba_c1)\n\n    plt.figure(figsize=(8,6))\n    threshold_boundary = thresholds.shape[0]\n    plt.plot(thresholds, precisions[0:threshold_boundary], linestyle='--', label='precision')\n    plt.plot(thresholds, recalls[0:threshold_boundary],label='recall')\n\n    start, end = plt.xlim()\n    plt.xticks(np.round(np.arange(start, end, 0.1),2))\n\n    plt.xlabel('Threshold value'); plt.ylabel('Precision and Recall value')\n    plt.legend(); plt.grid()\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:23:19.044635Z","iopub.execute_input":"2024-11-19T14:23:19.045039Z","iopub.status.idle":"2024-11-19T14:23:19.054838Z","shell.execute_reply.started":"2024-11-19T14:23:19.044996Z","shell.execute_reply":"2024-11-19T14:23:19.053816Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"precision_recall_curve_plot( y_test, lr_clf.predict_proba(X_test)[:, 1] )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:23:30.907805Z","iopub.execute_input":"2024-11-19T14:23:30.908217Z","iopub.status.idle":"2024-11-19T14:23:31.205201Z","shell.execute_reply.started":"2024-11-19T14:23:30.908178Z","shell.execute_reply":"2024-11-19T14:23:31.204077Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.ensemble import RandomForestClassifier\n\nrf_clf = RandomForestClassifier(n_estimators=100, random_state=42)\nrf_clf.fit(X_train_over, y_train_over)\ny_pred = rf_clf.predict(X_test)\ny_pred_proba = rf_clf.predict_proba(X_test)[:, 1]\nget_clf_eval(y_test, y_pred, y_pred_proba)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:23:38.291932Z","iopub.execute_input":"2024-11-19T14:23:38.292358Z","iopub.status.idle":"2024-11-19T14:27:46.005767Z","shell.execute_reply.started":"2024-11-19T14:23:38.292317Z","shell.execute_reply":"2024-11-19T14:27:46.004726Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"lgbm_clf = LGBMClassifier(n_estimators=1000, num_leaves=64, n_jobs=-1, boost_from_average=False)\nget_model_train_eval(lgbm_clf, ftr_train=X_train_over, ftr_test=X_test,\n                  tgt_train=y_train_over, tgt_test=y_test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:27:46.007569Z","iopub.execute_input":"2024-11-19T14:27:46.007912Z","iopub.status.idle":"2024-11-19T14:28:33.232077Z","shell.execute_reply.started":"2024-11-19T14:27:46.007878Z","shell.execute_reply":"2024-11-19T14:28:33.230898Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"앙상블로 ROC-AUC 확인","metadata":{}},{"cell_type":"code","source":"from sklearn.ensemble import VotingClassifier\nfrom sklearn.metrics import roc_auc_score\n\nvoting_clf = VotingClassifier(estimators=[\n    ('lr_clf', lr_clf),\n    ('lgbm_clf', lgbm_clf),\n    ('rf_clf', rf_clf)\n], voting='soft')\n\nvoting_clf.fit(X_train, y_train)\n\ny_pred_proba_voting = voting_clf.predict_proba(X_test)[:, 1]\n\nroc_auc_voting = roc_auc_score(y_test, y_pred_proba_voting)\n\nprint(f'[M] Voting Classifier ROC-AUC: {roc_auc_voting:.4f}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:37:06.110461Z","iopub.execute_input":"2024-11-19T14:37:06.110892Z","iopub.status.idle":"2024-11-19T14:39:28.864763Z","shell.execute_reply.started":"2024-11-19T14:37:06.110852Z","shell.execute_reply":"2024-11-19T14:39:28.863290Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"최적 파라미터","metadata":{}},{"cell_type":"code","source":"# 최적의 하이퍼파라미터\nbest_lr_params = {'C': 0.01, 'solver': 'liblinear'}\nlr_clf_tuned = LogisticRegression(C=best_lr_params['C'], solver=best_lr_params['solver'])\n\nlr_clf_tuned.fit(X_train, y_train)\n\nlr_pred = lr_clf_tuned.predict(X_test)\nlr_pred_proba = lr_clf_tuned.predict_proba(X_test)[:, 1]\n\nget_clf_eval(y_test, lr_pred, lr_pred_proba)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:39:43.898501Z","iopub.execute_input":"2024-11-19T14:39:43.898936Z","iopub.status.idle":"2024-11-19T14:39:46.434205Z","shell.execute_reply.started":"2024-11-19T14:39:43.898885Z","shell.execute_reply":"2024-11-19T14:39:46.430641Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 최적의 하이퍼파라미터\nbest_rf_clf = RandomForestClassifier(n_estimators=100, max_depth=10, min_samples_split=2, random_state=42)\n\nbest_rf_clf.fit(X_train, y_train)\n\ny_pred_rf = best_rf_clf.predict(X_test)\ny_pred_proba_rf = best_rf_clf.predict_proba(X_test)[:, 1]\n\nget_clf_eval(y_test, y_pred_rf, y_pred_proba_rf)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:39:46.437086Z","iopub.execute_input":"2024-11-19T14:39:46.437921Z","iopub.status.idle":"2024-11-19T14:41:15.521424Z","shell.execute_reply.started":"2024-11-19T14:39:46.437862Z","shell.execute_reply":"2024-11-19T14:41:15.520369Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 최적의 하이퍼파라미터\nbest_lgbm_clf = LGBMClassifier(num_leaves=31, learning_rate=0.01, n_estimators=200, max_depth=5, random_state=42)\n\nbest_lgbm_clf.fit(X_train, y_train)\n\ny_pred_lgb = best_lgbm_clf.predict(X_test)\ny_pred_proba_lgb = best_lgbm_clf.predict_proba(X_test)[:, 1]\n\nget_clf_eval(y_test, y_pred_lgb, y_pred_proba_lgb)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:44:31.530246Z","iopub.execute_input":"2024-11-19T14:44:31.530667Z","iopub.status.idle":"2024-11-19T14:44:36.562061Z","shell.execute_reply.started":"2024-11-19T14:44:31.530628Z","shell.execute_reply":"2024-11-19T14:44:36.561029Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"앙상블로 최종 ROC-AUC 확인","metadata":{}},{"cell_type":"code","source":"from sklearn.ensemble import VotingClassifier\nfrom sklearn.metrics import roc_auc_score\n\nvoting_clf = VotingClassifier(estimators=[\n    ('lr_clf', lr_clf),\n    ('lgbm_clf', lgbm_clf),\n    ('rf_clf', rf_clf)\n], voting='soft')\n\nvoting_clf.fit(X_train, y_train)\n\ny_pred_proba_voting = voting_clf.predict_proba(X_test)[:, 1]\n\nroc_auc_voting = roc_auc_score(y_test, y_pred_proba_voting)\n\nprint(f'[Final] Voting Classifier ROC-AUC: {roc_auc_voting:.4f}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:47:39.483700Z","iopub.execute_input":"2024-11-19T14:47:39.484113Z","iopub.status.idle":"2024-11-19T14:50:01.877365Z","shell.execute_reply.started":"2024-11-19T14:47:39.484078Z","shell.execute_reply":"2024-11-19T14:50:01.876071Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 최적의 하이퍼파라미터\nbest_lgbm_clf = LGBMClassifier(num_leaves=31, learning_rate=0.01, n_estimators=200, max_depth=5, random_state=42)\n\nbest_lgbm_clf.fit(X_train, y_train)\n\ny_pred_lgb = best_lgbm_clf.predict(X_test)\ny_pred_proba_lgb = best_lgbm_clf.predict_proba(X_test)[:, 1]\n\nget_clf_eval(y_test, y_pred_lgb, y_pred_proba_lgb)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:51:04.629990Z","iopub.execute_input":"2024-11-19T14:51:04.630400Z","iopub.status.idle":"2024-11-19T14:51:09.701994Z","shell.execute_reply.started":"2024-11-19T14:51:04.630365Z","shell.execute_reply":"2024-11-19T14:51:09.700950Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"y_pred_lgb = best_lgbm_clf.predict(X_test)\ny_pred_proba_lgb = best_lgbm_clf.predict_proba(X_test)[:, 1]\n\nget_clf_eval(y_test, y_pred_lgb, y_pred_proba_lgb)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:51:25.589792Z","iopub.execute_input":"2024-11-19T14:51:25.590196Z","iopub.status.idle":"2024-11-19T14:51:26.069016Z","shell.execute_reply.started":"2024-11-19T14:51:25.590159Z","shell.execute_reply":"2024-11-19T14:51:26.067866Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 'Amount_Scaled' 열을 train 데이터에서 계산한 방식대로 test 데이터에 추가\ntest['Amount_Scaled'] = np.log1p(test['Amount'])\n\n# 학습 데이터에서 사용한 열만 선택\ntrain_columns = X_train.columns\n\n# test 데이터에서 train 데이터에 있는 피처만 선택\ntest_selected = test[train_columns]\n\n# 테스트 데이터에 대해 확률 예측\ny_pred_proba_test = best_lgbm_clf.predict_proba(test_selected)[:, 1]  # 두 번째 클래스의 확률값 추출\n\n# 제출 파일 생성 (id 열과 예측값을 포함)\nsubmission = pd.DataFrame({'id': test['id'], 'Class': y_pred_proba_test})\n\n# 제출 파일을 CSV로 저장\nsubmission.to_csv('submission.csv', index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:51:31.438180Z","iopub.execute_input":"2024-11-19T14:51:31.439177Z","iopub.status.idle":"2024-11-19T14:51:32.573762Z","shell.execute_reply.started":"2024-11-19T14:51:31.439135Z","shell.execute_reply":"2024-11-19T14:51:32.572383Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-19T14:51:37.125611Z","iopub.execute_input":"2024-11-19T14:51:37.126008Z","iopub.status.idle":"2024-11-19T14:51:37.136848Z","shell.execute_reply.started":"2024-11-19T14:51:37.125958Z","shell.execute_reply":"2024-11-19T14:51:37.135762Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"전반적으로 수행가능한 난이도였지만 문제 해결이 어려운 고비가 수 차례 있었다. 그 중에 경고 문구와 함께 무한정 반복되는 [LightGBM] [Warning] No further splits with positive gain, best gain: -inf. 이 구문은 감당하기 어려운 내용이었다. 나중에 인지하게 되었는데 실무 영역에서 이와 유사한 결과 값과 과정은 종종 경험할 수 있는 부분이라 생각하게 되었다. 포기하고 있다가 교재의 내용을 중심으로 사기 검출에 대한 전체 맥락에 주목해서 다시 수행했다. 개인 일정과 수업 준비로 분주한 터라 매우 아쉽긴 하지만 불균형한 레이블 분포 사례를 수행하게 되어 귀중한 경험이 되었다고 생각한다.  ","metadata":{}},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}