Studio KimHippo :D

[ Kaggle ] 1. Bike sharing demand EDA 본문

Kaggle Study

[ Kaggle ] 1. Bike sharing demand EDA

김작은하마 2019. 7. 8. 21:11

Data field from : https://www.kaggle.com/c/bike-sharing-demand/data

  • 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

필요한 패키지 로드

# -*- coding: utf-8 -*-
%matplotlib inline

# NOTE : Bike sharing Demand
# 자전거 대여량을 예측하는 문제이기 때문에, 회귀와 관련된 문제

import matplotlib.font_manager as fm
import matplotlib.pyplot as plt
import matplotlib as mpl
from scipy import stats
import seaborn as sns
import pandas as pd
import numpy as np
import os

plt.style.use('ggplot')
sns.set()

# os.chdir('./Kaggle/Kaggle_Study/data')
os.getcwd()

폰트 설정

# NOTE : 그래프에서 마이너스 폰트 깨지는 문제에 대한 대처
mpl.rcParams['axes.unicode_minus'] = False

font_name = fm.FontProperties(fname = 'C:/Windows/Fonts/malgun.ttf').get_name()
plt.rc('font', family = font_name)

데이터 불러오기 및 확인

# NOTE : datetime 형식으로 데이터를 불러옴.
train = pd.read_csv('bike_train.csv', parse_dates=["datetime"], engine = 'python')
train.shape

# NOTE
# train.columns : 데이터의 행에 대한 정보

# NOTE
# train.dtypes : 데이터 형에 대한 정보

# NOTE : 둘 다 합친 정보
train.info()
train.head()

Out [1] :

(10886, 12)

 

Out [2] : 

RangeIndex: 10886 entries, 0 to 10885

Data columns (total 12 columns):

datetime 10886 non-null datetime64[ns]

season 10886 non-null int64

holiday 10886 non-null int64

workingday 10886 non-null int64

weather 10886 non-null int64

temp 10886 non-null float64

atemp 10886 non-null float64

humidity 10886 non-null int64

windspeed 10886 non-null float64

casual 10886 non-null int64

registered 10886 non-null int64

count 10886 non-null int64

dtypes: datetime64[ns](1), float64(3), int64(8)

memory usage: 1020.6 KB

 

 

Out [3] : 

2011-01-01 00:00:00 1 0 0 1 9.84 14.395 81 0.0 3 13 16
2011-01-01 01:00:00 1 0 0 1 9.02 13.635 80 0.0 8 32 40
2011-01-01 02:00:00 1 0 0 1 9.02 13.635 80 0.0 5 27 32
2011-01-01 03:00:00 1 0 0 1 9.84 14.395 75 0.0 3 10 13
2011-01-01 04:00:00 1 0 0 1 9.84 14.395 75 0.0 0 1 1

Null값이 있는지 확인

# NOTE : temp라는 feature에 대한 통계치
print(train.temp.describe(), '\n')

# NOTE : 각 열별로 Null인 데이터 찾기
print(train.isnull().sum())

# NOTE
# isNull은 0 또는 1로 반환 되기 때문에, 
# isNull().sum()을 수행했을 때 0이라면 Null인 값은 없는 것이다.

Out [1] :

count 10886.00000

mean 20.23086

std 7.79159

min 0.82000

25% 13.94000

50% 20.50000

75% 26.24000

max 41.00000

Name: temp, dtype: float64

 

Out [2] : 

datetime 0

season 0

holiday 0

workingday 0

weather 0

temp 0

atemp 0

humidity 0

windspeed 0

casual 0

registered 0

count 0

dtype: int64

데이터 분할

# NOTE : 데이터를 년, 월, 일, 시, 분, 초로 나눔
train['year'] = train['datetime'].dt.year
train['month'] = train['datetime'].dt.month
train['day'] = train['datetime'].dt.day
train['hour'] = train['datetime'].dt.hour
train['minute'] = train['datetime'].dt.minute
train['second'] = train['datetime'].dt.second

Out [1] :

(10886, 18)

시간별 대여량 시각화

# NOTE : 시간별 대여량 시각화
fig, ((ax1, ax2, ax3), (ax4, ax5, ax6)) = plt.subplots(nrows=2, ncols=3)
fig.set_size_inches(18, 15)

sns.barplot(data = train, x = 'year', y = 'count', ax = ax1)
sns.barplot(data = train, x = 'month', y = 'count', ax = ax2)
sns.barplot(data = train, x = 'day', y = 'count', ax = ax3)
sns.barplot(data = train, x = 'hour', y = 'count', ax = ax4)
sns.barplot(data = train, x = 'minute', y = 'count', ax = ax5)
sns.barplot(data = train, x = 'second', y = 'count', ax = ax6)

ax1.set(ylabel='Count', title = '연도별 대여량')
ax2.set(xlabel = 'month', title = '월별 대여량')
ax3.set(xlabel = 'day', title = '일별 대여량')
ax4.set(xlabel = 'hour', title = '시간별 대여량')

# NOTE 
# 연도별 대여량은 2011년보다 2012년이 더 많다.
# 추운 계절보다 덥거나 따뜻한 계절의 대여량이 더 많다.
# train 데이터에는 일별 데이터가 19일까지 밖에 없다. (! 이 feature를 사용해선 안된다.)!
# 출퇴근 시간에 대여량이 많은것 같다. (평일과 주말로 나누어 볼 필요 있음.)
# 분, 초는 모두 0이기 때문에 의미가 없다.

계절별, 시간별, 근무일 여부를 기준으로 데이터 시각화

# NOTE 
# 계절별, 시간별 그리고 근무일을 기준으로 데이터를 시각화 한다.

fig, axes = plt.subplots(nrows = 2, ncols = 2)
fig.set_size_inches(12, 15)

sns.boxplot(data = train, y = 'count', orient = 'v', ax = axes[0][0])
sns.boxplot(data = train, y = 'count', x = 'season', orient = 'v', ax = axes[0][1])
sns.boxplot(data = train, y = 'count', x = 'hour', orient = 'v', ax = axes[1][0])
sns.boxplot(data = train, y = 'count', x = 'workingday', orient = 'v', ax = axes[1][1])

axes[0][0].set(ylabel = 'Count', title = '대여량')
axes[0][1].set(xlabel = 'Season', ylabel = 'Count', title = '계절별 대여량')
axes[1][0].set(xlabel = 'Hour of Day', ylabel = 'Count', title = '시간별 대여량')
axes[1][1].set(xlabel = 'Working Day', ylabel = 'Count', title = '근무일 여부에 따른 대여량')

# NOTE 
# 여름과 가을에 가장 많은 대여량을 보인다.
# 근무일이 아닌 날과 근무일인 날에는 큰 차이가 없지만, 근무일이 아닐때 대여량이 더많다.

요일별 데이터 확인

train['dayofweek'] = train['datetime'].dt.dayofweek
print(train.shape)

train['dayofweek'].value_counts()
# NOTE : 요일별 대여량은 큰 차이를 보이지 않는다.

Out [1] : 

(10886, 19)

 

Out [2] :

5 1584

6 1579

3 1553

2 1551

0 1551

1 1539

4 1529

Name: dayofweek, dtype: int64

상관계수 계산

# NOTE 
# 온도, 사용자 등록위치, 습도, 풍속을 바탕으로 상관계수 분석

corrMat = train[['temp', 'atemp', 'casual', 'registered',
                'humidity', 'windspeed', 'count']]
corrMat = corrMat.corr()
print(corrMat)

mask = np.array(corrMat)
mask[np.tril_indices_from(mask)] = False

Out [1] :

                    temp          atemp         casual          registered      humidity       windspeed     count

temp             1.000000     0.984948      0.467097      0.318571        -0.064949     -0.017852      0.394454

atemp            0.984948     1.000000      0.462067     0.314635         -0.043536     -0.057473      0.389784

casual            0.467097     0.462067      1.000000      0.497250        -0.348187     0.092276       0.690414

registered       0.318571     0.314635      0.497250      1.000000        -0.265458     0.091052       0.970948

humidity         -0.064949    -0.043536    -0.348187     -0.265458       1.000000      -0.318607      -0.317371

windspeed      -0.017852    -0.057473    0.092276       0.091052        -0.318607     1.000000       0.101369

count             0.394454     0.389784     0.690414       0.970948        -0.317371     0.101369       1.000000

 

상관계수 히트맵 시각화

# NOTE 
# 상관관계를 히트맵으로 시각화
fig, ax = plt.subplots()
fig.set_size_inches(20,20)
sns.heatmap(corrMat, mask = mask, vmax = .8, square = True, annot = True)

# NOTE
# 온도, 습도, 풍속은 상관관계가 거의 없다.
# 대여량과 등록된 사용자의 상관관계가 높다.
# 등록하지 않은 사용자와 풍속의 상관관계가 높다.
# 등록한 사용자와 등록하지 않은 사용자는 train dataset에만 있어서 feature로 사용하기 적합하지 않다.
# 온도와 체감온도는 feature로 사용하기 적합하지 않다.
# (왜냐하면 상관계수가 거의 1에 수렴하기 때문에 같은 데이터로 보여진다.)

Out [1] :

 

참고

[1] https://github.com/corazzon/KaggleStruggle/blob/master/bike-sharing-demand/bike-sharing-demand-EDA.ipynb

[2] https://www.kaggle.com/viveksrinivasan/eda-ensemble-model-top-10-percentile

Comments