{ "cells": [ { "cell_type": "markdown", "id": "97ea11e7-1416-4cc5-aa59-eb00dd2b2090", "metadata": {}, "source": [ "### 분류 실습 - 캐글 신용카드 사기 검출\n", "\n", "- 캐글의 신용카드 데이터 세트를 이용해 신용카드 사기 검출 분류 실습\n", "- 코드의 빈칸(###) 채우거나 물음에 답하면 됨\n", "\n", "1. 데이터 일차 가공 및 모델 학습/예측/평가\n", "2. 이상치 데이터 제거 후 모델 학습/예측/평가" ] }, { "cell_type": "markdown", "id": "db9e0f12-aba8-464b-b9c9-65eae04ef4e1", "metadata": {}, "source": [ "#### 1. 데이터 일차 가공 및 모델 학습/예측/평가\n", "\n", "밑의 주소를 클릭하여 creaditcard.csv 파일 다운받기 \\\n", "https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud" ] }, { "cell_type": "code", "execution_count": 1, "id": "ec3c46b8-0e05-4050-b60e-17199e302d86", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
TimeV1V2V3V4V5V6V7V8V9...V21V22V23V24V25V26V27V28AmountClass
00.0-1.359807-0.0727812.5363471.378155-0.3383210.4623880.2395990.0986980.363787...-0.0183070.277838-0.1104740.0669280.128539-0.1891150.133558-0.021053149.620
10.01.1918570.2661510.1664800.4481540.060018-0.082361-0.0788030.085102-0.255425...-0.225775-0.6386720.101288-0.3398460.1671700.125895-0.0089830.0147242.690
21.0-1.358354-1.3401631.7732090.379780-0.5031981.8004990.7914610.247676-1.514654...0.2479980.7716790.909412-0.689281-0.327642-0.139097-0.055353-0.059752378.660
31.0-0.966272-0.1852261.792993-0.863291-0.0103091.2472030.2376090.377436-1.387024...-0.1083000.005274-0.190321-1.1755750.647376-0.2219290.0627230.061458123.500
42.0-1.1582330.8777371.5487180.403034-0.4071930.0959210.592941-0.2705330.817739...-0.0094310.798278-0.1374580.141267-0.2060100.5022920.2194220.21515369.990
\n", "

5 rows × 31 columns

\n", "
" ], "text/plain": [ " Time V1 V2 V3 V4 V5 V6 V7 \\\n", "0 0.0 -1.359807 -0.072781 2.536347 1.378155 -0.338321 0.462388 0.239599 \n", "1 0.0 1.191857 0.266151 0.166480 0.448154 0.060018 -0.082361 -0.078803 \n", "2 1.0 -1.358354 -1.340163 1.773209 0.379780 -0.503198 1.800499 0.791461 \n", "3 1.0 -0.966272 -0.185226 1.792993 -0.863291 -0.010309 1.247203 0.237609 \n", "4 2.0 -1.158233 0.877737 1.548718 0.403034 -0.407193 0.095921 0.592941 \n", "\n", " V8 V9 ... V21 V22 V23 V24 V25 \\\n", "0 0.098698 0.363787 ... -0.018307 0.277838 -0.110474 0.066928 0.128539 \n", "1 0.085102 -0.255425 ... -0.225775 -0.638672 0.101288 -0.339846 0.167170 \n", "2 0.247676 -1.514654 ... 0.247998 0.771679 0.909412 -0.689281 -0.327642 \n", "3 0.377436 -1.387024 ... -0.108300 0.005274 -0.190321 -1.175575 0.647376 \n", "4 -0.270533 0.817739 ... -0.009431 0.798278 -0.137458 0.141267 -0.206010 \n", "\n", " V26 V27 V28 Amount Class \n", "0 -0.189115 0.133558 -0.021053 149.62 0 \n", "1 0.125895 -0.008983 0.014724 2.69 0 \n", "2 -0.139097 -0.055353 -0.059752 378.66 0 \n", "3 -0.221929 0.062723 0.061458 123.50 0 \n", "4 0.502292 0.219422 0.215153 69.99 0 \n", "\n", "[5 rows x 31 columns]" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# 다운로드 받은 creditcard.csv 파일을 DataFrame 으로 로딩하기\n", "import pandas as pd\n", "import numpy as np\n", "import matplotlib.pyplot as plt \n", "import warnings \n", "warnings.filterwarnings(\"ignore\") \n", "%matplotlib inline\n", "\n", "card_df = pd.read_csv('creditcard.csv') \n", "card_df.####()" ] }, { "cell_type": "markdown", "id": "110027ae-68a6-4117-acd1-c8e78869aff1", "metadata": {}, "source": [ "- Amount 피처는 신용카드 트랜잭션 금액을 의미\n", "- Class 는 레이블로서 0의 경우 정상, 1의 경우 사기 트랜잭션" ] }, { "cell_type": "code", "execution_count": 5, "id": "706b2203-6887-4557-b8cb-9ec4a733ec07", "metadata": {}, "outputs": [], "source": [ "# info() 를 사용하여 데이터의 결측치와 형태 확인하는 코드 작성하기" ] }, { "cell_type": "code", "execution_count": 49, "id": "e0da9765-4a52-4436-83f6-8ba10f87eaa3", "metadata": {}, "outputs": [], "source": [ "# 예측 성능을 비교하기 위해 인자로 인력된 DataFrame 을 복사한 뒤 이를 가공하여 반환하는 get_preprocessed_df() 함수와\n", "# 데이터 가공 후 학습/테스트 데이터 세트를 반환하는 get_train_test_df() 함수 생성\n", "\n", "from sklearn.model_selection import ################\n", "\n", "# Time 피처는 데이터 생성 관련한 작업용 속성으로서 큰 의미가 없기 때문에 제거하는 코드 작성\n", "# 인자로 입력받은 DataFrame을 복사한 뒤 Time 칼럼만 삭제하고 복사된 DataFrame 반환 \n", "\n", "def get_preprocessed_df(df=None) :\n", " df_copy = df.copy()\n", " df_copy.####('Time', axis=1, inplace=True)\n", " return df_copy" ] }, { "cell_type": "code", "execution_count": 50, "id": "5954214e-4150-4866-a83f-a248e9c75313", "metadata": {}, "outputs": [], "source": [ "# 사전 데이터 가공 후 학습과 테스트 데이터 세트를 반환하는 함수.\n", "def get_train_test_dataset(df=None):\n", " \n", " # 인자로 입력된 DataFrame의 사전 데이터 가공이 완료된 복사 DataFrame 반환\n", " df_copy = get_preprocessed_df(df)\n", " \n", " # DataFrame의 맨 마지막 칼럼이 레이블, 나머지는 피처들\n", " X_features = df_copy.iloc[:, :-1]\n", " y_target = df_copy.iloc[:, -1]\n", " \n", " # train_test_split( )으로 학습과 테스트 데이터 분할. stratify=y_target으로 Stratified 기반 분할 \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", " \n", " # 학습과 테스트 데이터 세트 반환\n", " return X_train, X_test, y_train, y_test\n", "\n", "X_train, X_test, y_train, y_test = #####################(card_df)" ] }, { "cell_type": "code", "execution_count": 51, "id": "7a52e465-c44a-4497-8134-30c4acf0049a", "metadata": {}, "outputs": [], "source": [ "# 생성한 학습 데이터 세트와 테스트 데이터 세트의 레이블 값 비율을 백분율로 환산해서 서로 비슷하게 분할 되었는지 확인하는 코드 작성하기" ] }, { "cell_type": "code", "execution_count": 52, "id": "4e85ce06-8c2d-4f28-ac67-60d9fce3d4c8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "오차 행렬\n", "[[85281 14]\n", " [ 58 90]]\n", "정확도: 0.9992, 정밀도: 0.8654, 재현율: 0.6081, F1 : 0.7143, AUC:0.9713\n" ] } ], "source": [ "# 로지스틱 회귀를 이용해 신용 카드 사기 여부를 예측하기\n", "from sklearn.linear_model import ##################\n", "\n", "lr_clf = ##################(max_iter=1000) \n", "lr_clf.fit(X_train, y_train)\n", "lr_pred = lr_clf.predict(X_test)\n", "lr_pred_proba = lr_clf.predict_proba(X_test)[:, 1]\n", "\n", "# 정확도, 오차행렬, 정밀도, 재현율, F1 score, AUC 출력하는 get_clf_eval 함수 생성하고 출력하기\n", "from sklearn.metrics import accuracy_score\n", "from sklearn.metrics import confusion_matrix\n", "from sklearn.metrics import precision_score\n", "from sklearn.metrics import f1_score\n", "from sklearn.metrics import recall_score\n", "from sklearn.metrics import #############\n", "\n", "\n", "def get_clf_eval(y_test, pred=None, pred_proba=None): \n", " confusion = confusion_matrix(y_test, pred) \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 = #############(y_test, pred_proba)\n", " print('오차 행렬')\n", " print(confusion)\n", " print('정확도: {0:.4f}, 정밀도: {1:.4f}, 재현율: {2:.4f}, F1 : {3:.4f}, AUC:{4:.4f}'.format(accuracy, precision, recall, f1, roc_auc))\n", "\n", "get_clf_eval(y_test, lr_pred, lr_pred_proba)" ] }, { "cell_type": "code", "execution_count": 23, "id": "16440642-14fc-4e5b-bb0d-eb7adcf49313", "metadata": {}, "outputs": [], "source": [ "# 이 문제의 경우 정밀도와 재현율 중 어떤 것의 수치가 더 중요한지 이유와 함께 적어보기" ] }, { "cell_type": "code", "execution_count": 26, "id": "ff4189c6-edf7-4eed-91f2-152fbb8927dd", "metadata": {}, "outputs": [], "source": [ "# LightGBM을 이용하여 모델 만들기\n", "\n", "# 인자로 사이킷런의 Estimator 객체와 학습/테스트 데이터 세트를 입력받아서 학습/예측/평가 수행. \n", "def get_model_train_eval(#####, ftr_train=None, ftr_test=None, tgt_train=None, tgt_test=None):\n", " #####.fit(ftr_train, tgt_train)\n", " pred = #####.predict(ftr_test)\n", " pred_proba = #####.predict_proba(ftr_test)[:, 1] \n", " get_clf_eval(tgt_test, pred, pred_proba)" ] }, { "cell_type": "code", "execution_count": 33, "id": "a5d307e6-323d-4b59-96a6-3f7b19a1b91a", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "오차 행렬\n", "[[85290 5]\n", " [ 36 112]]\n", "정확도: 0.9995, 정밀도: 0.9573, 재현율: 0.7568,F1 : 0.8453, AUC:0.9790\n" ] } ], "source": [ "# LightGBM으로 모델을 학습한 뒤 별도의 테스트 데이터 세트에서 예측 평가 수행\n", "import warnings \n", "warnings.filterwarnings(\"ignore\") \n", "%matplotlib inline\n", "from lightgbm import ##############\n", "\n", "import lightgbm as lgb\n", "\n", "lgbm_params = {\n", " 'verbosity': -1, # 더 이상 경고 메시지 출력하지 않음\n", " 'force_col_wise': True, # 경고 메시지 제거를 위한 추가 설정\n", " # 다른 파라미터들...\n", "}\n", "\n", "lgbm_clf = ##############(n_estimators=1000, num_leaves=64, n_jobs=-1, boost_from_average=False, **lgbm_params) \n", "get_model_train_eval(lgbm_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)" ] }, { "cell_type": "code", "execution_count": 34, "id": "958edde1-35ab-4846-a544-ebcb8d0767a9", "metadata": {}, "outputs": [], "source": [ "# 위의 출력결과를 로지스틱 회귀와 비교하여 정밀도와 재현율이 어떻게 다른지 또는 어떤 모델이 더 적합한지 적어보기" ] }, { "cell_type": "markdown", "id": "4e573b97-7910-4d96-b3a2-41c12e56623c", "metadata": {}, "source": [ "#### 2. 이상치 데이터 제거 후 모델 학습/예측/평가" ] }, { "cell_type": "code", "execution_count": 36, "id": "db4b9b96-065c-49c6-bca8-f3c442bf191a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "# 이상치 데이터를 IQR 을 이용해 제거해보기\n", "# 어떤 피처에서의 이상치 데이터를 검출할 것인지 선택이 필요하기 때문에 heatmap 을 활용해 레이블과 가장 상관성이 높은 피처를 찾아내\n", "# 해당 피처의 이상치를 제거하기 \n", "\n", "import seaborn as sns\n", "plt.figure(figsize=(9, 9)) \n", "corr = card_df.####() \n", "sns.#######(corr, cmap='RdBu')" ] }, { "cell_type": "code", "execution_count": 37, "id": "25b9677e-c914-4713-bcf8-e42ce8812ecd", "metadata": {}, "outputs": [], "source": [ "# 레이블과 상관성이 높은 피처가 무엇인지 작성하기" ] }, { "cell_type": "code", "execution_count": 41, "id": "7ffc986c-3388-4c70-a1ee-fe6b4b75207c", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "이상치 데이터 인덱스: Int64Index([8296, 8615, 9035, 9252], dtype='int64')\n" ] } ], "source": [ "# V14에 대해서만 이상치를 찾아서 제거해보기\n", "\n", "import numpy as np\n", "# get_outlier() 함수는 인자로 DataFrame과 이상치를 검출한 칼럼을 입력받는다. \n", "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", " # 함수 내에서 넘파이의 percentile()을 이용해 1/4 분위와 3/4 분위를 구하고, 이에 기반해 IQR을 계산한다.\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 < ########) | (fraud > #########)].index\n", " return outlier_index\n", "\n", "outlier_index = get_outlier(df=card_df, column='V14', weight=1.5)\n", "print('이상치 데이터 인덱스:', ###########)" ] }, { "cell_type": "code", "execution_count": 43, "id": "7b6c4a9d-02f6-4976-bcb0-243bb0d49739", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "### 로지스틱 회귀 예측 성능 ###\n", "오차 행렬\n", "[[85281 14]\n", " [ 48 98]]\n", "정확도: 0.9993, 정밀도: 0.8750, 재현율: 0.6712,F1 : 0.7597, AUC:0.9743\n", "### LightGBM 예측 성능 ###\n", "오차 행렬\n", "[[85290 5]\n", " [ 25 121]]\n", "정확도: 0.9996, 정밀도: 0.9603, 재현율: 0.8288,F1 : 0.8897, AUC:0.9780\n" ] } ], "source": [ "# get_processed_df( )를 로그 변환 후 V14 피처의 이상치 데이터를 삭제하는 로직으로 변경. \n", "def get_preprocessed_df(df=None):\n", " df_copy = df.copy()\n", " amount_n = np.log1p(df_copy['Amount'])\n", " df_copy.######(0, 'Amount_Scaled', amount_n) \n", " df_copy.####(['Time', 'Amount'], axis=1, inplace=True)\n", "\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", "\n", "X_train, X_test, y_train, y_test = get_train_test_dataset(card_df)\n", "print('### 로지스틱 회귀 예측 성능 ###')\n", "get_model_train_eval(lr_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train,\n", " tgt_test=y_test) \n", "print('### LightGBM 예측 성능 ###')\n", "get_model_train_eval(lgbm_clf, ftr_train=X_train, ftr_test=X_test, tgt_train=y_train, tgt_test=y_test)" ] }, { "cell_type": "code", "execution_count": 44, "id": "777680de-53bf-4f59-b0f5-2da629170870", "metadata": {}, "outputs": [], "source": [ "# 이상치 데이터를 제거한 뒤의 로지스틱 회귀와 LightGBM 의 예측 성능이 어떻게 변화되었는지 작성해보기기" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.7" } }, "nbformat": 4, "nbformat_minor": 5 }