본문 바로가기

프로그래머스 데브 코스/TIL

[6기] 프로그래머스 인공지능 데브코스 49일차 TIL

1019

[8주차 - Day3] ML_basics - 실습

최종 제출 코드

시행착오는 이후에 천천히 업로드
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

%matplotlib inline

dataset = pd.read_csv("./delivery_raw.csv")
df = dataset.copy()
df.head(5)
# 데이터프레임 확인해 본 결과 '\' 해당 문자로 나뉘어 한 줄에 다 출력됨

df = pd.read_csv("./delivery_raw.csv", delimiter='\t')
df
# 데이터 나눈 문자를 delimiter 인자로 처리해 주니 예쁘게 출력됨

df.dtypes
df['created_at_time'] = pd.to_datetime(df['created_at'])
df['actual_delivery_time_time'] = pd.to_datetime(df['actual_delivery_time'])
df['time'] = df['actual_delivery_time_time'] - df['created_at_time']
df['delivery_time'] = df['time'].dt.total_seconds()
df.dtypes
df = df.drop(labels=['time', 'actual_delivery_time', 'created_at',
                     'created_at_time', 'actual_delivery_time_time'],axis=1)
# 주문 생성 시간과 배달 도착 시간 빼서 총 배달 시간 'delivery_time' 열 생성

df.isnull().sum()
df_del = df.dropna()
df_del.isnull().sum()
df_del.reset_index(drop=False, inplace=True)
df_del = df_del.drop(labels=['index'],axis=1)
df_del
# 결측치 데이터 삭제 후 인덱스 값 조정

df_del['store_primary_category'].value_counts()

category = []

category = df_del['store_primary_category'].unique().tolist()
df_category = df_del['store_primary_category'].to_list()

for i in range(len(df_category)):
    df_category[i] = category.index(df_category[i])

df_del['store_primary_category'] = df_category
df_del
# 가게 카테고리 연관성에 반영하기 위해 숫자형 데이터로 바꿔 주기

plt.figure(figsize=(20,15))
sns.heatmap(data = df_del.corr(), annot=True, fmt = '.2f', linewidths=.5, cmap='Blues')
# 상관계수 히트맵 그래프로 쉽게 확인

plt.figure(figsize=(20,8))
sns.violinplot(data=df_del, palette='muted')
plt.xticks(rotation=45)
plt.show()
# 평균값을 크게 벗어나는 값들이 존재하는지 그래프로 확인

for i in list(df_del.columns):
    Q1 = df_del[i].quantile(0.25)
    Q3 = df_del[i].quantile(0.75)
    IQR = Q3 - Q1

    lower_bound = Q1 - 1.5 * IQR
    upper_bound = Q3 + 1.5 * IQR

    df_del = df_del[df_del[i] > lower_bound]
    df_del = df_del[df_del[i] < upper_bound]
df_del
# IQR을 계산하고 해당 값을 이용해 각 열의 이상치 탐지 및 제거

from sklearn.model_selection import train_test_split

train_dataset, val_dataset = train_test_split(df_del, test_size=0.1)

X_train = train_dataset.drop(labels='delivery_time',axis=1)
y_train = train_dataset['delivery_time']
X_val = val_dataset.drop(labels='delivery_time',axis=1)
y_val = val_dataset['delivery_time']


model = LinearRegression()
model.fit(X_train, y_train)

score = model.score(X_train, y_train)
print(f'Train : {score}')

score = model.score(X_val, y_val)
print(f'Test : {score}')
# 학습 데이터: 0.2294   검증 데이터 0.2261

from sklearn.model_selection import GridSearchCV

X = df_del.drop(labels='delivery_time',axis=1)
y = df_del['delivery_time']

poly = PolynomialFeatures(degree=2)
X_poly = poly.fit_transform(X)

X_train, X_val, y_train, y_val = train_test_split(X_poly, y, test_size=0.1, random_state=42)

model = Ridge(alpha=11.0)
model.fit(X_train, y_train)

y_pred = model.predict(X_val)

print('학습 평가 : ', model.score(X_train, y_train))
print('검증 평가 : ', model.score(X_val, y_val))
# 데이터 다항회귀와 Ridge모델 등을 적용하여
# 학습 데이터: 0.2627   검증 데이터 0.5868


dataset2 = pd.read_csv("./delivery_raw.csv", delimiter='\t')
dataset2['time'] = pd.to_datetime(dataset2['created_at']).dt.hour
dataset2.loc[(0 <= dataset2['time']) & (dataset2['time'] < 7), 'day'] = 0
dataset2.loc[(7 <= dataset2['time']) & (dataset2['time'] < 11), 'day'] = 1
dataset2.loc[(11 <= dataset2['time']) & (dataset2['time'] < 17), 'day'] = 2
dataset2.loc[(17 <= dataset2['time']) & (dataset2['time'] < 21), 'day'] = 3
dataset2.loc[(21 <= dataset2['time']) & (dataset2['time'] < 24), 'day'] = 4
dataset2.loc[dataset2['time'] == 0, 'day'] = 4
# 데이터 전처리를 더 수행하기 위해 주문이 생성된 시간을 제거하지 않고
# 아침/점심/오후/저녁/밤-새벽 등으로 시간대를 나누어 숫자형으로 저장


Q1 = dataset2['estimated_order_place_duration'].quantile(0.25)
Q3 = dataset2['estimated_order_place_duration'].quantile(0.75)
IQR = Q3 - Q1

lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR

dataset2 = dataset2[dataset2['estimated_order_place_duration'] > lower_bound]
dataset2 = dataset2[dataset2['estimated_order_place_duration'] < upper_bound]

dataset2.reset_index(drop=False, inplace=True)
dataset2 = dataset2.drop(labels=['index'],axis=1)
# 'estimated_order_place_duration'열의 이상치 삭제


plt.scatter(dataset2['day'], dataset2['estimated_order_place_duration'], alpha=0.4)
plt.show()
# 그래프를 통해 시간대별로 값이 확연히 차이는 나지만,
# 평균 250 - 450에서 크게 벗어나지 않음을 확인

dataset2['making'] = dataset2['delivery_time'] - dataset2['estimated_order_place_duration'] - dataset2['estimated_store_to_consumer_driving_duration']

ch_dataset = dataset2[['store_id', 'day', 'estimated_order_place_duration']]
mk_dataset = dataset2[['store_id', 'store_primary_category', 'total_items',
                     'num_distinct_items', 'max_item_price', 'delivery_time']]
del_dataset = dataset2[['market_id', 'day', 'total_onshift',
                        'total_busy', 'total_outstanding_orders',
                       'estimated_store_to_consumer_driving_duration']]
# 가게에서 주문을 수락하는 시간
# 가게에서 음식을 제조하는 시간
# 가게에서 주문자에게까지 배달되는 시간을 나누어 계산

pred = []
datasets = [ch_dataset, mk_dataset, del_dataset]
datacolumns = ['estimated_order_place_duration', 'making',
              'estimated_store_to_consumer_driving_duration']

for i in range(3):
    train_dataset, val_dataset = train_test_split(datasets[i], test_size=0.1)

    X_train = train_dataset.drop(labels=datacolumns[i],axis=1)
    y_train = train_dataset[datacolumns[i]]
    X_val = val_dataset.drop(labels=datacolumns[i],axis=1)
    y_val = val_dataset[datacolumns[i]]

    poly = PolynomialFeatures(degree=2)
    X_poly = poly.fit_transform(X)

    X_train, X_val, y_train, y_val = train_test_split(X_poly, y, test_size=0.1, random_state=42)

    model = Ridge(alpha=10.0)
    model.fit(X_train, y_train)

    pred.append(model.predict(X_val))

y_pred = sum(pred)

mse = mean_squared_error(y_val, y_pred)
rmse = np.sqrt(mse)

print("평균 제곱 오차 (MSE):", mse)
print("평균 제곱근 오차 (RMSE):", rmse)

print('학습 평가 : ', model.score(X_train, y_train))
print('검증 평가 : ', model.score(X_val, y_val))

for actual, predicted in zip(X_val, y_pred):
    underpredictions = (predicted < actual).sum()
    total_predictions = len(X_val)
    underprediction_ratio = underpredictions / total_predictions

print(f'Under-prediction 비율: {underprediction_ratio:.2%}')
#평균 제곱 오차 (MSE): 29061233.036536735
#평균 제곱근 오차 (RMSE): 5390.847153883769
#학습 평가 :  0.262776247965373
#검증 평가 :  0.25868989235748285
#Under-prediction 비율: 0.32%


pred = []
datasets = [mk_dataset, del_dataset]
datacolumns = ['making',
              'estimated_store_to_consumer_driving_duration']

for i in range(2):
    train_dataset, val_dataset = train_test_split(datasets[i], test_size=0.1)

    X_train = train_dataset.drop(labels=datacolumns[i],axis=1)
    y_train = train_dataset[datacolumns[i]]
    X_val = val_dataset.drop(labels=datacolumns[i],axis=1)
    y_val = val_dataset[datacolumns[i]]

    poly = PolynomialFeatures(degree=2)
    X_poly = poly.fit_transform(X)

    X_train, X_val, y_train, y_val = train_test_split(X_poly, y, test_size=0.1, random_state=42)

    model = Ridge(alpha=1.0)
    model.fit(X_train, y_train)

    pred.append(model.predict(X_val))

y_pred = sum(pred) + 700

mse = mean_squared_error(y_val, y_pred)
rmse = np.sqrt(mse)

print("평균 제곱 오차 (MSE):", mse)
print("평균 제곱근 오차 (RMSE):", rmse)

print('학습 평가 : ', model.score(X_train, y_train))
print('검증 평가 : ', model.score(X_val, y_val))

for actual, predicted in zip(X_val, y_pred):
    underpredictions = (predicted < actual).sum()
    total_predictions = len(X_val)
    underprediction_ratio = underpredictions / total_predictions

print(f'Under-prediction 비율: {underprediction_ratio:.2%}')
# 가게에서 주문을 받는 시간이 크게 의미가 없어 보여서 700으로 맞추고 성능 검사
#평균 제곱 오차 (MSE): 11838977.181209398
#평균 제곱근 오차 (RMSE): 3440.7814782705104
#학습 평가 :  0.26277630303647725
#검증 평가 :  0.2586902844903438
#Under-prediction 비율: 0.33%