{"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","execution":{"iopub.status.busy":"2024-11-12T06:55:17.664295Z","iopub.execute_input":"2024-11-12T06:55:17.664682Z","iopub.status.idle":"2024-11-12T06:55:18.062567Z","shell.execute_reply.started":"2024-11-12T06:55:17.664643Z","shell.execute_reply":"2024-11-12T06:55:18.061513Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\n\ntrain_path = '/kaggle/input/aiffel-ds-3-credit-card-fraud-detection/train.csv'\ntest_path = '/kaggle/input/aiffel-ds-3-credit-card-fraud-detection/test.csv'\nsubmission_path = '/kaggle/input/aiffel-ds-3-credit-card-fraud-detection/sample_submission.csv'\n\ntrain_df = pd.read_csv(train_path)\ntest_df = pd.read_csv(test_path)\nsubmission_df = pd.read_csv(submission_path)","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:18.064226Z","iopub.execute_input":"2024-11-12T06:55:18.064657Z","iopub.status.idle":"2024-11-12T06:55:21.574138Z","shell.execute_reply.started":"2024-11-12T06:55:18.064622Z","shell.execute_reply":"2024-11-12T06:55:21.573147Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 1. 데이터 이해 및 탐색","metadata":{}},{"cell_type":"code","source":"print(\"Train 데이터프레임의 첫 5행:\\n\", train_df.head())\nprint(\"\\nTest 데이터프레임의 첫 5행:\\n\", test_df.head())\nprint(\"\\nSample Submission 데이터프레임의 첫 5행:\\n\", submission_df.head())","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:21.575320Z","iopub.execute_input":"2024-11-12T06:55:21.575650Z","iopub.status.idle":"2024-11-12T06:55:21.609172Z","shell.execute_reply.started":"2024-11-12T06:55:21.575617Z","shell.execute_reply":"2024-11-12T06:55:21.608160Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"데이터의 첫 5행:\\n\", train_df.head())\n# Time 변환 필요\n# v1 ~ 28은 PCA를 통한 차원축소 피쳐로 어떠한지 알 수 없음\n# Amount 사기거래금액, Class 0이면 정상 1이면 사기\n\nprint(\"\\n데이터 정보:\\n\", train_df.info())\n# ID 및 Class(int64) 제외 모두 float64\n\nprint(\"\\n기본 통계 요약:\\n\", train_df.describe())\n# amt에서 이상치인 -값은 확인되지 않음","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:21.611493Z","iopub.execute_input":"2024-11-12T06:55:21.611847Z","iopub.status.idle":"2024-11-12T06:55:21.924589Z","shell.execute_reply.started":"2024-11-12T06:55:21.611793Z","shell.execute_reply":"2024-11-12T06:55:21.923573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df['Hour'] = (train_df['Time'] // 3600) % 24\ntrain_df['Hour'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:21.925857Z","iopub.execute_input":"2024-11-12T06:55:21.926197Z","iopub.status.idle":"2024-11-12T06:55:21.949600Z","shell.execute_reply.started":"2024-11-12T06:55:21.926133Z","shell.execute_reply":"2024-11-12T06:55:21.948482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.shape","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:21.950939Z","iopub.execute_input":"2024-11-12T06:55:21.951609Z","iopub.status.idle":"2024-11-12T06:55:21.958198Z","shell.execute_reply.started":"2024-11-12T06:55:21.951561Z","shell.execute_reply":"2024-11-12T06:55:21.957137Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.duplicated().sum()\n# 중복 미존재","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:21.959618Z","iopub.execute_input":"2024-11-12T06:55:21.960052Z","iopub.status.idle":"2024-11-12T06:55:22.406550Z","shell.execute_reply.started":"2024-11-12T06:55:21.960007Z","shell.execute_reply":"2024-11-12T06:55:22.405451Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.isna().sum()\n# null 미존재","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:22.408085Z","iopub.execute_input":"2024-11-12T06:55:22.408841Z","iopub.status.idle":"2024-11-12T06:55:22.425073Z","shell.execute_reply.started":"2024-11-12T06:55:22.408771Z","shell.execute_reply":"2024-11-12T06:55:22.424074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 불필요한 열 제거\ntrain_df = train_df.drop('id', axis=1)","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:22.426253Z","iopub.execute_input":"2024-11-12T06:55:22.426570Z","iopub.status.idle":"2024-11-12T06:55:22.450384Z","shell.execute_reply.started":"2024-11-12T06:55:22.426536Z","shell.execute_reply":"2024-11-12T06:55:22.449305Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.head(1)","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:22.454129Z","iopub.execute_input":"2024-11-12T06:55:22.454485Z","iopub.status.idle":"2024-11-12T06:55:22.477589Z","shell.execute_reply.started":"2024-11-12T06:55:22.454449Z","shell.execute_reply":"2024-11-12T06:55:22.476645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import seaborn as sns\nimport matplotlib.pyplot as plt\n\nplt.figure(figsize=(10, 6))\nsns.boxplot(x='Class', y='Amount', data=train_df)\nplt.title(\"boxplot\")\nplt.xlabel(\"class\")\nplt.ylabel(\"amt\")\nplt.show()\n\n#특이 이상치는 확인되어지지 않음","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:22.478671Z","iopub.execute_input":"2024-11-12T06:55:22.479002Z","iopub.status.idle":"2024-11-12T06:55:23.599403Z","shell.execute_reply.started":"2024-11-12T06:55:22.478960Z","shell.execute_reply":"2024-11-12T06:55:23.598418Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport seaborn as sns\n\nplt.figure(figsize=(6, 4))\nsns.countplot(x='Class', data=train_df)\nplt.title(\"fraud & n_Fraud\")\nplt.xlabel(\"class\")\nplt.ylabel(\"cnt\")\nplt.show()\n\nratio = round((train_df['Class']==1).sum() / len(train_df),6)\nprint(ratio)\n#정상거래 대비 사기거래는 굉장히 적음을 알 수 있음","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:23.600843Z","iopub.execute_input":"2024-11-12T06:55:23.601334Z","iopub.status.idle":"2024-11-12T06:55:23.783650Z","shell.execute_reply.started":"2024-11-12T06:55:23.601298Z","shell.execute_reply":"2024-11-12T06:55:23.782640Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(10, 6))\nsns.histplot(train_df['Amount'], bins=50, kde=True)\nplt.title(\"amt\")\nplt.xlabel(\"amt\")\nplt.ylabel(\"frequency\")\nplt.show()\n\n#거래금액 이상치도 확인되어지지 않음\n\n#이상치는 없음으로 결론","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:23.784988Z","iopub.execute_input":"2024-11-12T06:55:23.785314Z","iopub.status.idle":"2024-11-12T06:55:24.981798Z","shell.execute_reply.started":"2024-11-12T06:55:23.785281Z","shell.execute_reply":"2024-11-12T06:55:24.980758Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings('ignore')\n\nfraud_pur = train_df[train_df['Class']==1]\n\nplt.figure(figsize= (12, 5))\nplt.subplot(1, 2, 1)\nsns.histplot(train_df['Hour'], bins=50, kde=True)\nplt.title('The Time')\nplt.xlabel('Hour')\nplt.ylabel('Frequency')\nplt.xticks(range(24))\n#정상 거래\n\nplt.subplot(1, 2, 2)\nsns.histplot(fraud_pur['Hour'], bins=50, kde=True)\nplt.title('The Fraud Time')\nplt.xlabel('Hour')\nplt.ylabel('Frequency')\nplt.xticks(range(24))\nplt.tight_layout()\n#사기거래\n\n#주 거래 활동시간인 오후엔 사기거래가 잠잠하며, 특정시간인 새벽 02시, 11시에 많이 발생함을 확인 <> 주 거래 시간대와 다른 행보","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:24.983277Z","iopub.execute_input":"2024-11-12T06:55:24.983602Z","iopub.status.idle":"2024-11-12T06:55:26.656120Z","shell.execute_reply.started":"2024-11-12T06:55:24.983568Z","shell.execute_reply":"2024-11-12T06:55:26.655064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"amt_hour = train_df.groupby('Hour')['Amount'].sum()\nfraud_amt_hour = fraud_pur.groupby('Hour')['Amount'].sum()\n\nplt.figure(figsize= (12, 5))\nplt.subplot(1, 2, 1)\nsns.lineplot(x=amt_hour.index, y=amt_hour.values)\nplt.title('The Amount')\nplt.xlabel('Hour')\nplt.ylabel('Amount')\nplt.xticks(range(24))\n#정상 거래\n\nplt.subplot(1, 2, 2)\nsns.lineplot(x=fraud_amt_hour.index, y=fraud_amt_hour.values)\nplt.title('The Fraud Amount')\nplt.xlabel('Hour')\nplt.ylabel('Amount')\nplt.xticks(range(24))\nplt.tight_layout()\n#사기거래\n\n#사기 거래가 많이 발생하는 시간대인 02시 11시에 거래 금액이 높게 나타남","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:26.657338Z","iopub.execute_input":"2024-11-12T06:55:26.657651Z","iopub.status.idle":"2024-11-12T06:55:27.385816Z","shell.execute_reply.started":"2024-11-12T06:55:26.657618Z","shell.execute_reply":"2024-11-12T06:55:27.384785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fraud_cnt_hour = fraud_pur.groupby('Hour').size()  \nfraud_amt_hour = fraud_pur.groupby('Hour')['Amount'].sum() \n\nfig, ax1 = plt.subplots(figsize=(14, 6))\n\nax1.set_xlabel('Hour')\nax1.set_ylabel('Fraud Cnt', color='tab:blue')\nax1.plot(fraud_cnt_hour.index, fraud_cnt_hour.values, label='Fraud Cnt', color='tab:blue')\nax1.tick_params(axis='y', labelcolor='tab:blue')\nax1.set_xticks(range(24)) \n\nax2 = ax1.twinx()\nax2.set_ylabel('Fraud Amt', color='tab:red')\nax2.plot(fraud_amt_hour.index, fraud_amt_hour.values, label='Fraud Amt', color='tab:red')\nax2.tick_params(axis='y', labelcolor='tab:red')\n\nfig.suptitle('Fraud Cnt and Amt')\n\nax1.legend(loc=\"upper left\")\nax2.legend(loc=\"upper right\")\n\nplt.show()\n\n#시간대별 사기거래가 발생 빈도와 금액이 거의 일치\n#다만 오후시간대에 빈도수 대비 거래금액이 높아 오후시간결제는 고금액대 결제로 추측 <> 고금액대면 사기확률이 높을수있다(?)","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:27.387074Z","iopub.execute_input":"2024-11-12T06:55:27.387388Z","iopub.status.idle":"2024-11-12T06:55:27.824551Z","shell.execute_reply.started":"2024-11-12T06:55:27.387356Z","shell.execute_reply":"2024-11-12T06:55:27.823513Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\n\nbins = [0, 50, 100, 200, 500, 1000, 5000, train_df['Amount'].max()]\nlabels = ['0-50', '50-100', '100-200', '200-500', '500-1000', '1000-5000', '5000+']\ntrain_df['Amount_Bin'] = pd.cut(train_df['Amount'], bins=bins, labels=labels)\n\namt_fraud_ratio = train_df[train_df['Class'] == 1].groupby('Amount_Bin').size() / train_df.groupby('Amount_Bin').size()\n\nplt.figure(figsize=(10, 6))\namt_fraud_ratio.plot(kind='bar', color='coral')\nplt.title(\"fraud amt\")\nplt.xlabel(\"amt bins\")\nplt.ylabel(\"fraud ratio\")\nplt.show()\n#고금액대면 사기확률이 높아짐을 확인","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:27.826116Z","iopub.execute_input":"2024-11-12T06:55:27.826520Z","iopub.status.idle":"2024-11-12T06:55:28.208537Z","shell.execute_reply.started":"2024-11-12T06:55:27.826476Z","shell.execute_reply":"2024-11-12T06:55:28.207577Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(12, 5))\n\nsns.heatmap((train_df.drop(columns='Amount_Bin')).corr(), cmap='coolwarm', cbar=True)\nplt.title(\"fraud\")\n\nplt.show()\n\n#큰 상관관계가 보이지 않음","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:28.210313Z","iopub.execute_input":"2024-11-12T06:55:28.210740Z","iopub.status.idle":"2024-11-12T06:55:29.246768Z","shell.execute_reply.started":"2024-11-12T06:55:28.210692Z","shell.execute_reply":"2024-11-12T06:55:29.245726Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(15, 10))\n\nplt.subplot(1, 2, 1)\nsns.heatmap((train_df[train_df['Class'] == 1].drop(columns=['Class', 'Amount_Bin'])).corr(), cmap='coolwarm', cbar=False)\nplt.title(\"fraud\")\n\nplt.subplot(1, 2, 2)\nsns.heatmap((train_df[train_df['Class'] == 0].drop(columns=['Class', 'Amount_Bin'])).corr(), cmap='coolwarm', cbar=True)\nplt.title(\"n_fraud\")\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:29.247967Z","iopub.execute_input":"2024-11-12T06:55:29.248271Z","iopub.status.idle":"2024-11-12T06:55:30.886482Z","shell.execute_reply.started":"2024-11-12T06:55:29.248238Z","shell.execute_reply":"2024-11-12T06:55:30.885509Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(15, 10))\n\nplt.subplot(1, 2, 1)\nsns.heatmap(train_df[train_df['Class'] == 1].iloc[:, 1:29].corr(), cmap='coolwarm', cbar=False)\nplt.title(\"fraud pur\")\n\nplt.subplot(1, 2, 2)\nsns.heatmap(train_df[train_df['Class'] == 0].iloc[:, 1:29].corr(), cmap='coolwarm', cbar=True)\nplt.title(\"n_fraud pur\")\n\nplt.show()\n\n#피처끼리 비교시 사기거래에선 서로 상관관계가 있음을 확인","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:30.888073Z","iopub.execute_input":"2024-11-12T06:55:30.888563Z","iopub.status.idle":"2024-11-12T06:55:32.463371Z","shell.execute_reply.started":"2024-11-12T06:55:30.888515Z","shell.execute_reply":"2024-11-12T06:55:32.462344Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 요약.1\n> - 데이터는 초(이후 시간으로 변환완료)로 이루어져 있으며 PCA를 통해 이루어진 피쳐 v 버전들, 사기거래 금액, 사기구분값존재\n> - null, 중복값, 이상치는 존재하지 않음\n> - 정상거래와 사기거래는 약 0.21% 정도로서 극히 적은 비율의 사기가 발생해 이후 모델선택에 주의가 필요함\n> - 정상거래와 사기거래의 발생시간은 서로 일치 하지않으며 정상거래는 오후 9시 피크 이후 많은 거래가 이루어지나 사기거래는 02시 및 11시에 많이 발생\n> - 사기거래의 오후시간대 거래 건수대비 금액이 높음을 통해 오후시간의 거래는 고금액대 일 것이라는 추측과 함께 고금액대면 사기확률이 높다는 가설 설립\n> - 사기거래금액의 범주를 나누어 발생 비율 확인시 고금액대임 500-1000사이에서 가잔 많이 발생함을 확인(위가설 대략 일치)\n> - 전체데이터에서 서로의 상관관계는 없으나 사기거래 발생 내에선 피쳐끼리 상관관계 있음을 확인(특정 패턴이 있을 수도 있음)","metadata":{}},{"cell_type":"markdown","source":"# 2.데이터 전처리","metadata":{}},{"cell_type":"code","source":"train_df.head(1)\n#결측치, 중복값, 이상치는 1에서 완료","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:32.464723Z","iopub.execute_input":"2024-11-12T06:55:32.465112Z","iopub.status.idle":"2024-11-12T06:55:32.489764Z","shell.execute_reply.started":"2024-11-12T06:55:32.465076Z","shell.execute_reply":"2024-11-12T06:55:32.488738Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#amount와 hour는 큰 차이가 나 표준화 진행\nfrom sklearn.preprocessing import StandardScaler\n\nscaler = StandardScaler()\ntrain_df['scaled_Amount'] = scaler.fit_transform(train_df[['Amount']])\ntrain_df['scaled_Hour'] = scaler.fit_transform(train_df[['Hour']])\n\ntrain_df = train_df.drop(['Amount', 'Hour'], axis=1)\n","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:32.491062Z","iopub.execute_input":"2024-11-12T06:55:32.491386Z","iopub.status.idle":"2024-11-12T06:55:32.592737Z","shell.execute_reply.started":"2024-11-12T06:55:32.491352Z","shell.execute_reply":"2024-11-12T06:55:32.591648Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = train_df.drop('Time', axis=1)","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:32.594376Z","iopub.execute_input":"2024-11-12T06:55:32.594702Z","iopub.status.idle":"2024-11-12T06:55:32.617107Z","shell.execute_reply.started":"2024-11-12T06:55:32.594668Z","shell.execute_reply":"2024-11-12T06:55:32.616035Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = train_df.drop('Amount_Bin', axis=1)","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:32.618997Z","iopub.execute_input":"2024-11-12T06:55:32.619430Z","iopub.status.idle":"2024-11-12T06:55:32.639684Z","shell.execute_reply.started":"2024-11-12T06:55:32.619383Z","shell.execute_reply":"2024-11-12T06:55:32.638809Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#1에서 본 사거거래일때 상관관계가 높은 피쳐끼리 묶어 새로운 변수 선택(패턴을 찾기 위해)\n\nimport pandas as pd\n\ncorr = train_df[train_df['Class']==1].drop(columns=['scaled_Amount','scaled_Hour']).corr().abs()\n\nhigh_corr = []\nscore = 0.95\nfor i in range(len(corr.columns)):\n    for j in range(i+1, len(corr.columns)):\n        if corr.iloc[i, j] > score:\n            col1 = corr.columns[i]\n            col2 = corr.columns[j]\n            high_corr.append((col1, col2))\n\nfor col1, col2 in high_corr:\n    train_df[f\"{col1}_{col2}\"] = train_df[col1] * train_df[col2]\n\n    \n#'V16_V17', 'V17_V18' 특징 파악 변수 추가\n","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:32.640998Z","iopub.execute_input":"2024-11-12T06:55:32.641326Z","iopub.status.idle":"2024-11-12T06:55:32.667752Z","shell.execute_reply.started":"2024-11-12T06:55:32.641293Z","shell.execute_reply":"2024-11-12T06:55:32.666886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.columns","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:32.669171Z","iopub.execute_input":"2024-11-12T06:55:32.670120Z","iopub.status.idle":"2024-11-12T06:55:32.676655Z","shell.execute_reply.started":"2024-11-12T06:55:32.670072Z","shell.execute_reply":"2024-11-12T06:55:32.675698Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. 모델 선택 및 비교","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nx = train_df.drop(columns=['Class'])\ny = train_df['Class']\n\nx_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=123, stratify=y)\n","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:32.678114Z","iopub.execute_input":"2024-11-12T06:55:32.678931Z","iopub.status.idle":"2024-11-12T06:55:32.901301Z","shell.execute_reply.started":"2024-11-12T06:55:32.678886Z","shell.execute_reply":"2024-11-12T06:55:32.900345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 로지스틱 회귀\nfrom sklearn.linear_model import LogisticRegression\n\nlr = LogisticRegression(class_weight='balanced', random_state=123)\nlr.fit(x_train, y_train)\n\nlr_pred = lr.predict(x_test)\nlr_pred_proba = lr.predict_proba(x_test)[:, 1]\n\n#사기 탐지 데이터는 불균형이 굉장히 큰(1의 비율이 너무 낮은) 데이터로서 단순한 분류를 위해 사용\n","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:32.907749Z","iopub.execute_input":"2024-11-12T06:55:32.908111Z","iopub.status.idle":"2024-11-12T06:55:34.576287Z","shell.execute_reply.started":"2024-11-12T06:55:32.908078Z","shell.execute_reply":"2024-11-12T06:55:34.575022Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 랜덤 포레스트\nfrom sklearn.ensemble import RandomForestClassifier\n\nrf = RandomForestClassifier(class_weight='balanced', random_state=123)\nrf.fit(x_train, y_train)\n\nrf_pred = rf.predict(x_test)\nrf_pred_proba = rf.predict_proba(x_test)[:, 1]\n\n#v1 ~ 28까지 여러가지 피쳐가 있어 복잡한 관계도(?)를 가질 수 있기에 비선형적인 데이터를 학습하는데 있어 높은 활용을 위해 사용","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:55:34.577816Z","iopub.execute_input":"2024-11-12T06:55:34.578756Z","iopub.status.idle":"2024-11-12T06:56:31.418254Z","shell.execute_reply.started":"2024-11-12T06:55:34.578708Z","shell.execute_reply":"2024-11-12T06:56:31.417174Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# XGBoost\nfrom xgboost import XGBClassifier\n\nxgb = XGBClassifier(scale_pos_weight=1/0.03, random_state=123, use_label_encoder=False, eval_metric='logloss')\nxgb.fit(x_train, y_train)\n\nxgb_pred = xgb.predict(x_test)\nxgb_pred_proba = xgb.predict_proba(x_test)[:, 1]\n\n#오차를 줄여가며 미세한 차이를 학습하여 활용하기 위해 사용\n","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:56:31.419475Z","iopub.execute_input":"2024-11-12T06:56:31.419790Z","iopub.status.idle":"2024-11-12T06:56:33.591242Z","shell.execute_reply.started":"2024-11-12T06:56:31.419758Z","shell.execute_reply":"2024-11-12T06:56:33.590315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import classification_report, roc_auc_score, confusion_matrix\n\ndef evaluate_model(y_test, y_pred, y_pred_proba, model_name):\n    print(f\"=== {model_name} ===\")\n    print(\"classification_report:\\n\", classification_report(y_test, y_pred))\n    print(\"confusion_matrix:\\n\", confusion_matrix(y_test, y_pred))\n    print(\"roc_auc_score:\", roc_auc_score(y_test, y_pred_proba))\n    print(\"\\n\")","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:56:33.595148Z","iopub.execute_input":"2024-11-12T06:56:33.596145Z","iopub.status.idle":"2024-11-12T06:56:33.601495Z","shell.execute_reply.started":"2024-11-12T06:56:33.596103Z","shell.execute_reply":"2024-11-12T06:56:33.600439Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 로지스틱 회귀 평가\nevaluate_model(y_test, lr_pred, lr_pred_proba, \"Logistic Regression\")\n\n# 정상거래\n# precision 100%\n# Recall 98%\n# F1-Score - 위 두가지 종합 99%\n# 50006 + 1151 = 51,157 건 중 50,006건을 정확히 예측, 1,151건을 사기로 잘못 예측\n\n\n\n# 사기거래\n# precision 8% 심각히 낮아 대부분 틀린결과를 나타냈을 경우가 높음\n# Recall 91% 사기거래는 놓치지 않았음을 확인\n# F1-Score - 위 두가지 종합 14% Recall 이 낮아 낮게 나옴\n# 10 + 98 = 108건 중 98건을 사기로 정확히 맞췄으나, 10건을 정상거래로 잘못 예측\n\n# roc 0.967로 사기 거래 탐지에서 높은 기능을 함을 보임\n# accuracy 98%\n\n# == 결론 ==\n# 로지스틱 회기 모델은 사기거래는 놓치지 않으나 정상거래를 잘못 판단하는 비율이 높다는 단점이 있음","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:56:33.602901Z","iopub.execute_input":"2024-11-12T06:56:33.603220Z","iopub.status.idle":"2024-11-12T06:56:33.711014Z","shell.execute_reply.started":"2024-11-12T06:56:33.603187Z","shell.execute_reply":"2024-11-12T06:56:33.709873Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 랜덤 포레스트 평가\nevaluate_model(y_test, rf_pred, rf_pred_proba, \"Random Forest\")\n\n# 정상거래\n# precision 100%\n# Recall 100%\n# F1-Score - 위 두가지 종합 100%\n# 51,155 + 2 = 51,157 건 중 51,155건을 정확히 예측, 2건을 사기로 잘못 예측\n\n\n# 사기거래\n# precision 98% \n# Recall 80% 사기거래는 많이 놓치지 않음을 확인\n# F1-Score - 위 두가지 종합 88%로 높은 편\n# 86 + 22 = 108 건 중 86건을 사기로 정확히 맞췄으나, 22건을 정상거래로 잘못 예측\n\n# roc 0.957로 사기 거래 탐지에서 높은 기능을 함을 보임\n# accuracy 100%\n\n# == 결론 ==\n# 랜덤 포레스트는 사기 거래를 높은 정확도로 판단하기도 하면서 로지스틱 회기 대비 정상을 잘못 판단하는 경우도 적음","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:56:33.712202Z","iopub.execute_input":"2024-11-12T06:56:33.712522Z","iopub.status.idle":"2024-11-12T06:56:33.803782Z","shell.execute_reply.started":"2024-11-12T06:56:33.712489Z","shell.execute_reply":"2024-11-12T06:56:33.802877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# XGBoost 평가\nevaluate_model(y_test, xgb_pred, xgb_pred_proba, \"XGBoost\")\n\n# 정상거래\n# precision 100%\n# Recall 100%\n# F1-Score - 위 두가지 종합 100%\n# 51,153 + 4 = 51,157 건 중 51,153건을 정확히 예측, 4건을 사기로 잘못 예측\n\n\n# 사기거래\n# precision 96% \n# Recall 82% 사기거래는 많이 놓치지 않음을 확인\n# F1-Score - 위 두가지 종합 89%로 높은 편\n# 89 + 19 = 108 건 중 89건을 사기로 정확히 맞췄으나, 19건을 정상거래로 잘못 예측\n\n# roc 0.974로 사기 거래 탐지에서 높은 기능을 함을 보임\n# accuracy 100%\n\n# == 결론 ==\n# 세 모델중 가장 좋은 결과를 보이는 모델","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:56:33.805164Z","iopub.execute_input":"2024-11-12T06:56:33.805497Z","iopub.status.idle":"2024-11-12T06:56:33.903602Z","shell.execute_reply.started":"2024-11-12T06:56:33.805463Z","shell.execute_reply":"2024-11-12T06:56:33.902586Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4. 성능 평가","metadata":{}},{"cell_type":"code","source":"#로지스틱 회귀 하이퍼파라미터 튜닝\nfrom sklearn.model_selection import GridSearchCV\n\nparam_grid_lr = {\n    'penalty': ['l2'],                \n    'C': [0.01, 0.1, 1, 10, 100],     \n    'solver': ['lbfgs']               \n                }\n\ngrid_search_lr = GridSearchCV(LogisticRegression(class_weight='balanced', random_state=123), param_grid_lr, scoring='roc_auc', cv=3)\ngrid_search_lr.fit(x_train, y_train)\n\nprint(\"Best Param:\", grid_search_lr.best_params_)\nprint(\"Best ROC-AUC Score:\", grid_search_lr.best_score_)\n\nbest_lr = grid_search_lr.best_estimator_\nlr_pred = best_lr.predict(x_test)\nlr_pred_proba = best_lr.predict_proba(x_test)[:, 1]\n","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:56:33.905200Z","iopub.execute_input":"2024-11-12T06:56:33.905536Z","iopub.status.idle":"2024-11-12T06:56:50.516402Z","shell.execute_reply.started":"2024-11-12T06:56:33.905501Z","shell.execute_reply":"2024-11-12T06:56:50.515243Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#하이퍼파라미터를 반영 결과 1차\nbest_lr = LogisticRegression(C=0.01, penalty='l2', solver='lbfgs', class_weight='balanced', random_state=123)\nbest_lr.fit(x_train, y_train)\n\nlr_pred = best_lr.predict(x_test)\nlr_pred_proba = best_lr.predict_proba(x_test)[:, 1]\n\nevaluate_model(y_test, lr_pred, lr_pred_proba, \"Logistic Regression\")\n\n\n\n# 정상거래\n# precision 100%                                                        => 100% 유지\n# Recall 98%                                                            => 98% 유지\n# F1-Score - 위 두가지 종합 99%                                            => 99% 유지\n# 50006 + 1151 = 51,157 건 중 50,006건을 정확히 예측, 1,151건을 사기로 잘못 예측 => 50,083건 정확히 예측, 1,074건 잘못예측 77건 증가\n\n\n# 사기거래\n# precision 8% 심각히 낮아 대부분 틀린결과를 나타냈을 경우가 높음                   =>8% 유지\n# Recall 91% 사기거래는 놓치지 않았음을 확인                                    =>91% 유지\n# F1-Score - 위 두가지 종합 14% Recall 이 낮아 낮게 나옴                       => 15% 1% 상승\n# 10 + 98 = 108건 중 98건을 사기로 정확히 맞췄으나, 10건을 정상거래로 잘못 예측      => 동일\n\n# roc 0.967로 사기 거래 탐지에서 높은 기능을 함을 보임                           => 0.973으로 소폭 상승\n\n\n","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:56:50.521567Z","iopub.execute_input":"2024-11-12T06:56:50.524809Z","iopub.status.idle":"2024-11-12T06:56:52.125662Z","shell.execute_reply.started":"2024-11-12T06:56:50.524747Z","shell.execute_reply":"2024-11-12T06:56:52.124618Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#랜덤포레스트 하이퍼파라미터 튜닝\n# from sklearn.model_selection import RandomizedSearchCV\n\n# param_grid_rf = {\n#     'n_estimators': [100, 300],  \n#     'max_depth': [20, 30],  \n#     'min_samples_split': [5, 10]   \n# }\n\n# random_search_rf = RandomizedSearchCV(               \n#     RandomForestClassifier(class_weight='balanced', random_state=123), \n#     param_distributions=param_grid_rf, \n#     n_iter=5, \n#     scoring='roc_auc', \n#     cv=3,\n#     n_jobs=-1,\n#     random_state=123\n# )\n\n\n# random_search_rf.fit(x_train, y_train)\n\n# print(\"Best Param:\", random_search_rf.best_params_)\n# print(\"Best ROC-AUC Score:\", random_search_rf.best_score_)\n\n# # 최적의 모델로 예측 및 평가\n# best_rf = random_search_rf.best_estimator_\n# rf_pred = best_rf.predict(x_test)\n# rf_pred_proba = best_rf.predict_proba(x_test)[:, 1]\n#============== 결과값이 나오지 않아 아래 와같이 하나하나 여러번 테스트 시도 [원래는 gridsearch 해도확인이 안되 randomnized를 적용하였으나 그래도 확인불가] 이유를 알수가 없음\n#============== 아래 하이퍼파라미터 튜닝도 하나하나 수정시 결과값 보는것이 너무 오래걸림 \n\n#랜덤포레스트 하이퍼파라미터 튜닝\nrf = RandomForestClassifier(\n    n_estimators=300,           \n    max_depth=30,                \n    min_samples_split=3,         \n    class_weight='balanced',     \n    random_state=123\n)\n\nrf.fit(x_train, y_train)\n\nrf_pred = rf.predict(x_test)\nrf_pred_proba = rf.predict_proba(x_test)[:, 1]\n\nprint(\"ROC-AUC Score:\", roc_auc_score(y_test, rf_pred_proba))\nprint(\"\\nClassification Report:\\n\", classification_report(y_test, rf_pred))\nprint(\"\\nConfusion Matrix:\\n\", confusion_matrix(y_test, rf_pred))\n\n#다양한 값을 시도했으나 기존값보다 좋은 결과를 보기 어려웠음(시간제약으로 더 많은 세밀한 수정은 불가)","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:56:52.127172Z","iopub.execute_input":"2024-11-12T06:56:52.127591Z","iopub.status.idle":"2024-11-12T06:59:42.005806Z","shell.execute_reply.started":"2024-11-12T06:56:52.127545Z","shell.execute_reply":"2024-11-12T06:59:42.004676Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# xgb 하이퍼파라미터 튜닝\nfrom sklearn.model_selection import RandomizedSearchCV\nxgb_model = XGBClassifier(random_state=123, use_label_encoder=False, eval_metric='logloss')\nparam_range = {\n    'n_estimators': [100, 200, 300],\n    'max_depth': [3, 5, 7],\n    'learning_rate': [0.01, 0.05, 0.1],\n    'subsample': [0.8, 1],\n    'colsample_bytree': [0.8, 1]\n}\n\nrandom_search = RandomizedSearchCV(\n    xgb_model, \n    param_distributions=param_range, \n    n_iter=5, \n    cv=5, \n    scoring='roc_auc',   \n    random_state=123\n)\n\nrandom_search.fit(x_train, y_train)\n\nprint(\"Best Param:\", random_search.best_params_)\nprint(\"Best ROC-AUC Score:\", random_search.best_score_)\n\nbest_xgb = random_search.best_estimator_\nxgb_pred = best_xgb.predict(x_test)\nxgb_pred_proba = best_xgb.predict_proba(x_test)[:, 1]","metadata":{"execution":{"iopub.status.busy":"2024-11-12T07:01:27.686356Z","iopub.execute_input":"2024-11-12T07:01:27.686794Z","iopub.status.idle":"2024-11-12T07:02:26.831563Z","shell.execute_reply.started":"2024-11-12T07:01:27.686753Z","shell.execute_reply":"2024-11-12T07:02:26.830679Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#하이퍼파라미터 값 적용\nxgb = XGBClassifier(\n    scale_pos_weight=1/0.03,      \n    n_estimators=300,             \n    max_depth=5,                 \n    learning_rate=0.1,            \n    subsample=0.8,                \n    colsample_bytree=1,           \n    random_state=123,\n    use_label_encoder=False,\n    eval_metric='logloss'\n)\n\nxgb.fit(x_train, y_train)\n\nxgb_pred = xgb.predict(x_test)\nxgb_pred_proba = xgb.predict_proba(x_test)[:, 1]\n\nprint(\"ROC-AUC Score:\", roc_auc_score(y_test, xgb_pred_proba))\nprint(\"\\nClassification Report:\\n\", classification_report(y_test, xgb_pred))\nprint(\"\\nConfusion Matrix:\\n\", confusion_matrix(y_test, xgb_pred))\n\n#종합적으로 기존보단 정상거래에 약간의 오탐률이 증가하였지만 목표는 사기탐지기에 사기탐지에서 높은 확률을 보여주어 결과적으로 튜닝 후 모델이 더 적합함을 확인","metadata":{"execution":{"iopub.status.busy":"2024-11-12T07:02:26.833698Z","iopub.execute_input":"2024-11-12T07:02:26.834493Z","iopub.status.idle":"2024-11-12T07:02:31.681264Z","shell.execute_reply.started":"2024-11-12T07:02:26.834444Z","shell.execute_reply":"2024-11-12T07:02:31.680218Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.preprocessing import StandardScaler\n\ntest_df['Hour'] = (test_df['Time'] // 3600) % 24  \n\nnew_scaler = StandardScaler()\nscaled_values = new_scaler.fit_transform(test_df[['Amount', 'Hour']])\ntest_df['scaled_Amount'] = scaled_values[:, 0]\ntest_df['scaled_Hour'] = scaled_values[:, 1]\n\ntest_df = test_df.drop(columns=['Amount', 'Hour', 'Time'], errors='ignore')\n\ntest_df['V16_V17'] = test_df['V16'] * test_df['V17']\ntest_df['V17_V18'] = test_df['V17'] * test_df['V18']\n\ny_pred = xgb.predict(test_df.drop(columns=['id'], errors='ignore'))\n\nsubmission = pd.DataFrame({'id': test_df['id'], 'Class': y_pred})\nprint(submission.head())\nsubmission.to_csv('submission.csv', index=False)\n","metadata":{"execution":{"iopub.status.busy":"2024-11-12T07:03:26.565186Z","iopub.execute_input":"2024-11-12T07:03:26.565593Z","iopub.status.idle":"2024-11-12T07:03:27.018584Z","shell.execute_reply.started":"2024-11-12T07:03:26.565555Z","shell.execute_reply":"2024-11-12T07:03:27.017493Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission","metadata":{"execution":{"iopub.status.busy":"2024-11-12T07:03:37.674243Z","iopub.execute_input":"2024-11-12T07:03:37.674648Z","iopub.status.idle":"2024-11-12T07:03:37.687344Z","shell.execute_reply.started":"2024-11-12T07:03:37.674609Z","shell.execute_reply":"2024-11-12T07:03:37.686196Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission[submission['Class']==1]","metadata":{"execution":{"iopub.status.busy":"2024-11-12T07:03:41.888814Z","iopub.execute_input":"2024-11-12T07:03:41.889351Z","iopub.status.idle":"2024-11-12T07:03:41.930491Z","shell.execute_reply.started":"2024-11-12T07:03:41.889303Z","shell.execute_reply":"2024-11-12T07:03:41.921905Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission[submission['Class']==0]","metadata":{"execution":{"iopub.status.busy":"2024-11-12T07:03:40.461945Z","iopub.execute_input":"2024-11-12T07:03:40.462342Z","iopub.status.idle":"2024-11-12T07:03:40.478168Z","shell.execute_reply.started":"2024-11-12T07:03:40.462304Z","shell.execute_reply":"2024-11-12T07:03:40.477019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}