カリフォルニアの住宅評価額

カリフォルニアの住宅評価額

カリフォルニアの住宅評価額

 ニューラルネットワークを用いた回帰分析の実践例です。
 今回は scikit-learn の California Housing dataset (sorce : StatLib repository)を使って、カリフォルニア州の地区ごとの住宅評価額を学習させてみます。

California Housing dataset

 California Housing dataset は 1990 年にアメリカ合衆国カリフォルニア州で実施された国勢調査に基づいて作成されました。入力データの 1 レコード (8項目の特徴量) は 1 ブロック (国勢調査の最小地理単位) のデータです。一般的に、1 ブロックにはおおよそ 600 ~ 3000 程度の人口が含まれます。目標変数 (正解値) は該当ブロックの住宅評価額の中央値です。

 最初に以下のコードで fetch_california_housing をインポートします。

# リストM13-A-5
from sklearn.datasets.california_housing import fetch_california_housing

 このデータセットをまだ一度も使用したことがない場合、以下のコードの最初の行でダウンロードが実行されます (2回目以降はフォルダから読み込まれます)。

# リストM13-A-6

# データをダウンロード
ch = fetch_california_housing()

# 入力データをdataに格納
data = ch.data

# 目標変数をtargetに格納
target = ch.target
target = target[:, np.newaxis]

 feature_names属性で入力データの項目 (特徴量) を確認できます。

# 特徴量を表示
print(ch.feature_names)
['MedInc', 'HouseAge', 'AveRooms', 'AveBedrms',
 'Population', 'AveOccup', 'Latitude', 'Longitude']

 各項目の意味は以下の通りです。

・MedInc (median income in block)
 住民の収入の中央値

・HouseAge (median house age in block)
 家屋の築年数の中央値

・AveRooms (average number of rooms)
 部屋数の平均値

・AveBedrms (average number of bedrooms)
 寝室数の平均値

・Population (block population)
 人口

・AveOccup (average house occupancy)
 住居の占める割合

・Latitude (house block latitude)
 ブロックの緯度

・Longitude (house block longitude)
 ブロックの経度

 入力データの総数 (ブロック数) は 20640 です:

# 配列の形状を確認
print(ch.data.shape)
(20640, 8)

入力データの標準化と分割

 学習を安定させるために入力データを標準化しておきます:

# リストM13-A-7

def zscore(x, axis = None):
    x_mean = np.mean(x, axis=0)
    x_std  = np.std(x, axis=0)
    zscore = (x-x_mean)/x_std
    return zscore

data = zscore(data)

 入力データの 3/4 を訓練データ、残りをテストデータとします:

# リストM13-A-8

# インデックス配列を作成
np.random.seed(10)
idx = np.arange(len(data))
np.random.shuffle(idx)
idx_train = idx[idx % 4 != 0]
idx_test = idx[idx % 4 == 0]

# 入力データを訓練データとテストデータに分割
data_train = data[idx_train]
data_test = data[idx_test]

# 正解データを訓練データとテストデータに分割
target_train = target[idx_train]
target_test = target[idx_test]

 

住宅評価額の学習

 ユニット数 8 の中間層を 2 つ重ねてニューラルネットワークを構築し、ブロックごとの住宅評価額を ミニバッチ 学習させます。ネットワークの構成は以下の通りです。

 ・入力層のユニット数  : 8
 ・中間層 1 のユニット数 : 10
 ・中間層 1 の活性化関数 : ReLU
 ・中間層 2 のユニット数 : 10
 ・中間層 2 の活性化関数 : sigmoid関数
 ・出力層のユニット数  : 1
 ・バッチサイズ     : 10
# リストM13-A-9

# ネットワークの順伝播関数
def forward(data):
    mid_1.forward(data)
    mid_2.forward(mid_1.y_out)
    return out.forward(mid_2.y_out)

# 乱数を初期化
np.random.seed(11)

# 学習率を設定
alpha = 0.005

# epochを設定
epoch = 400

# データの個数
n_train = data_train.shape[0]
n_test = data_test.shape[0]

# バッチサイズとバッチ数
b_size = 10
n_batch = n_train // b_size

# インデックス配列
idx = np.arange(n_train)

# 中間層と出力層を作成
mid_1 = Middle_layer(8, 10, ReLU)
mid_2 = Middle_layer(10, 10, Sigmoid)
out = Output_layer(10, 1)

# epoch配列
x = np.arange(epoch)

# 訓練誤差とテスト誤差の初期値
error_train = np.zeros(epoch)
error_test = np.zeros(epoch)

# FigureとAxes
fig = plt.figure(figsize = (6, 6))
ax = fig.add_subplot(111)
ax.grid()
ax.set_xlim(0, epoch)
ax.set_xlabel("Epochs", size = 15, labelpad = 8)
ax.set_ylabel("RSS", size = 15, labelpad = 8)

# エポック数だけ学習を繰り返す
for j in range(epoch):
    
    # 訓練データを学習途中のネットワークに入力して出力を取得
    forward(data_train)
    
    # 訓練データの二乗和誤差
    error_train[j] = rss(out.y_out, target_train)
    
    # テストデータを学習途中のネットワークに入力して出力を取得
    forward(data_test)
    
    # テストデータの二乗和誤差
    error_test[j] = rss(out.y_out, target_test)
    
    # インデックスをランダムに並べ替える
    np.random.shuffle(idx)

    # ミニバッチ学習
    for k in range(n_batch):
        batch = idx[k * b_size : (k + 1) * b_size]
        mid_1.forward(data_train[batch, :])
        mid_2.forward(mid_1.y_out)
        out.activate(mid_2.y_out, target_train[batch, :])
        mid_2.backward(out.y_back)
        mid_1.backward(mid_2.y_back)

# 二乗和誤差(RSS)の推移
ax.plot(x, error_train, color = "blue", label = "train")
ax.plot(x, error_test, color = "red", label = "test")
ax.legend()

 California Housing dataset (Epochs-RSS)

 学習済みのネットワークに 10 個のテストデータを入力して、ブロックごとの予想住宅価格が出力されることを確認しておきます。

# 学習済みのネットワークにテストデータを入力
forward(data_test[10:20])

print(out.y_out)
[[1.31418576]
 [1.40602699]
 [1.41048713]
 [2.08381142]
 [1.47503575]
 [4.93269334]
 [2.60073102]
 [1.46253389]
 [0.96458591]
 [1.39023383]]