본문 바로가기
데이터 분석/dacon

[데이콘] 서울시 따릉이 자전거 이용 예측 AI모델

by Leunco 2021. 10. 19.

데이콘 : https://dacon.io/competitions/open/235576/mysubmission

 

[공공] 서울시 따릉이 자전거 이용 예측 AI모델 - DACON

좋아요는 1분 내에 한 번만 클릭 할 수 있습니다.

dacon.io

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

반응형

댓글