일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 오차역전파
- 퍼셉트론
- nlp
- CNN
- 데이터 파싱
- computer vision
- pdf parsing
- segmentation
- 시계열
- anomaly detection
- LLM
- rag parsing
- 컴퓨터비전
- 머신러닝
- visual instruction tuning
- 활성화함수
- Non-Maximum Suppression
- 이상탐지
- E
- Cross Entropy Error
- 활성화 함수
- Time Series
- LLaVA
- 합성곱 신경망
- leetcode
- 딥러닝
- deep learning
- 손실함수
- Mean squared error
- Today
- Total
굴러가는 분석가의 일상
[Kaggle] Bike Share Demand 본문
*본 커널은 아래의 URL을 통해 참조하였습니다. 참고 부탁드립니다.
https://www.kaggle.com/code/viveksrinivasan/eda-ensemble-model-top-10-percentile
1. 프로젝트 이해하기
캐글에서 소개한 Bike Share Demand는 Washington DC의 자전거 대여 수요에 대해 Regression으로 예측하는 것 입니다.
2. 데이터 이해하기
datetime - hourly date + timestamp
season - 1 = spring, 2 = summer, 3 = fall, 4 = winter
holiday - whether the day is considered a holiday
workingday - whether the day is neither a weekend nor holiday
weather - 1: Clear, Few clouds, Partly cloudy, Partly cloudy
2: Mist + Cloudy, Mist + Broken clouds, Mist + Few clouds, Mist
3: Light Snow, Light Rain + Thunderstorm + Scattered clouds, Light Rain + Scattered clouds
4: Heavy Rain + Ice Pallets + Thunderstorm + Mist, Snow + Fog
temp - temperature in Celsius
atemp - "feels like" temperature in Celsius
humidity - relative humidity
windspeed - wind speed
casual - number of non-registered user rentals initiated
registered - number of registered user rentals initiated
count - number of total rentals
3. 프로젝트 프로세스
i) 데이터 형태 파악
ii) EDA / Feature Engineering
iii) 모델링
4. 데이터 형태 파악
- 데이터 및 Library Import 함수를 통해 불러오기
- 데이터의 전반적인 모양 및 형태 파악
4.1 데이터 및 Library Import 함수를 통해 불러오기
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime
pd.set_option('display.max_rows',100)
pd.set_option('display.max_columns',100)
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')
train.head(20)
4.2 데이터의 전반적인 모양 및 형태 파악
- 여기에서 주목해야할 부분은 Train 및 Test 데이터의 Column에 차이가 있습니다. Train 데이터에는 "Casual"," Registered", "Count" 라는 변수가 있지만 Test 데이터는 없으므로, 예측해야하는 변수는 "Count"임을 알 수 있습니다.
- 또한, 모든 변수 또는 특성이 숫자형으로 구성 되어있므로, 전형적인 회귀분석의 Example 입니다.
# Train dataset의 크기 => (10886, 15)
train.shape
5. 데이터 EDA 진행
- 현재 datetime의 형태는 yyyy-mm-dd 00:00:00 입니다. 이를 날짜 및 시간별로 나눠서 자전거 수요량이 어떻게 변화하는지 파악
- 여기서 날짜의 Month 및 Weekday 추출할 것이고, 시간은 Hour만 추출
- calendar.day_name[datetime.datetime.strptime()].weekday() 사용하게 된다면; 1 → Saturday 같은 형식으로 변환!
- 또한, map() 함수를 통해 숫자형을 범주형으로 변환
- 필요가 없어진 Datetime 피쳐를 삭제
import calendar, datetime
train['date'] = train['datetime'].apply(lambda x: x.split()[0])
train['hour'] = train['datetime'].apply(lambda x: x.split()[1].split(":")[0])
train['weekday'] = train['date'].apply(lambda x: calendar.day_name[datetime.datetime.strptime(x,'%Y-%m-%d').weekday()])
train["month"] = train['date'].apply(lambda x : calendar.month_name[datetime.datetime.strptime(x,"%Y-%m-%d").month])
train['season'] = train['season'].map({1: "Spring",
2: "Summer",
3: "Fall",
4: "Winter"})
train['weather'] = train['weather'].map({1: " Clear + Few clouds + Partly cloudy + Partly cloudy",
2 : " Mist + Cloudy, Mist + Broken clouds, Mist + Few clouds, Mist ",
3 : " Light Snow, Light Rain + Thunderstorm + Scattered clouds, Light Rain + Scattered clouds",
4 :" Heavy Rain + Ice Pallets + Thunderstorm + Mist, Snow + Fog " })
#필요가 없어진 "datetime" 을 삭제해줍니다!
train.drop('datetime',axis = 1, inplace = True)
#Category 변수로 변환
var_to_categorical = ['hour','weekday','month','season','holiday','workingday','weather']
for var in var_to_categorical:
train[var] = train[var].astype('category')
#Train 데이터의 타입 파악
dataTypeDf = pd.DataFrame(train.dtypes.astype(str).value_counts()).reset_index().rename(columns={"index":"variableType",0:"count"})
fig,ax = plt.subplots()
fig.set_size_inches(12,5)
sns.barplot(data=dataTypeDf,x="variableType",y="count",ax=ax)
ax.set(xlabel='variableTypeadriable Type', ylabel='Count',title="Variables DataType Count")
5.1 피처별 데 자전거 수요량 확인 (시각화)
- Categorical Feature
# Category 변수 시각화
fig, axes = plt.subplots(2,2, figsize = (12,10))
sns.boxplot(data = train, y = 'count', orient = 'v',ax = axes[0][0])
sns.boxplot(data = train, x = 'season', y = 'count', ax = axes[0][1])
sns.boxplot(data = train, x = 'hour', y = 'count', ax = axes[1][0])
sns.boxplot(data = train, x = 'workingday', y = 'count', ax = axes[1][1])
- Numerical Feature
- atemp 및 temp 같은 경우 서로 Strong Correlation 이기에 모델링 시 삭제 필요 → Multicollinearity 문제 야기
- Windspeed는 Count 변수에게 큰 영향을 주지 않음
- Humidity와 atemp 영향 줄 가능성 있음
- "humidity","windspeed" 및 "temp" 변수에 Regplot 적용 → Windspeed "0"의 값이 무수히 많음 (Feature Engineering 작업 필요)
corrMatt = train[["temp","atemp","casual","registered","humidity","windspeed","count"]].corr()
mask = np.array(corrMatt)
mask[np.tril_indices_from(mask)] = False
fig,ax= plt.subplots()
fig.set_size_inches(20,10)
sns.heatmap(corrMatt, mask=mask,vmax=.8, square=True,annot=True)
- Dependent Variable (count 분포 확인)
- Dependent Variable의 분포는 Skew to the Right 아래와 같이 확인할 수 있습니다. 하지만 머신러닝에 적용하기 위해서는 dependent variable 이상적인 분포는 Normal Distribution 입니다. 이에 log변환을 통해 정규분포와 비스무리하게 변환시켜줍니다.
fig, axes = plt.subplots(2,2,figsize = (12,10))
sns.distplot(train['count'],ax = axes[0][0])
stats.probplot(train['count'], dist = 'norm', fit = True, plot = axes[0][1])
sns.distplot(np.log(train['count']), ax = axes[1][0])
stats.probplot(np.log(train['count']), dist = 'norm', fit = True, plot = axes[1][1])
각 Hour 평균과 Month, Season, Weekday 변수가 Count에 미치는 영향
- June, July, August (여름)에 자전거를 사용하는 수요가 가장 많은걸 파악 가능
- 평일에는 출/퇴근 시간 (7:00AM ~ 09:00AM / 17:00PM ~ 19:00PM) 수요가 가장 높고, 주말에는 오후 (13:00PM~17:00PM)에 가장 많음.
- 사계절내내 17:00PM~18:00PM 시간대에 수요가 가장 높음
fig, axes = plt.subplots(3,1,figsize=(15,10))
monthOrder = ["January","February","March","April","May","June","July","August","September","October","November","December"]
DayOrder = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]
#month
agg_month = pd.DataFrame(train.groupby("month")["count"].mean()).reset_index()
sort_month = agg_month.sort_values(by = 'count', ascending= False)
sns.barplot(data = sort_month, x = 'month', y = 'count', ax = axes[0], order =monthOrder)
axes[0].set(xlabel = ' ',title = 'Average Count By Month')
#season
agg_hour = pd.DataFrame(train.groupby(['hour','season'], sort = True)['count'].mean()).reset_index()
sns.pointplot(x = agg_hour['hour'], y = agg_hour['count'], hue = agg_hour['season'], ax = axes[1])
axes[1].set(xlabel = ' ',title = 'Average Users Count by Hour & Season')
#weekday
agg_weekday = pd.DataFrame(train.groupby(['hour','weekday'], sort = True)['count'].mean()).reset_index()
sns.pointplot(x=agg_weekday["hour"], y=agg_weekday["count"],hue=agg_weekday["weekday"],hue_order=DayOrder, data=agg_weekday, join=True,ax=axes[2])
axes[2].set(xlabel = ' ', title = 'Average Users Count by Hour & weekday')
6. Feature Engineering
- Windspeed의 regplot 통해 "0" 이라는 값이 무수히 많은걸 파악했습니다. 개인적인 생각으로는 데이터가 수집되어 있지 않아 임의 값 "0"으로 Replaced 된거 같습니다. 이에 RandomForestRegressor 대처하고자 합니다.
- correlation에서 큰 변화를 기대했던 저는.... 0.01 밖에 안오른거 보고.... 놀랐습니다... 굳이 안해도 되는 작업이었네요...
#판다스의 concat 함수를 통해 train 및 test 데이터를 합쳐주겠습니다
TrainData = pd.read_csv('train.csv')
TestData = pd.read_csv('test.csv')
CombinedData = pd.concat([TrainData,TestData], axis = 0).reset_index()
CombinedData.drop('index',axis = 1, inplace = True)
#이전에 진행하였던 것과 동일하게 합쳐진 데이터에 적용시켜줍니다.
CombinedData['date'] = CombinedData['datetime'].apply(lambda x: x.split()[0])
CombinedData['hour'] = CombinedData['datetime'].apply(lambda x: x.split()[1].split(":")[0]).astype('int')
CombinedData['weekday'] = CombinedData['date'].apply(lambda x: datetime.datetime.strptime(x,"%Y-%m-%d").weekday())
CombinedData['month'] = CombinedData['date'].apply(lambda x: datetime.datetime.strptime(x,"%Y-%m-%d").month)
CombinedData["year"] = CombinedData.datetime.apply(lambda x : x.split()[0].split("-")[0]).astype('int')
# "0"이 포함되어 있는 Windspeed 변수에 랜덤포레스트 Regressor 적용하여, 값을 바꿔주겠습니다.
from sklearn.ensemble import RandomForestRegressor
dataWind0 = CombinedData[CombinedData["windspeed"]==0]
dataWindNot0 = CombinedData[CombinedData["windspeed"]!=0]
rfModel_wind = RandomForestRegressor()
windColumns = ["season","weather","humidity","month","temp","year","atemp","hour"]
rfModel_wind.fit(dataWindNot0[windColumns], dataWindNot0["windspeed"])
wind0Values = rfModel_wind.predict(X= dataWind0[windColumns])
dataWind0["windspeed"] = wind0Values
data = dataWindNot0.append(dataWind0)
data.reset_index(inplace=True)
data.drop('index',inplace=True,axis=1)
corrMatt = data[["temp","atemp","casual","registered","humidity","windspeed","count"]].corr()
mask = np.array(corrMatt)
mask[np.tril_indices_from(mask)] = False
fig,ax= plt.subplots()
fig.set_size_inches(20,10)
sns.heatmap(corrMatt, mask=mask,vmax=.8, square=True,annot=True)
7. Modeling
#범주형 데이터로 변환 시켜줍니다!
categoricalFeature = ["season","holiday","workingday","weather","weekday","month","year","hour"]
for var in categoricalFeature:
data[var] = data[var].astype('category')
train_df = data[pd.notnull(data['count'])].sort_values(by=['datetime'])
test_df = data[~pd.notnull(data['count'])].sort_values(by=['datetime'])
datetimecol = test_df["datetime"]
yLabels = train_df["count"]
yLablesRegistered = train_df["registered"]
yLablesCasual = train_df["casual"]
dropFeature = ['casual','count','datetime','date','registered']
train_df = train_df.drop(dropFeature,axis=1)
test_df = test_df.drop(dropFeature,axis=1)
RMSLE 값은 0에 가까우면 가까울수록 좋습니다!!!
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import GridSearchCV
from sklearn import metrics
lr = LinearRegression()
yLabels_log = np.log(yLabels)
lr.fit(train_df, yLabels_log)
prediction = lr.predict(train_df)
print("RMSLE Value for Linear Regression :", np.sqrt(metrics.mean_squared_log_error(np.exp(yLabels_log),np.exp(prediction))))
----- 결과 ------
#RMSLE Value for Linear Regression : 1.017857808335659
from sklearn.ensemble import BaggingRegressor, GradientBoostingRegressor,RandomForestRegressor
from sklearn.svm import SVR
from sklearn.neighbors import KNeighborsRegressor
models = [RandomForestRegressor(), BaggingRegressor(), GradientBoostingRegressor(),SVR(),KNeighborsRegressor()]
model_name = ['RandomForestRegressor','BaggingRegressor','GradientBoostingRegressor','SVR','KNeighborsRegressor']
rmsle = []
d = {}
for model in range(len(models)):
clf = models[model]
clf.fit(train_df, yLabels_log)
test_pred = clf.predict(train_df)
rmsle.append(np.sqrt(metrics.mean_squared_log_error(np.exp(yLabels_log),np.exp(test_pred))))
result={'Modelling Algo':model_name,'RMSLE':rmsle}
result_df = pd.DataFrame(result)
result_df
두둥탁..... 1.017857에서 0.110024까지 줄어들었네요!!!
근 길 읽어주셔서 감사드립니다.
궁금하신 사항이 있으시다면, 댓글 부탁드립니다!!!