Rのランダムフォレストで、不動産物件の賃料予測をしました

IT,インターネット | 月曜日 12月 14 2009 3:47 PM | コメント (0) Tags: , , ,

卒論のために勉強した統計の知識とか、R(統計解析ソフト)の使い方が、
誰かの参考になればと思って公開しておきます。

私が卒論でやったことは、
「賃貸物件検索サイトスマイティの物件データを使用し、物件の条件(予測変数)で賃料(基準変数)を予測する」
というものです。

解析手法は機械学習の一分野である決定木とランダムフォレスト(以下、RF)です。
決定木が一般的なのですが、単独学習で精度が低いことから、
集団学習の中でも優秀とされるRFと併用して比較しました。

この記事の対象者

誰に読んで頂いてもありがたいのですが

  • 決定木に関する知識があり
  • Rを使ったことがある、もしくは使う予定があり
  • RFをしたい人

に向けた書き方をしています。
なので、それ以外の方には不親切な部分があるかも知れないということ、ご了承下さい。

RFの特徴

簡単に、RFの特徴をまとめました。

  • 予測精度が高い
  • スピードが速い
  • 予測変数の重みが算出される
  • 多変数、高次元の分析に強い
  • 欠損データに強い

決定木を基本としているので、そこから順々に説明してゆきます。

決定木とは

決定木はポピュラーな手法なので、定義だけ紹介します。

決定木とは
木構造を利用して、入力パターンに対応する予測値を決定するアルゴリズムを表現した手法
です。

単独学習で、予測精度が低いです。

集団学習とは

単独学習の精度の低さを補う手法です。
集団学習の中でもシンプルな、バギングを例に説明します。

バギングではデータからブートストラップリサンプリングを行い、何度も決定木を行います。
ブートストラップリサンプリングとは、「n個の標本数があるデータから、重複ありでn個を取り出す手法」です。

つまり一つのデータに対して、取り出すオブジェクトの組み合わせを変えながら、何度も決定木を行います。
そして複数の学習結果を統合(後述)して一つのアルゴリズムとします。

集団学習なのでデータの恣意性に左右されにくくなり、
予測精度が安定します。

次に、生成した複数の決定木を統合する方法を説明します。

判別と回帰

集団学習でも決定木と同じく、基準変数が質的か量的かで、
判別の問題となるか回帰の問題となるかに分かれます。

集団学習で判別を行う場合、予測結果は集団の多数決で決まります。
回帰を行う場合、集団の平均で決まります。

RFとは

バギングは全ての予測変数を使用しましたが、RFは予測変数もランダムサンプリングします。
標本、予測変数ともにランダムリサンプリングする手法です。
これによって予測精度やスピードが高まります。

RFの手順

RFの具体的な手順は、下記の通りです。

1. ブートストラップサンプリングし、OOB(Out of Bag)データを取り除く

標本数の数だけ復元抽出するブートストラップサンプリングを行う。
ただし、後に自己検証を行うために、ブートストラップ標本の1/3をOOBデータとして取り除く。

2. いくつかの変数を用いて,未剪定の決定木を生成する

まずは1で抽出した標本データから、m個の変数をランダムサンプリングする。
そしてその変数を用いて、決定木を生成する。
この段階では剪定を行わない。

3. OOBデータでテストを行い,結果に基づいて分類木を構築する

2で生成した決定木をOOBデータに適用して、推測誤差(OOB推測誤差)を求める。
その結果に基づいて新たな分類木を構築する回帰の場合は平均、分類の場合は多数決をとる。

余談ですが

集団学習って何度も(500回とか1000回とか)処理を行うので、
直感的には時間がかかりそうなものですが、実際はむしろ逆です。

小さいまとまり毎に処理した方が早いということだと思います。
ソフトウェア畑の人にしたら当たり前なんでしょうか。

RFの説明はこれまでにして、Rでの実行方法にうつります。

R

1. データセット

まずはデータを用意します。
新宿区の物件データです。

> # データを読み込んで、2/3を推定用、1/3を検証用に分割する
>
> real <- read.csv("rawdata.csv", header=T) # 標本数合計3000
> real.learn <- real[(1:2000),-c(1,11:14)]  # 学習用データ2000
> real.test <- real[-(1:2000),-c(1,11:14)]  # 検証用データ1000
>
> # データの分割を確認
>
> head(real.learn)

       最寄駅 徒歩 専有面積 間取り 築年数 方位       種別   構造 所在階 賃料
2017   早稲田    6     7.29     1R     29   南   アパート   木造      2  3.5
2018 高田馬場   10    12.50     1R     38   南   アパート   木造      2  4.1
2019 西早稲田    1    15.00     1K     32 南西   アパート 鉄骨造      1  4.6
2020   早稲田    7     5.30     1R     24   西 マンション 鉄骨造      3  4.8
2021     中井    6    10.00     1R     21 南東 マンション 鉄骨造      2  5.3
2022   早稲田    4    19.83     1K     44   西   アパート   木造      2  5.6
head(real.test)

> head(real.test)

      最寄駅 徒歩 専有面積 間取り 築年数 方位       種別 構造 所在階 賃料
1 落合南長崎    8    10.00     1K     34   東   アパート 木造      2  3.3
2   高田馬場    8     9.72     1R     44   南   アパート 木造      2  3.6
3   江戸川橋    7    13.00     1R     23   北   アパート   RC      1  4.3
4       中井   11    10.53     1R     34   南   アパート 木造      2  4.7
5       目白   15    12.78     1R     36 南東 マンション   RC      2  5.1
6       中井    6    14.00     1R     27   東 マンション   RC      3  5.4

2. パッケージrandomForestのインストール、ライブラリの呼び出し

RFのパッケージをインストールして、ライブラリを呼び出します。
インストール時において、CRANのミラーサイトはJapan(Tsukuba)を選択。
なぜかJapan(Tokyo)だとダメみたいです。
パッケージrandomForestの詳細に関しては、Packege ‘randamForest’をご覧下さい。

# ランダムフォレストのパッケージ、ライブラリを読み込む

> install.packages("randomForest")
> library(randomForest)

3. 学習

続いて学習を行いますが、ランダムサンプリングなのでシードを固定しなければ結果が毎回変わります。
randomForest関数の引数の意味はこんな感じ。

  • 「formula = (基準変数) ~ (予測変数)」と書きます。予測変数の部分を「.」(カンマ)と書くと基準変数以外の全ての変数が予測変数になります
  • ntreeは生成する決定木の数を示します。デフォルトが500です
  • importance=TRUEは後ほど説明しますが、予測変数の重要度を算出するために使います

最後にplotしたのは誤差の平均平方のグラフです。

>  # シードを固定してから学習
> set.seed(0)
> (real.rf<-randomForest(賃料 ~ . , data=real.learn, ntree=100, importance=TRUE))

Call:
 randomForest(formula = 賃料 ~ ., data = real.learn, ntree = 100,      importance = TRUE)
               Type of random forest: regression
                     Number of trees: 100
No. of variables tried at each split: 3

          Mean of squared residuals: 5.698583
                    % Var explained: 90.11
> plot(real.rf)

基準変数が賃料(量的変数)ということで、random forestのタイプはregression(回帰)になります。
誤差の平均平方が5.698583、変数の説明率が90.11%という結果が出ました。
誤差の平均平方のグラフをみると、決定木が20ぐらいで落ち着き、50以降はそれほど変化しなくなります。

4. 予測

学習用データ、検証用データでそれぞれ予測します。
この場合学習用データを予測するのは、自分自身の予測ですのでそれほど意味のある行為ではありませんが。

それぞれに関して予測値と正解の相関係数を算出します。

> # 学習用データで予測
>
> plot(real.rf)
> real.pred<-predict(real.rf , newdata=real.learn)
> cor(real.pred, real.learn$実質賃料)
[1] 0.9924784

> # 検証用データで予測
>
> real.pred<-predict(real.rf , newdata=real.test)
> cor(real.pred, real.test$実質賃料)
[1] 0.9678588

同じことを決定木でやった場合、
相関係数はそれぞれ0.9946105、0.940806となりました。

つまりRFは

  • 自分自身の予測に関しては、完璧ではない

  • 新しいデータに対しては、安定した結果を返すことができる

ということが言えます。

5. 予測変数の寄与率

先ほどrandomForest関数でinportance=trueとやったのが、
予測変数の寄与率を算出するためです。

> varImpPlot(real.rf)

グラフの左が精度を基準とした平均値です。
右が樹木を作成する際に計算されたジニ係数の平均値で、変数の重要度を表します。

6. 予測誤差

正解に対する予測誤差の幅は0~64.9%、中央値は4.25%(決定木は5.14%)でした。
どうやって出したかというと、予測の部分で使ったpredict関数の入れ物を実行します。

> real.pred

 2001      2002      2003      ...
 4.908311  4.641344  7.176658  ...

各物件の予測値が出るので、表計算ソフトに張り付けて、うにゃうにゃ(謎)します。

参考

下記のWebサイトが参考になりました。

書籍でキッチリ学ぶなら、下記の金明哲先生の本がおススメです。

Rによるデータサイエンス - データ解析の基礎から最新手法まで
金 明哲
森北出版
売り上げランキング: 72629

ちなみに金先生はJIN’S PAGEというHPをやっておられまして、
Rの学習の参考になります。