빅데이터분석기사/작업형2

[작업형2] 제품 배송 시간에 맞춰 배송되었는지 예측하기(분류)

seo0seok 2023. 6. 15. 10:39

// 퇴근후딴짓 님의 강의를 참고하였습니다. //

 

Dataset :

Train.csv
0.42MB

 

문제) 제품 배송 시간에 맞춰 배송되었는지 예측모델 만들기(정시 도착하지 않을 확률), 다음과 같은 형식의 CSV 파일로 생성하시오.

- ID : 고객 ID

- Reached.on.Time_Y.N : 정시 도착 여부 (0: 정시 도착, 1: 정시 도착하지 않음)

 

1. 데이터 불러오기

# 시험환경 세팅 3개 파일 생성 (코드 변경 X)
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split

def exam_data_load(df, target, id_name="", null_name=""):
    if id_name == "":
        df = df.reset_index().rename(columns={"index": "id"})
        id_name = 'id'
    else:
        id_name = id_name

    if null_name != "":
        df[df == null_name] = np.nan

    X_train, X_test = train_test_split(df, test_size=0.2, random_state=2022)
    y_train = X_train[[id_name, target]]
    X_train = X_train.drop(columns=[target])

    y_test = X_test[[id_name, target]]
    X_test = X_test.drop(columns=[target])
    return X_train, X_test, y_train, y_test

df = pd.read_csv("Train.csv") # 파일명이 다를 경우 파일명을 수정해주세요
X_train, X_test, y_train, y_test = exam_data_load(df, target='Reached.on.Time_Y.N', id_name='ID')
X_train.to_csv("X_train.csv", index=False)
y_train.to_csv("y_train.csv", index=False)
X_test.to_csv("X_test.csv", index=False)

→ Dataset이 Train.csv 1개로 합쳐져 있는 것을 나눠주는 코드이다.

 

# 데이터 불러오기
import pandas as pd
X_test = pd.read_csv("X_test.csv")
X_train = pd.read_csv("X_train.csv")
y_train = pd.read_csv("y_train.csv")

X_train.shape, y_train.shape, X_test.shape

실행 결과 :
((8799, 11), (8799, 2), (2200, 11))

 

2. EDA

# 데이터 확인(X_train)
X_train.head()

→ X_train은ID, Warehouse_block, Mode_of_shipment 등 11개의 열로 이루어져있다.

 

# 데이터 확인(y_train)
y_train.head()

→ y_train은 ID와 Reached.on.Time_Y.N 2개의 열로 이루어져있다.

 

# 결측치 확인 train
X_train.isnull().sum()

실행 결과 : 
ID                     0
Warehouse_block        0
Mode_of_Shipment       0
Customer_care_calls    0
Customer_rating        0
Cost_of_the_Product    0
Prior_purchases        0
Product_importance     0
Gender                 0
Discount_offered       0
Weight_in_gms          0
dtype: int64

→ X_train에는 결측치가 없다.

 

# 결측치 확인 test
X_test.isnull().sum()

실행 결과 : 
ID                     0
Warehouse_block        0
Mode_of_Shipment       0
Customer_care_calls    0
Customer_rating        0
Cost_of_the_Product    0
Prior_purchases        0
Product_importance     0
Gender                 0
Discount_offered       0
Weight_in_gms          0
dtype: int64

X_test 또한 결측치가 없다.

 

# 타겟(레이블) 확인 0:정시 도착, 1: 정시 도착하지 않음
y_train['Reached.on.Time_Y.N'].value_counts()

실행 결과 :
1    5236
0    3563
Name: Reached.on.Time_Y.N, dtype: int64

→ y_train 확인 시 0이 3563, 1이 5236으로 정시 도착하지 않은 경우가 더 많은 것을 알 수 있다.

 

# 데이터 타입 확인
X_train.info()

실행 결과 :
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 8799 entries, 0 to 8798
Data columns (total 11 columns):
 #   Column               Non-Null Count  Dtype 
---  ------               --------------  ----- 
 0   ID                   8799 non-null   int64 
 1   Warehouse_block      8799 non-null   object
 2   Mode_of_Shipment     8799 non-null   object
 3   Customer_care_calls  8799 non-null   int64 
 4   Customer_rating      8799 non-null   int64 
 5   Cost_of_the_Product  8799 non-null   int64 
 6   Prior_purchases      8799 non-null   int64 
 7   Product_importance   8799 non-null   object
 8   Gender               8799 non-null   object
 9   Discount_offered     8799 non-null   int64 
 10  Weight_in_gms        8799 non-null   int64 
dtypes: int64(7), object(4)
memory usage: 756.3+ KB

→ X_train은 7개의 수치형 변수와 4개의 명목형 변수로 이루어져있다.

 

# 기초 통계 획인
X_train.describe()

→ X_train 기초 통계 확인 시 특이사항은 보이지 않는다.

 

# X_train 기초 통계 확인 object
X_train.describe(include='object')

→ X_train의 명목형 변수는 Warehouse_block, Mode_of_Shipment, Product_importance, Gender 4가지 이다.

 

# X_test 기초 통계 획인 object
X_test.describe(include='object')

→ X_test의 명목형 변수 또한 Warehouse_block, Mode_of_Shipment, Product_importance, Gender 4가지 이다.

 

# [Tip] object 타입 고유값 개수 확인
X_train[['Warehouse_block', 'Mode_of_Shipment', 'Product_importance', 'Gender']].nunique()

실행 결과 :
Warehouse_block       5
Mode_of_Shipment      3
Product_importance    3
Gender                2
dtype: int64

→ object 타입의 고유값 개수를 물어 볼때 .nunique() 함수를 사용해 나타낼 수 있다.

 

# X데이터와 y데이터 합치기
df = pd.concat([X_train, y_train['Reached.on.Time_Y.N']], axis=1)
df.head(1)

→ pd.concat 함수를 사용해 X_train과 y_train의 Reached.on.Time_Y.N 열을 합쳐본다.

 

# idea? 할인율이 도착에 영향을 미칠까?
cond = df['Discount_offered'] > 5 
sum(cond)

실행 결과 :
5480

cond = df['Discount_offered'] > 10
sum(cond)

실행 결과 :
2104

 

sum(df[cond]['Reached.on.Time_Y.N'])

실행 결과 : 
3673

실행 결과 : 
2104

→ 할인율이 도착에 영향을 미치는지 알아보기 위한 코드이다.

→ 할인율이 5프로 이상인 경우가 5480건일 때 정시에 도착하지 않은 경우는 3673건이다.

→ 할인율이 10프로 이상인 경우가 2104건일 때 정시에 도착하지 않은 경우는 2104건으로 100%이다.

 

→ 이는 할인율이 높을 수록 주문 배송이 많아 정시에 도착하지 않을 확률이 높았지 않을까라는 예측할 수 있다.

 

3. 데이터 전처리 및 피처엔지니어링

# 라벨 인코딩
from sklearn.preprocessing import LabelEncoder

cols = X_train.select_dtypes(include='object').columns
print(cols)

for col in cols:
  le = LabelEncoder()
  X_train[col] = le.fit_transform(X_train[col])
  X_test[col] = le.transform(X_test[col])
  
X_train.head()

→ 명목형 변수의 컬럼명들을 cols 변수에 담고 반복문을 사용해 LabelEncoder() 작업을 진행한다.

 

# trainID 삭제, testID 값만 옮겨둠
X_train = X_train.drop('ID', axis=1)
X_test_id = X_test.pop('ID')
X_test.head()

→ 훈련 과정에서 필요 없는 ID 열을 삭제한다.

→ 최종 제출 csv 파일에 사용할 ID열을 X_test_id 변수에 따로 담아둔다.

 

 

4. 모델 및 평가

# 라이브러리 불러오기
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from xgboost import XGBClassifier

from sklearn.metrics import roc_auc_score
from numpy.random.mtrand import RandomState
# 검증 데이터 분리
from sklearn.model_selection import train_test_split
X_tr, X_val, y_tr, y_val = train_test_split(X_train,
                                            y_train['Reached.on.Time_Y.N'],
                                            test_size=0.2,
                                            random_state=2021
                                            )
X_tr.shape, X_val.shape, y_tr.shape, y_val.shape

실행 결과 :
((7039, 10), (1760, 10), (7039,), (1760,))

→ 로지스틱 회귀, 의사결정나무, 랜덤포레스트, XGBoost 4가지 모델로 예측 후 roc_auc_score로 평가하기 위한 코드

X_train, y_train 데이터를 훈련용과 검증용 데이터로 분리한다.

 

# 로지스틱 회귀
model = LogisticRegression(random_state=2022)
model.fit(X_tr, y_tr)
pred = model.predict_proba(X_val)
print(roc_auc_score(y_val, pred[:,1]))

실행 결과 :
0.7084136003323999
# 의사결정나무
model = DecisionTreeClassifier(random_state=2022)
model.fit(X_tr, y_tr)
pred = model.predict_proba(X_val)
print(roc_auc_score(y_val, pred[:,1]))

실행 결과 :
0.6321275746145835
# 랜덤포레스트
model = RandomForestClassifier(random_state=2022)
model.fit(X_tr, y_tr)
pred = model.predict_proba(X_val)
print(roc_auc_score(y_val, pred[:,1]))

실행 결과 :
0.7279225281811363
# XGBOOST
model = XGBClassifier(random_state=2022)
model.fit(X_tr, y_tr)
pred = model.predict_proba(X_val)
print(roc_auc_score(y_val, pred[:,1]))

실행 결과 :
0.7348018821599512

→ 4가지 모델 중 XGBoost의 예측률이 0.73으로 제일 높게 나온 것을 알 수 있다.

 

5. 예측 및 제출

# 예측
pred = model.predict_proba(X_test)
pred

실행 결과 :
array([[0.717337  , 0.28266302],
       [0.5674526 , 0.4325474 ],
       [0.7829215 , 0.21707852],
       ...,
       [0.51868916, 0.48131084],
       [0.5928507 , 0.40714929],
       [0.78776836, 0.2122316 ]], dtype=float32)

→ XGBoost 모델에 X_test를 넣어 실행한 결과이다.

→ 왼쪽은 정시 도착 확률, 오른쪽은 정시 도착하지 않을 확률 이다.

 

# 데이터프레임 만들기
submit = pd.DataFrame(
    {
        'ID' : X_test_id,
        'Reached.on.Time_Y.N' : pred[:,1]
    }
)

→ 문제에서 제시한 형식을 만들기 위해 데이터 프레임에 ID와 정시 도착하지 않을 확률을 넣어 만들어준다.

 

# 데이터 확인
submit.head()

→ 데이터프레임 확인시 ID와 정시 도착하지 않을 확률이 잘 들어간 것을 확인 할 수 있다.

 

# CSV파일 만들기
submit.to_csv('수험번호.csv', index=False)

→ 제출하기 위한 csv파일을 만드는 코드이다, index는 False로 지정해 생성되지 않도록 한다.

 

5. 제대로 제출 되었는지 확인

pd.read_csv("수험번호.csv")

→ 생성한 csv 파일이 제대로 만들어지고 제출되었는지 read_csv로 불러와 재확인한다.

 

6. 채점 (수험자는 알 수 없는 부분)

you = pd.read_csv("수험번호.csv")
print("당신의 score는?:",roc_auc_score(y_test['Reached.on.Time_Y.N'], you['Reached.on.Time_Y.N']))

실행 결과 :
당신의 score는?: 0.7312431644814588

→ 수험자는 알 수 없는 부분이지만 y_test를 통해 평가 시 0.73 예측률로 나쁘지 않은 성과가 나온것을 확인 할 수 있다.