{"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"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 데이터 불러오기","metadata":{}},{"cell_type":"code","source":"# 데이터위치 확인\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:31.166357Z","iopub.execute_input":"2024-11-13T18:01:31.166802Z","iopub.status.idle":"2024-11-13T18:01:31.597982Z","shell.execute_reply.started":"2024-11-13T18:01:31.166762Z","shell.execute_reply":"2024-11-13T18:01:31.596721Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 필요한 라이브러리 불러오기\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n%matplotlib inline","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:31.600291Z","iopub.execute_input":"2024-11-13T18:01:31.600939Z","iopub.status.idle":"2024-11-13T18:01:31.611612Z","shell.execute_reply.started":"2024-11-13T18:01:31.600887Z","shell.execute_reply":"2024-11-13T18:01:31.609876Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# train데이터 불러오기\ntrain_df = pd.read_csv('/kaggle/input/aiffel-ds-3-credit-card-fraud-detection/train.csv')\ndisplay(train_df.shape)\ndisplay(train_df.head(3))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:31.613176Z","iopub.execute_input":"2024-11-13T18:01:31.613787Z","iopub.status.idle":"2024-11-13T18:01:34.116029Z","shell.execute_reply.started":"2024-11-13T18:01:31.613727Z","shell.execute_reply":"2024-11-13T18:01:34.115025Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test데이터 불러오기\ntest_df = pd.read_csv('/kaggle/input/aiffel-ds-3-credit-card-fraud-detection/test.csv')\ntest_df.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:34.118340Z","iopub.execute_input":"2024-11-13T18:01:34.118720Z","iopub.status.idle":"2024-11-13T18:01:35.800120Z","shell.execute_reply.started":"2024-11-13T18:01:34.118681Z","shell.execute_reply":"2024-11-13T18:01:35.799019Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 모듈화","metadata":{}},{"cell_type":"code","source":"# 필요없는 변수 삭제하고 확인하는 모듈\n\ndef rm_cols(data=None, cols=None):\n    \n    data_copy = data.copy()\n    print(f'컬럼삭제 전 shape: {data_copy.shape}')\n    data_copy.drop(cols, axis = 1, inplace = True)\n    print(f'컬럼삭제 후 shape: {data_copy.shape}\\n')\n    \n    return data_copy","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:35.802090Z","iopub.execute_input":"2024-11-13T18:01:35.802597Z","iopub.status.idle":"2024-11-13T18:01:35.808465Z","shell.execute_reply.started":"2024-11-13T18:01:35.802547Z","shell.execute_reply":"2024-11-13T18:01:35.807428Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# class가 1에 속할 확률을 반환하는 모듈\n\ndef pred_proba(data, model):\n    return model.predict_proba(data)[:, 1]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:35.810009Z","iopub.execute_input":"2024-11-13T18:01:35.810930Z","iopub.status.idle":"2024-11-13T18:01:35.818687Z","shell.execute_reply.started":"2024-11-13T18:01:35.810880Z","shell.execute_reply":"2024-11-13T18:01:35.817538Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 데이터 탐색 및 전처리","metadata":{}},{"cell_type":"code","source":"# 데이터 탐색\ntrain_df.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:35.820430Z","iopub.execute_input":"2024-11-13T18:01:35.820823Z","iopub.status.idle":"2024-11-13T18:01:35.859568Z","shell.execute_reply.started":"2024-11-13T18:01:35.820779Z","shell.execute_reply":"2024-11-13T18:01:35.858282Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 기술통계량 확인\npd.set_option('display.max_columns', 50)\ntrain_df.describe()","metadata":{"execution":{"iopub.status.busy":"2024-11-13T18:01:35.860900Z","iopub.execute_input":"2024-11-13T18:01:35.861262Z","iopub.status.idle":"2024-11-13T18:01:36.187324Z","shell.execute_reply.started":"2024-11-13T18:01:35.861197Z","shell.execute_reply":"2024-11-13T18:01:36.186140Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"- 모두 수치형 데이터로 이루어져 있다.\n- id는 거래를 식별하는 변수\n- Time은 각 거래와 데이터셋의 첫 거래 사이의 경과 시간(초)\n- Amount는 신용카드 트랜잭션 금액\n- Class는 0의 경우 정상, 1의 경우 사기 트랜젝션\n- V1~V28은 평균이 0, 표준편차가 1에 가깝다. PCA와 표준화변환이 같이 이뤄진 것을 보인다.\n- 뚜렷한 결측치는 없어보인다(시간 절약상 결측치 확인은 따로 해주지 않았다.)","metadata":{}},{"cell_type":"markdown","source":"거래를 식별하는 id와 첫 거래사이의 경과시간을 나타내는 Time변수는 이상탐지에 영향을 주지 못할 것으로 예상하여 삭제한다.","metadata":{}},{"cell_type":"code","source":"# 훈련데이터에서 id, Time 변수 삭제\ntrain_df = rm_cols(train_df, ['id', 'Time'])\n\n# 테스트데이터에서 id추출\ntest_id = test_df['id']\n\n# 테스트데이터에서 id, Time 변수 삭제\ntest_df = rm_cols(test_df, ['id', 'Time'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:36.188637Z","iopub.execute_input":"2024-11-13T18:01:36.189009Z","iopub.status.idle":"2024-11-13T18:01:36.256543Z","shell.execute_reply.started":"2024-11-13T18:01:36.188971Z","shell.execute_reply":"2024-11-13T18:01:36.255041Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"각 변수를 시각화해보고 변환이 필요하면 변환한다.","metadata":{}},{"cell_type":"code","source":"# Amount 시각화\nimport seaborn as sns\n\ndisplay(train_df['Amount'].describe())\nsns.histplot(train_df['Amount'], bins = 100, kde = True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:36.259831Z","iopub.execute_input":"2024-11-13T18:01:36.260227Z","iopub.status.idle":"2024-11-13T18:01:37.849110Z","shell.execute_reply.started":"2024-11-13T18:01:36.260177Z","shell.execute_reply":"2024-11-13T18:01:37.847999Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"- Amount의 제 3사분위 수가  76.720000인데 최댓값이 19656.530000이다. 분포가 지나치게 왼쪽으로 치우쳐있다.\n- 로그변환을 한 뒤 분포를 확인해본다.","metadata":{"execution":{"iopub.status.busy":"2024-11-12T06:07:27.792259Z","iopub.execute_input":"2024-11-12T06:07:27.793164Z","iopub.status.idle":"2024-11-12T06:07:27.799910Z","shell.execute_reply.started":"2024-11-12T06:07:27.793114Z","shell.execute_reply":"2024-11-12T06:07:27.798667Z"}}},{"cell_type":"code","source":"# Amount 로그변환\nsns.histplot(np.log1p(train_df['Amount']), bins = 100, kde = True)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:37.850470Z","iopub.execute_input":"2024-11-13T18:01:37.851153Z","iopub.status.idle":"2024-11-13T18:01:38.979397Z","shell.execute_reply.started":"2024-11-13T18:01:37.851104Z","shell.execute_reply":"2024-11-13T18:01:38.978268Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"- 여전히 분포가 왼쪽으로 치우친 경향이 있으나, 어느정도 안정되었으므로, 변환한 변수를 사용해준다.","metadata":{}},{"cell_type":"code","source":"# Amount_scaled에 로그변환한 Amount저장\ntrain_df['Amount_scaled'] = np.log1p(train_df['Amount'])\ntest_df['Amount_scaled'] = np.log1p(test_df['Amount'])\n\n# 기존의 Amount변수 삭제\ntrain_df = rm_cols(train_df, ['Amount'])\ntest_df = rm_cols(test_df, ['Amount'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:38.980853Z","iopub.execute_input":"2024-11-13T18:01:38.981322Z","iopub.status.idle":"2024-11-13T18:01:39.103278Z","shell.execute_reply.started":"2024-11-13T18:01:38.981259Z","shell.execute_reply":"2024-11-13T18:01:39.101878Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"V1에서 V28까지의 변수를 시각화한다. ","metadata":{}},{"cell_type":"code","source":"# V1~V28 displot \n# 참고: 진짜 오래걸림 / histplot은 더 오래걸림\n# displot은 subplots 기능이 듣지 않아서 한 줄의 하나의 그래프만 생성함\n\nv_cols = train_df.columns[:28]\n\nfor i,col in enumerate(v_cols):\n    sns.displot(data=train_df, x=col, hue=\"Class\", kind=\"kde\", rug=True)\n    \nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:01:39.104609Z","iopub.execute_input":"2024-11-13T18:01:39.104994Z","iopub.status.idle":"2024-11-13T18:03:11.587431Z","shell.execute_reply.started":"2024-11-13T18:01:39.104955Z","shell.execute_reply":"2024-11-13T18:03:11.586263Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"위의 그래프를 보고 개인적으로 아래와 같이 판단해보았다.\n- class에 따른 분포의 차이가 보이는 변수: V1,2,3,4,7 ~ 12,14,16 ~ 18  \n- class에 따른 분포의 차이가 보이지 않는 변수:V5,6,13,15,19 ~ 28\n\nclass에 따른 분포의 차이가 보이지 않는 변수들에 대해 유의한 변수인지 독립표본검정을 통해 두 집단의 모평균을 비교하려고 했으나, 정규성검정과 등분산검정을 해야하고 정규성을 만족하지 않은 변수의 경우 비모수 검정을 따로 실시해주어야 해서 보류했다.","metadata":{}},{"cell_type":"markdown","source":"주어진 독립변수들에 대해 heatmap으로 시각해본다.","metadata":{}},{"cell_type":"code","source":"# heatmap\n\nplt.figure(figsize=(9,9))\ncorr=train_df.drop('Class',axis=1).corr()\nsns.heatmap(corr, cmap='RdBu')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:03:11.588703Z","iopub.execute_input":"2024-11-13T18:03:11.589045Z","iopub.status.idle":"2024-11-13T18:03:12.581645Z","shell.execute_reply.started":"2024-11-13T18:03:11.589011Z","shell.execute_reply":"2024-11-13T18:03:12.580482Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Amount_scaled에 대해 색이 진하게 나타난(상관관계가 있어보이는) 변수인 V2와 V5에 대해 상관계수를 확인해본다.","metadata":{}},{"cell_type":"code","source":"# Amount_scaled변수와 V2와 V5의 상관계수\ntrain_df[['V2','V5','Amount_scaled']].corr()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:03:12.583037Z","iopub.execute_input":"2024-11-13T18:03:12.583416Z","iopub.status.idle":"2024-11-13T18:03:12.603657Z","shell.execute_reply.started":"2024-11-13T18:03:12.583379Z","shell.execute_reply":"2024-11-13T18:03:12.602601Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"상관계수의 절댓값으로 따지면 0.5이하라 상관관계가 커보이지 않지만 변수가 많으므로 하나라도 줄이기 위해 삭제해준다.","metadata":{}},{"cell_type":"code","source":"# V2, V5 삭제\ntrain_df = rm_cols(train_df, ['V2','V5'])\ntest_df = rm_cols(test_df, ['V2','V5'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:03:12.604945Z","iopub.execute_input":"2024-11-13T18:03:12.605345Z","iopub.status.idle":"2024-11-13T18:03:12.669963Z","shell.execute_reply.started":"2024-11-13T18:03:12.605307Z","shell.execute_reply":"2024-11-13T18:03:12.668838Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 성능비교\n---\n해당노트북으로 코드를 작성하기 전, \n- id, Time 컬럼을 삭제하고,\n- train데이터를 훈련데이터와 검증데이터로 8:2로 stratified하게 나눈뒤,\n- LogisticRegression(max_iter=1000)를 적용했을 때\nroc-auc score가 검증데이터, 테스트데이터 대상으로 각각 0.98517, 0.97287로 높은 성능이 나와, 전처리 단계마다 해당 모델로 비교해줌.\n\n\n**1. id, Time삭제 / Amount컬럼 로그변환 : 0.98559 / 0.97111**  \n**2. 1 + V2,V5 컬럼삭제: 0.98548 / 0.97252**\n","metadata":{}},{"cell_type":"markdown","source":"# 샘플링","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\ny_target = train_df['Class']\nX_features = train_df.drop('Class', axis = 1)\n\nX_train, X_test, y_train, y_test = train_test_split(X_features,\n                                                    y_target, \n                                                    test_size=0.2, \n                                                    random_state=2024, \n                                                    stratify=y_target)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:03:12.671484Z","iopub.execute_input":"2024-11-13T18:03:12.671947Z","iopub.status.idle":"2024-11-13T18:03:12.785250Z","shell.execute_reply.started":"2024-11-13T18:03:12.671896Z","shell.execute_reply":"2024-11-13T18:03:12.783923Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # SMOTE 샘플링\n# from imblearn.over_sampling import SMOTE\n\n# smote = SMOTE(random_state=0)\n# X_train_over, y_train_over = smote.fit_resample(X_train, y_train)\n# print(X_train.shape, y_train.shape)\n# print(X_train_over.shape, y_train_over.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:03:12.786864Z","iopub.execute_input":"2024-11-13T18:03:12.787388Z","iopub.status.idle":"2024-11-13T18:03:12.793908Z","shell.execute_reply.started":"2024-11-13T18:03:12.787330Z","shell.execute_reply":"2024-11-13T18:03:12.792701Z"},"_kg_hide-output":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 성능비교\n---\ntrain데이터를 훈련데이터와 검증데이터로 8:2로 stratified하게 나눈뒤, \nLogisticRegression(max_iter=1000)를 적용\n\n- id, Time삭제 / Amount컬럼 로그변환 : 0.98559 / 0.97111\n- 1 + V2,V5 컬럼삭제: 0.98548 / 0.97252\n\n**SMOTE 오버샘플링: 0.97564 / 0.96799**\n\n오버샘플링했을 때 성능이 오히려 떨어지므로 오버샘플링은 하지 않는다.","metadata":{"execution":{"iopub.status.busy":"2024-11-13T17:15:13.185105Z","iopub.execute_input":"2024-11-13T17:15:13.186146Z","iopub.status.idle":"2024-11-13T17:15:13.193971Z","shell.execute_reply.started":"2024-11-13T17:15:13.186097Z","shell.execute_reply":"2024-11-13T17:15:13.192477Z"}}},{"cell_type":"markdown","source":"# 모델링\n---\nLogisticRegression(), RandomForestClassifier(), LGBMClassifier(), XGBClassifier() 사용 ","metadata":{}},{"cell_type":"markdown","source":"## LogisticRegression\n---\nmax_iter=1000만 설정한 기본모델을 사용했고, 그 기본모델을 이후 앙상블 학습을 위해 사용하였다. 이후 규제강도(정규화강도)의 역수를 나타내는 C, 사용할 규제를 정하는 penalty, 최적화 알고리즘인 solver를 직접 조정하며 성능을 비교했다.","metadata":{}},{"cell_type":"code","source":"from sklearn.linear_model import LogisticRegression\nfrom sklearn.metrics import roc_auc_score\n\n# lr_clf = LogisticRegression(max_iter=1000)\nlr_clf = LogisticRegression(max_iter=1000,\n                            C=0.5,\n                            penalty='l1',\n                            solver='saga')  \nlr_clf.fit(X_train, y_train)\n\nroc_auc_score(y_test, pred_proba(X_test, lr_clf))\n\n# 성능비교(max_iter=1000을 기본으로 설정)\n# 기본(lbfgs, l2): 0.9854839629249541\n# lbfgs는 l1패널티 지원안함\n# saga는 성능이 좋아지긴 한데 시간이 오래걸림\n# saga, l2: 0.9851296649236835\n# saga, l1: 0.9852909316001237\n# saga, l1, c=0.5: 0.9855409763964228\n# saga, l1, c=0.1: 0.9837959569303947","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:03:12.811060Z","iopub.execute_input":"2024-11-13T18:03:12.811900Z","iopub.status.idle":"2024-11-13T18:05:16.941531Z","shell.execute_reply.started":"2024-11-13T18:03:12.811847Z","shell.execute_reply":"2024-11-13T18:05:16.940002Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 성능비교\n---\ntrain데이터를 훈련데이터와 검증데이터로 8:2로 stratified하게 나눈뒤, \nLogisticRegression(max_iter=1000)를 적용\n\n- id, Time삭제 / Amount컬럼 로그변환 : 0.98559 / 0.97111\n- 1 + V2,V5 컬럼삭제: 0.98548 / 0.97252\n- SMOTE 오버샘플링: 0.97564 / 0.96799  -> 오버샘플링 제외\n\nmax_iter=1000로 설정하고   \n1. 기본(lbfgs, l2): 0.98548\n2. saga, l2: 0.98512\n3. saga, l2: 0.98529\n\n\n**4. saga, l1, c=0.5: 0.98554 / 0.97397**  \n\n로지스틱회귀의 하이퍼파라미터를 max_iter=1000, C=0.5, penalty='l1', solver='saga'로 설정했을 때 가장 좋은 성능을 보였다.","metadata":{}},{"cell_type":"markdown","source":"## RandomForest\n---\nrandom_state=2024만 파라미터로 설정하고 모델을 실행해주었다.\n이후에 앙상블에도 해당모델을 그대로 넣어주었다.","metadata":{}},{"cell_type":"code","source":"from sklearn.ensemble import RandomForestClassifier\n\nrf_clf = RandomForestClassifier(random_state=2024)\nrf_clf.fit(X_train, y_train)\n\nroc_auc_score(y_test, pred_proba(X_test, rf_clf))\n\n# 기본: 0.9430606460440795","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-12T07:48:19.059522Z","iopub.execute_input":"2024-11-12T07:48:19.059917Z","iopub.status.idle":"2024-11-12T07:49:58.398038Z","shell.execute_reply.started":"2024-11-12T07:48:19.059878Z","shell.execute_reply":"2024-11-12T07:49:58.396914Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"점수가 0.94306으로 이전에 실행한 모델들보다 성능이 떨어져 제출하지 않았다.","metadata":{}},{"cell_type":"markdown","source":"## LightGBM\n--- \n다른 모델들과 비교해서 random_state를 제외한 파라미터설정을 해주지 않은 상태에서 성능이 0.9아래로 떨어져 베이지안 최적화 기반의 HyperOpt를 이용한 하이퍼파라미터 튜닝을 해주었다. 튜닝을 할 하이퍼파라미터와 범위는 교재에 실린 '캐글 산탄데르 고객 만족 예측'에 있는 하이퍼파라미터를 참고했다.","metadata":{}},{"cell_type":"code","source":"# 하이퍼 파라미터 검색 공간 설정\nfrom hyperopt import hp\n\nlgbm_search_space = {'num_leaves': hp.quniform('num_leaves', 32, 64, 1),\n                     'max_depth': hp.quniform('max_depth', 100, 160, 1),\n                     'min_child_samples': hp.quniform('min_child_samples', 60, 100, 1),\n                     'subsample': hp.uniform('subsample', 0.7, 1),\n                     'learning_rate':hp.uniform('learning_rate', 0.01, 0.2)}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:26:38.695570Z","iopub.execute_input":"2024-11-13T18:26:38.696048Z","iopub.status.idle":"2024-11-13T18:26:39.282452Z","shell.execute_reply.started":"2024-11-13T18:26:38.696007Z","shell.execute_reply":"2024-11-13T18:26:39.280998Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 목적함수 생성\nfrom sklearn.model_selection import KFold\nfrom lightgbm import LGBMClassifier\n\ndef objective_func(search_space):\n  lgbm_clf = LGBMClassifier(n_estimators=100,\n                            num_leaves=int(search_space['num_leaves']),\n                            max_depth=int(search_space['max_depth']),\n                            min_child_samples=int(search_space['min_child_samples']),\n                            subsample=search_space['subsample'],\n                            learning_rate=search_space['learning_rate'],\n                            early_stopping_rounds = 30)\n\n  roc_auc_list = []\n\n  kf = KFold(n_splits=5)\n\n  for tr_index, val_index in kf.split(X_train):\n    X_tr, y_tr = X_train.iloc[tr_index], y_train.iloc[tr_index]\n    X_val, y_val = X_train.iloc[val_index], y_train.iloc[val_index]\n\n    lgbm_clf.fit(X_tr, y_tr,\n                 eval_metric=\"auc\",\n                 eval_set=[(X_tr, y_tr), (X_val, y_val)])\n\n    score = roc_auc_score(y_val, lgbm_clf.predict_proba(X_val)[:,1])\n    roc_auc_list.append(score)\n\n    # 3개 kfold로 계산된 roc_auc값의 평균값을 반환하되,\n    # HyperOpt는 목적함수의 최솟값을 위한 입력값을 찾으므로 -1을 곱한 뒤 반환\n    return (-1)*np.mean(roc_auc_list)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:26:52.517545Z","iopub.execute_input":"2024-11-13T18:26:52.518361Z","iopub.status.idle":"2024-11-13T18:26:53.519717Z","shell.execute_reply.started":"2024-11-13T18:26:52.518310Z","shell.execute_reply":"2024-11-13T18:26:53.518596Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 최적 하이퍼 파라미터 도출\nfrom hyperopt import fmin, tpe, Trials\n\ntrials = Trials()\n\n# fmin() 함수를 도출. max_evals 지정된 횟수만큼 반복 후 목적함수이 최솟값을 가지는 최적 입력값 추출\nbest = fmin(fn=objective_func,\n            space=lgbm_search_space,\n            algo=tpe.suggest,\n            max_evals=50,  # 최대 반복 횟수\n            trials=trials,\n            rstate=np.random.default_rng(seed=30))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:27:04.799121Z","iopub.execute_input":"2024-11-13T18:27:04.800435Z","iopub.status.idle":"2024-11-13T18:29:49.168595Z","shell.execute_reply.started":"2024-11-13T18:27:04.800387Z","shell.execute_reply":"2024-11-13T18:29:49.167277Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 최적의 하이퍼파라미터 값\nbest","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:30:08.171189Z","iopub.execute_input":"2024-11-13T18:30:08.172063Z","iopub.status.idle":"2024-11-13T18:30:08.179125Z","shell.execute_reply.started":"2024-11-13T18:30:08.172018Z","shell.execute_reply":"2024-11-13T18:30:08.177826Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from lightgbm import LGBMClassifier\nfrom sklearn.metrics import roc_auc_score\n\n# 도출된 최적의 하이퍼파라미터를 이용해 LightGBM 학습\nlgbm_clf = LGBMClassifier(n_estimators=500,\n                          num_leaves=int(best['num_leaves']),\n                          max_depth=int(best['max_depth']),\n                          min_child_samples=int(best['min_child_samples']),\n                          subsample=round(best['subsample'], 5),\n                          learning_rate=round(best['learning_rate'], 5),\n                          early_stopping_round=100,\n                          force_row_wise=True)\n\nlgbm_clf.fit(X_train, y_train,\n             eval_metric='auc',\n             eval_set=[(X_train, y_train)])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:30:14.196989Z","iopub.execute_input":"2024-11-13T18:30:14.197437Z","iopub.status.idle":"2024-11-13T18:30:46.568873Z","shell.execute_reply.started":"2024-11-13T18:30:14.197393Z","shell.execute_reply":"2024-11-13T18:30:46.567803Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 검증 데이터에서 ROC-AUC 평가\nroc_auc_score(y_test, pred_proba(X_test, lgbm_clf))\n\n# 기본: 0.8350539184544461\n# n_estimators=500,early_stopping_round=100: 0.588724975158416\n# cv=3, hyperopts: 0.9591388522373716\n# cv=5, hyperopts:0.9621581227907279","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T18:30:55.846928Z","iopub.execute_input":"2024-11-13T18:30:55.848236Z","iopub.status.idle":"2024-11-13T18:30:57.235990Z","shell.execute_reply.started":"2024-11-13T18:30:55.848160Z","shell.execute_reply":"2024-11-13T18:30:57.234777Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 성능비교\n---\ntrain데이터를 훈련데이터와 검증데이터로 8:2로 stratified하게 나눈뒤, \nLogisticRegression(max_iter=1000)를 적용\n\n- id, Time삭제 / Amount컬럼 로그변환 : 0.98559 / 0.97111\n- 1 + V2,V5 컬럼삭제: 0.98548 / 0.97252\n- SMOTE 오버샘플링: 0.97564 / 0.96799  -> 오버샘플링 제외\n- 로지스틱회귀 하이퍼파라미터 튜닝(saga, l1, c=0.5): 0.98554 / 0.97397\n\nLGBMClassifier에서  \n\n1. 기본: 0.83505\n2. n_estimators=500,early_stopping_round=100: 0.58872\n-> 성능이 유난히 낮게 나왔는데, learning_rate를 설정하지 않아 기본값이 0.1로 설정되어 학습이 빠르게 일어나 예측기를 다 사용하기전에 수렴하여 학습이 제대로 이루어지지 못한것으로 추정된다(n_estimators가 500정도 되는 경우 learning_rate=0.01으로 설정해서 사용되는 걸로 보인다)\n4. cv=3, hyperopts: 0.95914\n\n**cv=5, hyperopts: 0.96216 / 0.96797**   \n이 경우 테스트데이터에서 성능이 더 잘나왔다...\n","metadata":{}},{"cell_type":"markdown","source":"## XGBoost\n---\n기본모델을 이용해 성능을 측정하고, 이후 앙상블 학습을 위해 기본모델을 그대로 사용하였다.","metadata":{}},{"cell_type":"code","source":"# xgboost\nfrom xgboost import XGBClassifier\n\nxgb_clf = XGBClassifier(random_state = 2024)\n\nxgb_clf.fit(X_train, y_train)\n\nroc_auc_score(y_test, pred_proba(X_test, xgb_clf))\n# 기본: 0.9678093795305348","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-13T19:00:27.174133Z","iopub.execute_input":"2024-11-13T19:00:27.176692Z","iopub.status.idle":"2024-11-13T19:00:32.024979Z","shell.execute_reply.started":"2024-11-13T19:00:27.176578Z","shell.execute_reply":"2024-11-13T19:00:32.023766Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 앙상블\n---\n위의 4가지 모델을 이용해 앙상블 모델을 적합하려고 했으나 시간이 오래걸려, 성능이 낮게 측정된 lightGBM을 제외하고 나머지 3개의 모델로 앙상블 학습을 진행했다. voting은 다수결의 hard보다 확률에 따라 결정되는 soft방식을 사용하였다.","metadata":{}},{"cell_type":"code","source":"from sklearn.ensemble import VotingClassifier\n\n# 성능이 낮게 측정된 lgbm제거\nvoting = VotingClassifier(estimators=[('LR', lr_clf),('RF', rf_clf),('XGB', xgb_clf)],\n                         voting = 'soft')\n\nvoting.fit(X_train, y_train)\nroc_auc_score(y_test, pred_proba(X_test, voting))\n\n# 기본모델사용: 0.9842361823779505","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-11-12T08:00:38.168137Z","iopub.execute_input":"2024-11-12T08:00:38.169052Z","iopub.status.idle":"2024-11-12T08:02:21.637538Z","shell.execute_reply.started":"2024-11-12T08:00:38.169012Z","shell.execute_reply":"2024-11-12T08:02:21.636756Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 성능비교\n---\ntrain데이터를 훈련데이터와 검증데이터로 8:2로 stratified하게 나눈뒤, \nLogisticRegression(max_iter=1000)를 적용\n\n- id, Time삭제 / Amount컬럼 로그변환 : 0.98559 / 0.97111\n- 1 + V2,V5 컬럼삭제: 0.98548 / 0.97252\n- SMOTE 오버샘플링: 0.97564 / 0.96799  -> 오버샘플링 제외\n- 로지스틱회귀 하이퍼파라미터 튜닝(saga, l1, c=0.5): 0.98554 / 0.97397\n- LGBMClassifier에서 데이터를 5조각으로 나눠 hyperopts: 0.96216 / 0.96797\n\nrandom_state외에 하이퍼파라미터를 설정하지 않은 기본모델인 logisticRegression, RandomForestClassifier, XGBClassifier를 이용한 앙상블 모델에서  \n\n**기본모델사용: 0.98424 / 0.97762**\n\n으로 제일 좋은 점수가 나왔다.","metadata":{}},{"cell_type":"markdown","source":"# 회고","metadata":{}},{"cell_type":"markdown","source":"1. 목표 및 문제 정의\n- 목표: 데이터을 꼼꼼히 살펴보고 인사이트를 얻어 모델링을 하기보다, 주어진 시간안에 배운내용을 최대한 적용하며 성능평가점수인 roc-auc점수를 늘리는데 집중했다.\n- 본질을 흐리는 목표일 수 있으나, 제출을 많이 해 캐글을 경험하는데 집중하려고 했다. 그러다보니 해보지 못한 시도들에 대한 아쉬움이 많이 있다.\n\n2. 데이터 전처리 및 탐색\n- 데이터에 변수가 많고, id,Time,Amount,Class외에는 다른 변수가 가지는 의미를 알지 못하므로 데이터를 꼼꼼히 보려고 하지 않았던 것 같다.\n- V1~V28의 변수를 확인했을 때 평균이 0이고 표준편차가 1근처의 값을 가지는데, 최댓값과 최솟값에서 이상치를 가지는 변수들이 눈에 띄였다. class에 따른 모평균 검정으로 필요없는 변수들을 정리해준뒤, 남은 변수들에서 이상치를 찾아내고 싶었지만 시간때문에 시도해보지 못한게 아쉽다.\n- 데이터 시각화할 때 변수 하나하나를 자세히 다뤄보고 싶었다. 가장 대표적으로 target변수인 Class변수에서 각 범주의 비율을 나타내는 barchart를 시각화해보지 못한 아쉬움이 있다. 또한 현재 노트북에는 담지 못했지만, V1의 분포가 봉우리가 3개 있는 다봉분포를 이뤘는데, 하나의 변수에 여러집단의 특성이 나타나는 것 같아 Class에 따른 시각화를 하지 못한 점이 아쉬웠다. 만약 Class에 따른 차이가 없다면 해당변수를 범주화하는 방향으로도 생각해보았을 것 같다.\n- 데이터 시각화를 할 때 오류가 자주났었다.그래프에 적합한 데이터셋의 형태를 만들어주지 못했거나 해당 그래프에 적용되지 않는 기능을 넣으려고 할 때 오류가 났다. pivot_table()을 만드는 연습이 부족했던 것 같다고 느꼈다. 또 실행시간을 줄이기 위해 pandas를 이용해 그래프를 그리는 시도를 하는 쪽으로 해결해보았으면 하는 아쉬움이 있다.\n\n3. 특성 엔지니어링 및 변수 선택\n- 데이터 전처리를 할 때 Time변수는 무조건 제거한다고 생각했고, Amount변수는 중요한 변수라고 미리 전제를 놓고 진행했는데, 그것을 EDA로 확인해보았으면 하는 아쉬움이 있었다.\n- Amount변수를 로그변환이 아닌 1/4승으로 변환하거나 MinMaxScaler를 사용하는 등 다른 시도를 해보았으면 하는 아쉬움이 있었다.\n\n\n4. 모델 선택 및 하이퍼파라미터 튜닝\n- 모델 선택은 노드에서 소개된 모델과 책에서 소개된 모델만 다뤘다. 그러다보니 새로운 모델을 사용해보지 못했다는 아쉬움이 있다. 나중에 분류모델링을 다시하게 된다면 catboost와 knn등도 다뤄보고 싶다.\n- 시간부족의 문제로 randomforest와 xgboost에 하이퍼파라미터 튜닝을 해보지 못한게 아쉽다.\n- 로지스틱회귀의 경우 하이퍼파라미터 튜닝을 진행할 때 각 인자의 의미를 알지 못하고 무작위로 조합을 해본 뒤 성능이 잘 나온 모델을 채택했다. 처음에는 막막했는데, 앞으로 하이퍼파라미터의 특성을 알아가고 여러 경우로 나눠 실험해보는 경험이 많이 필요한게 아닐까라는 생각이 들었다.\n- 다른 모델들과 비교해서 로지스틱회귀에서 성능이 높게 나왔는데, 그 이유가 독립변수들이 주성분분석으로 변환되었기 때문에 노이즈가 적어서 그런지, 변수는 많지만 class를 구분하는 경계가 복잡하지 않아서인지 모르겠다. 데이터 탐색의 부족이 모델링까지 영향을 미치는 것 같다.\n- lightgbm 모델에서 n_estimators를 설정하고 그에 맞는 learning_rate를 설정해주지 않아 점수가 0.58872로 매우 적게 나왔다. 각 하이퍼파라미터의 관계를 생각하며 적절한 인자를 넣어주어야 좋은 성능이 나올 수 있음을 확인했다.   \n- 기본 하이퍼파라미터를 사용해서 만든 앙상블 모델을 이용해 성능개선을 이뤘다. 시간상의 문제로 하이퍼파라미터 튜닝을 한 각각의 모델을 이용해 앙상블을 진행하지 못한게 아쉽다.\n\n5. 성능 평가 및 지표 \n- 전처리, 샘플링, 하이퍼파라미터 튜닝을 하며 대회에서 제시하는 roc-auc score에만 집중했다. 생각해보면, 사기거래의 데이터는 전체거래에서 차지하는 비율이 작으므로 데이터의 불균형이 심하다. roc-auc그래프에서 x축은 실제 정상거래지만 사기거래로 잘못 예측할 비율이고, y축은 실제 사기거래를 사기거래라 예측한 비율이다. 당연히 정상거래가 많으므로 x축의 해당하는 '1-특이도'의 값은 작게 나올 것이고,사기거래의 수가 작으므로 y축의 해당하는 값은 상대적으로 크게 나올 가능성이 있다.\n- 이 데이터를 전달한 신용카드사와 해당 카드사의 고객이 중요하다고 생각하는 지표가 무엇인지 생각해보았을때,\n    - 신용카드사:  카드사는 사기거래건을 잡아내지 못하는 게 손해로 이어질 수 있으므로, 실제 사기거래건에서 사기라고 예측한 비율인 재현율(Recall)\n    - 고객: 본인의 정상적인 거래가 억울하게 사기거래로 오인되지 않는게 중요하므로, 모델이 사기라고 판단한 거래들 중 진짜 사기인 비율인 정밀도(Precision)\n    - 신용카드사와 고객을 생각한다면, 재현율과 정밀도가 균형을 잘 이루고 있는지 확인하기 위해 f1-score\n  라고 생각해, 지표를 확인할 때 재현율과 정밀도 그리고 f1-score를 같이 확인하며 모델의 성능을 확인해보지 못한 아쉬움이 있다.\n\n\n","metadata":{"execution":{"iopub.status.busy":"2024-11-13T20:00:17.404742Z","iopub.execute_input":"2024-11-13T20:00:17.405287Z","iopub.status.idle":"2024-11-13T20:00:17.417950Z","shell.execute_reply.started":"2024-11-13T20:00:17.405231Z","shell.execute_reply":"2024-11-13T20:00:17.416080Z"}}},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}