# シェアバイク利用者数予測 ¶

## 必要なライブラリ ¶

• matplotlib 2.0.2
• numpy 1.12.1
• scikit-learn 0.18.2
• pandas 0.20.3
In [2]:

%matplotlib inline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split

import renom as rm
from renom import Sequential
from renom import Dense, Relu
from renom import Adam


## データの読み込みと前処理 ¶

まずはじめにデータを読み込みます。ダウンロードフォルダの中には2つのcsvファイルが入っていますが、本チュートリアルでは日毎のシェアバイク一時利用者数と予約利用者数を予測するので、day.csvファイルのみを使用します。

In [3]:

df = pd.read_csv("../day.csv")


In [4]:

df1=df.drop(['instant','dteday','cnt'],axis=1)
df1.head()

Out[4]:

season yr mnth holiday weekday workingday weathersit temp atemp hum windspeed casual registered
0 1 0 1 0 6 0 2 0.344167 0.363625 0.805833 0.160446 331 654
1 1 0 1 0 0 0 2 0.363478 0.353739 0.696087 0.248539 131 670
2 1 0 1 0 1 1 1 0.196364 0.189405 0.437273 0.248309 120 1229
3 1 0 1 0 2 1 1 0.200000 0.212122 0.590435 0.160296 108 1454
4 1 0 1 0 3 1 1 0.226957 0.229270 0.436957 0.186900 82 1518

In [5]:

df_s = df1.copy()

col_std=[]
col_mean=[]
for col in df1.columns:
v_std = df1[col].std()
v_mean = df1[col].mean()
col_std.append(v_std)
col_mean.append(v_mean)
df_s[col] = (df_s[col] - v_mean) / v_std

df_s.head()

Out[5]:

season yr mnth holiday weekday workingday weathersit temp atemp hum windspeed casual registered
0 -1.347291 -1.000684 -1.599066 -0.171863 1.497783 -1.470218 1.109667 -0.826097 -0.679481 1.249316 -0.387626 -0.753218 -1.924153
1 -1.347291 -1.000684 -1.599066 -0.171863 -1.495054 -1.470218 1.109667 -0.720601 -0.740146 0.478785 0.749089 -1.044499 -1.913899
2 -1.347291 -1.000684 -1.599066 -0.171863 -0.996248 0.679241 -0.725551 -1.633538 -1.748570 -1.338358 0.746121 -1.060519 -1.555624
3 -1.347291 -1.000684 -1.599066 -0.171863 -0.497441 0.679241 -0.725551 -1.613675 -1.609168 -0.263001 -0.389562 -1.077996 -1.411417
4 -1.347291 -1.000684 -1.599066 -0.171863 0.001365 0.679241 -0.725551 -1.466410 -1.503941 -1.340576 -0.046275 -1.115863 -1.370398

## データの分割 ¶

In [6]:

X, y = np.array(df_s.iloc[:, :11]), np.array(df_s.iloc[:, 11:13])
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=42)


## Sequentialモデルを用いたニューラルネットワークの定義 ¶

In [7]:

sequential = Sequential([
Dense(10),
Relu(),
Dense(8),
Relu(),
Dense(6),
Relu(),
Dense(2)
])


## 利用者数を回帰するための学習ループ ¶

In [8]:

# parameters
BATCH = 10
EPOCH = 100
optimizer = Adam(lr=0.01)

# Learning curves
learning_curve = []
test_curve = []

# Training loop
for i in range(1, 1+EPOCH):
N = X_train.shape[0] # Number of records in training data
perm = np.random.permutation(N)
train_loss = 0

for j in range(N//BATCH):
# Make mini-batch
index = perm[j*BATCH:(j+1)*BATCH]
train_batch_x = X_train[index]
train_batch_y = y_train[index]

# Forward propagation
with sequential.train():
z = sequential(train_batch_x)
loss = rm.mean_squared_error(z, train_batch_y)

# Backpropagation
grad = loss.grad()

# Update
grad.update(optimizer)

train_loss += loss.as_ndarray()

# calculate mean squared error for training data
train_loss = train_loss / (N // BATCH)
learning_curve.append(train_loss)

# calculate mean squared error for testidation data
y_test_pred = sequential(X_test)
test_loss = rm.mean_squared_error(y_test_pred, y_test).as_ndarray()
test_curve.append(test_loss)

# print training progress
if i % 10 == 0:
print("Epoch %d - loss: %f - test_loss: %f" % (i, train_loss, test_loss))

print('Finished!')

Epoch 10 - loss: 0.135388 - test_loss: 0.131142
Epoch 20 - loss: 0.119636 - test_loss: 0.117048
Epoch 30 - loss: 0.108519 - test_loss: 0.118423
Epoch 40 - loss: 0.105684 - test_loss: 0.140581
Epoch 50 - loss: 0.099742 - test_loss: 0.130865
Epoch 60 - loss: 0.099561 - test_loss: 0.127347
Epoch 70 - loss: 0.098927 - test_loss: 0.122917
Epoch 80 - loss: 0.095182 - test_loss: 0.140498
Epoch 90 - loss: 0.100924 - test_loss: 0.156761
Epoch 100 - loss: 0.093405 - test_loss: 0.150348
Finished!


## モデルの評価 ¶

### 学習曲線のプロット ¶

まず正しく学習が行われているかを確認するために学習曲線をプロットしましょう。

In [9]:

plt.figure(figsize=(10, 4))
plt.plot(learning_curve, label='train_loss')
plt.plot(test_curve, label='test_loss', alpha=0.6)
plt.title('Learning curve')
plt.xlabel("Epoch")
plt.ylabel("MSE")
plt.ylim(0, 1)
plt.legend()
plt.grid()


### 実際の利用者数と予測した利用者数の比較 ¶

In [10]:

# predict test value
y_pred = sequential(X_test)

casual_true = y_test[:,:1].reshape(-1, 1) * col_std[11] + col_mean[11]
casual_pred = y_pred[:,:1] * col_std[11] + col_mean[11]
registered_true = y_test[:,1:2].reshape(-1, 1) * col_std[12] + col_mean[12]
registered_pred = y_pred[:,1:2] * col_std[12] + col_mean[12]

plt.figure(figsize=(8, 8))
plt.plot([5, 8000], [5, 8000], c='k', alpha=0.6, label = 'diagonal line') # diagonal line
plt.scatter(casual_true, casual_pred,label='casual')
plt.scatter(registered_true, registered_pred,label='registered')
plt.xlim(0, 8000)
plt.ylim(0, 8000)
plt.xlabel('acutual count of users', fontsize=16)
plt.ylabel('predicted count of users', fontsize=16)
plt.legend()
plt.grid()


グラフのx軸は実際の利用者数、y軸は予測した利用者数を示します。黒い直線は対角線(y=x)であり、プロットがこの直線に近ければ近いほど、予測が正しく行われていることになります。グラフより、約1000〜3000辺りの範囲で利用者数が正しく予測できていないことがわかります。正確に予測を実施するためには、正しく予測できたデータと正しく予想できなかったデータを分けるて原因を調査する必要があります。

### 二乗平均平方根 ¶

In [11]:

print("Root mean squared error:{}".format(np.sqrt(rm.mse(casual_true, casual_pred))))
print("Root mean squared error:{}".format(np.sqrt(rm.mse(registered_true, registered_pred))))

Root mean squared error:208.06089782714844
Root mean squared error:377.4617004394531