데이콘 : https://dacon.io/competitions/open/235576/mysubmission
2017년 4월 1일부터, 5월 31일까지 시간별로 서울시 따릉이 대여수와 기상상황 데이터가 주어진다. 각 날짜의 1시간 전의 기상상황을 가지고 1시간 후의 따릉이 대여수를 예측하면 된다.
1. EDA
Colab에서 진행했고, 우선 train.csv 파일을 업로드한뒤 read_csv로 dataframe을 생성한다.
# train
from google.colab import files
uploaded = files.upload()
import io
import pandas as pd
train_df = pd.read_csv(io.StringIO(uploaded['train.csv'].decode('utf-8')))
# test
uploaded = files.upload()
test_df = pd.read_csv(io.StringIO(uploaded['test.csv'].decode('utf-8')))
# submission
uploaded = files.upload()
submission = pd.read_csv(io.StringIO(uploaded['submission.csv'].decode('utf-8')))
컬럼에 관한 설명은 다음과 같다.
- id : 날짜, 시간별 id
- hour : 시간
- hour_bef_temperature : 1시간 전 기온
- hour_bef_preciptitaion : 1시간 전 비 정보, 비가 오지 않았으면 0, 비가 오면 1
- hour_bef_windspeed : 1시간 전 풍속(평균)
- hour_bef_humidity : 1시간 전 습도
- hour_bef_visibility : 1시간 전 시정(視程), 시계(視界)(특정 기상 상태에 따른 가시성을 의미)
- hour_bef_ozone : 1시간 전 오존
- hour_bef_pm10 : 1시간 전 미세먼지(머리카락 굵기의 1/5에서 1/7 크기의 미세먼지)
- hour_bef_pm2.5 : 1시간 전 미세먼지(머리카락 굵기의 1/20에서 1/30 크기의 미세먼지)
- count : 시간에 따른 따릉이 대여 수
train_df.info()
- info()를 통해 각 컬럼을 살펴보면, 개수가 다르기 때문에 결측치가 있다고 짐작할 수 있다.
시간에 따른 따릉이 대여수를 살펴보자.
train_df.groupby('hour').mean()['count'].plot()
- 여기서 groupby()는 그룹별 데이터를 집계 및 요약할 수 있는 함수이다.
- 시간(hour)에 따라 따릉이 대여수(count)의 평균(mean)이 어떻게 변화하는지 다음 그래프로 알 수 있다.
- 그래프를 보면, 약 8시, 18시쯤 따릉이 대여수가 급증하는 것을 알 수 있다.
- 이를 통해 출퇴근시간에 사용량이 증가한다는 것을 짐작할 수 있다.
위의 그래프를 좀 더 편하게 살펴보자.
import matplotlib.pyplot as plt
plt.plot(train_df.groupby('hour').mean()['count'],'o-')
plt.grid()
plt.title('count by hour',fontsize=15)
plt.xlabel('hour',fontsize=15)
plt.ylabel('count',fontsize=15)
plt.axvline(8,color='r')
plt.axvline(18,color='r')
plt.text(8,120,'go work',fontsize=15)
plt.text(18,120,'leave work',fontsize=15)
# plt.savefig('picture.png')
- 제목, 가로축, 세로축을 각각 'count by hour', 'hour', 'count로 정해주었으며 8시, 18시에 빨간 세로선을 그어 해당하는 수치를 한눈에 알아볼 수 있다.
- plt.plot()의 스타일은 다양하게 지정할 수 있다.
색 | 마커 | 선 | |||||
문자열 | 의미 | 마커 | 의미 | 문자열 | 의미 | ||
blue | b | . | 점 | - | 실선 | ||
green | g | o | 원 | -- | 끊어진 실선 | ||
red | r | v | 역삼각형 | -. | 점+실선 | ||
cyan | c | ^ | 삼각형 | : | 점선 | ||
magenta | m | s | 사각형 | ||||
yellow | y | * | 별 | ||||
black | k | x | 엑스 | ||||
white | w | d | 다이아몬드 |
count 변수와 다른 변수 사이의 상관관계를 살펴보기 위해 corr()를 이용한다.
train_df.corr()
상관계수들을 보기 쉽게 heatmap으로 나타내어 판단한다.
import seaborn as sns
plt.figure(figsize=(10,10))
sns.heatmap(train_df.corr(),annot=True) # anoot=True : 수치 표현
- 각 변수들의 상관계수를 한눈에 알아볼 수 있으며, count와 상관성이 높은 변수는 hour, hour_bef_temperature, , hour_bef_windspeed 등이 있다.
- 여기서는 hour, hour_bef_temperature, hour_bef_windspeed 변수들과 count만을 분석할 예정이다.
2. 전처리
train 데이터와 test 데이터에서 결측치가 있는지 살펴보고, 만약 있다면 결측치를 처리해준다. 여기서는 hour, hour_bef_temerature, hour_bef_windspeed 변수들의 결측치만 살펴본다.
1) train 데이터
train_df.isna().sum()
hour 변수에는 결측치가 없으나, 나머지 두 변수에는 결측치가 있다.
1-1) hour_bef_temperature
결측치가 있는 위치만 골라서 해당 데이터를 살펴 본다. 실행 결과를 통해 934번, 1035 위치에 결측치가 있는 것을 확인하였다.
train_df[train_df['hour_bef_temperature'].isna()]
전체 평균으로 결측치를 처리하기엔 격차가 심하기 때문에(아래 그래프를 알 수 있다. 중간에 있는 가로선이 전체 평균을 의미한다) 시간별 평균값으로 대체하기로 결정하였다.
train_df.groupby('hour').mean()['hour_bef_temperature'].plot()
plt.axhline(train_df.groupby('hour').mean()['hour_bef_temperature'].mean())
# 시간별 평균 온도
train_df.groupby('hour').mean()['hour_bef_temperature']
groupby()로 시간별 평균 온도를 구할 수 있고, 결측치의 개수가 적기 때문에 딕셔너리를 이용해 직접 결측치를 처리한다.
train_df['hour_bef_temperature'].fillna({934:14.788136,1035:20.926667},inplace=True)
1-2) hour_bef_windspeed
위에서와 방법은 동일하다.
train_df[train_df['hour_bef_windspeed'].isna()]
train_df.groupby('hour').mean()['hour_bef_windspeed']
train_df['hour_bef_windspeed'].fillna({18:3.281356, 244:1.836667, 260:1.620000, 376:1.965517, 780:3.278333, 934:1.965517, 1035:3.838333, 1138:2.766667, 1229:1.633333},inplace=True)
2) test 데이터
test 데이터에서도 마찬가지로 결측치를 처리해야 후에 예측을 할 때 문제없이 할 수 있다. hour_bef_temperature와 hour_bef_windspeed의 결측치는 모두 1개밖에 없기 때문에, 위치를 찾지 않고 바로 결측치 처리를 하였다.
test_df.isna().sum()
2-1) hour_bef_temperature
train_df.groupby('hour').mean()['hour_bef_temperature']
test_df['hour_bef_temperature'].fillna(19.704918,inplace=True)
2-2) hour_bef_windspeed
train_df.groupby('hour').mean()['hour_bef_windspeed']
test_df['hour_bef_windspeed'].fillna(3.595082,inplace=True)
3. 모델 학습 및 검증
features = ['hour','hour_bef_temperature','hour_bef_windspeed']
X_train = train_df[features]
y_train = train_df['count']
X_test = test_df[features]
여기서는 RandomForestRegressor 모델을 사용했다.
from sklearn.ensemble import RandomForestRegressor
model100 = RandomForestRegressor(n_estimators=100,random_state=0)
model100_5 = RandomForestRegressor(n_estimators=100,max_depth=5,random_state=0)
model200 = RandomForestRegressor(n_estimators=200)
위에서 만든 모델 3개를 각각 fit을 이용해 학습을 해주고, predict을 통해 검증을 한다.
model100.fit(X_train,y_train)
model100_5.fit(X_train,y_train)
model200.fit(X_train,y_train)
ypred1 = model100.predict(X_test)
ypred2 = model100_5.predict(X_test)
ypred3 = model200.predict(X_test)
제출을 위해 submission 데이터프레임의 count 변수에 예측한 값을 대입하고(ypred1, ypred2, ypred3) csv파일로 저장해 데이콘 대회에 제출한다.
submission['count'] = ypred1
submission.to_csv('model100.csv',index=False)
submission['count'] = ypred2
submission.to_csv('model100_5.csv',index=False)
submission['count'] = ypred3
submission.to_csv('model200.csv',index=False)
4. 리더보드 확인
대회에 리더보드 칸에 들어가면, 순위와 점수, 제출을 몇 번했는지 확인할 수 있다.
출처 :
https://youtu.be/WreGAJxukpA
https://youtu.be/7IbTi1QicHU
https://youtu.be/FrzmkRKDyjA
댓글