不動産価格データを使って相場を推測する
以前の記事で、せっかく日本全国の不動産取引価格データが取れたので、もう少し不動産価格モデルについて詳しくやってみる。また、ちょっと進んだ手法についても触れてみたい(これは別記事にしました。詳細はこちら。不動産価格データを使った相場分析ー世田谷区一棟マンション)。
価格データの加工と可視化
以前紹介した通り、国土交通省の不動産価格取引情報検索からデータがダウンロードできる。これは全国をカバーしていて、2005年以降の20年近くのデータがある。サイトから一気に全国全期間のデータがダウンロードできる。
全国のデータは取れるが一気に全国データを扱うのは大変なので、簡単なモデルから徐々に複雑にしていく。こないだ世田谷のデータを使ったので、まずは世田谷区のデータを使う。こないだは過去1年に取引されたデータだけだったので、データが存在する10年以上前の取引データも全部使ってみる。前回説明した通り、築年が元号表記になっていたり、面積が文字列で入っていたりと泣けるデータ構造なので、その辺りは整形する。Rだとretiというパッケージがあって、同じサイトからデータをきれいにダウンロードできるようになっているらしい。余力があったらいずれこのパッケージも紹介したい。
setagaya <- house_price %>% filter(ken_name == '東京都') %>%
filter(shikuchoson_name=='世田谷区')
dim(setagaya) # 9995 recordsある。
価格と延べ床面積の関係
まずは延べ床面積と価格の関係を見てみる。
scatter_area_vs_price_setagaya <- setagaya %>% ggplot(aes(x=nobeyuka_menseki_number, y=price)) +
geom_point(alpha=1/5, size=0.5) +
theme_bw(base_family = "HiraKakuProN-W3") +
labs(x="延べ床面積(㎡)", y="価格(万円)") +
scale_x_continuous(labels=scales::comma) +
scale_y_continuous(labels=scales::comma)
print(scatter_area_vs_price_setagaya)
したがそのグラフ。500平米を超えるような大きな物件がある。また、10億円を超えるような超高級物件がある。
このグラフだと関係が見にくいので、500平米以下、5億以下で再度グラフを見る。
大体部屋が広いと高い、みたいな関係はありそう。
平米あたり単価の確認
次に、延べ床面積当たりの価格を計算して、どんなデータになっているのかチェックしてみる。
hist_unit_price_setagaya <- setagaya %>%
ggplot(aes(x=unit_price)) +
geom_histogram(binwidth=10) +
theme_bw(base_family = "HiraKakuProN-W3") +
theme(axis.title = element_text(size = 20),
axis.text = element_text(size = 14)) +
labs(x="平米単価(万円)", y="物件数")
print(hist_unit_price_setagaya)
みると1平米あたり200万円を超えるような、超高級物件がある。ちょっと調べてみる。
setagaya %>% filter(unit_price>200) %>%
select(chikumei, nobeyuka_menseki, madori, menseki, menseki_number, price, complete_year) %>%
as.data.frame() %>%
arrange(price)
chikumei nobeyuka_menseki madori menseki menseki_number price complete_year
1 弦巻 15 <NA> 150 150 3800 1957
2 三軒茶屋 30 <NA> 170 170 7500 1944
3 玉堤 35 <NA> 240 240 9500 1966
4 上北沢 25 <NA> 170 170 9700 1958
5 桜丘 50 <NA> 200 200 14000 1954
6 下馬 30 <NA> 200 200 15000 1944
7 等々力 55 <NA> 200 200 16000 1944
延べ床面積が部屋面積より小さいデータがある。1つは延べ床面積が15で、面積が150以上となっていて、明らかにおかしい。2つ目と3つ目は延べ床面積が30平米、35平米と狭すぎる。これは国土交通省のアンケートによる回答なので、延べ床面積と部屋の面積を回答した人が間違えたのかも知れない。延べ床面積が面積より小さいデータは省いた方が良さそう。
setagaya_cleaned <- setagaya %>%
filter(nobeyuka_menseki_number > menseki_number) %>%
filter(!is.na(menseki_number))
hist_unit_price_setagaya <- setagaya_cleaned %>%
ggplot(aes(x=unit_price)) +
geom_histogram(binwidth=10) +
theme_bw(base_family = "HiraKakuProN-W3") +
labs(x="平米単価(万円)", y="頻度")
print(hist_unit_price_setagaya)
築年と価格の関係
以前もやったように、築年と価格を単純に比較すると、そもそもの物件の大きさが違うので、延べ床面積当たりの価格を計算して、それで比較をする。
setagaya_scatter_age_vs_unit_price <- setagaya_cleaned %>%
ggplot(aes(x=age, y=unit_price)) +
geom_point(size=0.5, alpha=0.2) +
theme(axis.title = element_text(size = 20)) +
labs(x="築年", y="平米単価(万円)")
print(setagaya_scatter_age_vs_unit_price)
なだらかに右肩下がりになっていて、築年が古いほど価格が安い、と言う関係が見える。右側の方に塊があり、これは戦前に建てられたものか、築年が不明なものと思われる。これらも省く。全部で116件ある。
取引時点と価格の関係
最後に取引時点と価格の関係を見る。以前は直近1年間に取引されたデータだけを見た。今回は2005年以降に取引されたすべてのデータがあるので、もしかするとリーマンショックとかあって年によって相場が少し変わっているかもしれない。
setagaya_trend_unit_price_by_transaction_year <- setagaya_cleaned %>%
group_by(transaction_year) %>%
summarise(average_price = mean(unit_price),
median_price = median(unit_price),
p10_price = quantile(unit_price, p=0.1),
p90_price = quantile(unit_price, p=0.9)) %>%
ggplot(aes(x=transaction_year, y=average_price))+
theme(axis.title = element_text(size = 20)) +
geom_point() +
geom_ribbon(aes(ymin=p10_price, ymax=p90_price), alpha=0.2) +
labs(x="取引時点(年)", y="平米単価(万円)")
print(setagaya_trend_unit_price_by_transaction_year)
点が平均の平米単価。グレーで表示されている範囲が、平米単価の下位10%と上位10%の幅。例えば一番左端の2005年は平均が60万弱で、2005年に取引された物件全体の80%が40万から75万の間にある、と解釈できる。見ると2008年から2009年にかけて大きく値下がりしており、リーマンショックの影響が見て取れる。その後20012年当たりまで横ばいで、それ以降徐々に値上がりしていることがわかる。
つまりモデル化する時には広さと築年でだけではなく、取引時点の年を考慮した方が良い。なので基本モデルとして、築年、広さ、取引年のモデルを作る。
ベースモデル:延べ床面積+築年+取引時点
というわけで、基本的なモデルを作る。
base_model <- formula(price ~ nobeyuka_menseki_number + age +
factor(transaction_year))
setagaya_base_model_fit <- lm(base_model, data = setagaya_cleaned)
Rのデフォルトの関数は、モデル結果の表示がやや冗長なので、armというパッケージを使う。これはAndrew Gelmanの作ったパッケージ。
display(setagaya_base_model_fit)
lm(formula = base_model, data = setagaya_cleaned)
coef.est coef.se
(Intercept) 3996.99 675.46
nobeyuka_menseki_number 52.42 0.49
age -137.25 7.64
factor(transaction_year)2006 1008.99 762.64
factor(transaction_year)2007 632.40 768.69
factor(transaction_year)2008 291.48 778.53
factor(transaction_year)2009 -1170.33 786.90
factor(transaction_year)2010 -1347.50 816.85
factor(transaction_year)2011 -1384.63 782.45
factor(transaction_year)2012 -1747.58 785.53
factor(transaction_year)2013 -750.14 770.17
factor(transaction_year)2014 -1360.82 767.96
factor(transaction_year)2015 539.51 769.63
factor(transaction_year)2016 343.54 767.71
factor(transaction_year)2017 396.11 764.89
factor(transaction_year)2018 2491.44 767.00
factor(transaction_year)2019 1557.08 780.69
factor(transaction_year)2020 690.31 760.62
factor(transaction_year)2021 2969.96 846.63
---
n = 4746, k = 19
residual sd = 7327.26, R-Squared = 0.72
adjusted R squareは0.72。延べ床面積と築年の係数はそれぞれ有意で、52と-137となっている。取引時点の係数については、全てが優位という訳ではない。coef.seを2でかけた数字が大体の信頼区間で、例えば2006年だと推定値は1009で、conf.seが763。763に2をかけると1526で、1009から1526を引くと−517、足すと2535と、信頼区間が0を含む。なのでこの係数はゼロであるという可能性が否定できない。2012年、2018年、2019年、2021年が有意となっている。
モデルの改善2:建物の構造を考慮する
上で作ったベースのモデルを徐々に改善していく。まずありそうなのは、木造と鉄筋コンクリートの物件だと、鉄筋コンクリートの物件のが高いんでないか、なぜなら木造だと2、3階建てのアパートという感じだけど、鉄筋コンクリートはでかいマンションという感じがするから。という訳でまずはデータを見てみる。ここでも広さの影響が出ないように、平米単価でグラフ化してみる。
setagaya_cleaned %>% group_by(kouzou) %>%
summarise(record_count = n()) %>%
arrange(desc(record_count))
kouzou record_count
<chr> <int>
1 木造 3262
2 RC 803
3 鉄骨造 392
4 RC、木造 185
5 軽量鉄骨造 67
6 NA 63
7 SRC 56
8 RC、鉄骨造 15
一番多いのは木造で、その次がRC。RCというのはReinforced Concreteの略で、鉄筋コンクリートのこと。結構細かく分かれているので、件数が多いものだけを見てみる。
setagaya_box_plot_unit_price_by_structure <- setagaya_cleaned %>%
filter(kouzou %in% c('木造','RC','鉄骨造','RC、木造','軽量鉄骨造','SRC')) %>%
ggplot(aes(x=reorder(kouzou, unit_price), y=unit_price)) +
theme(axis.title = element_text(size = 20)) +
geom_boxplot() +
scale_y_continuous(limits=c(0,150)) +
labs(x="構造", y="平米単価(万円)")
print(setagaya_box_plot_unit_price_by_structure)
あまり変わらない感じもあるが、木造が一番高く見える。SRC (Steel-framed Reinforced Concrete)が一番高いように思ったが、そうでもないかもしれない。なので一応モデルに追加してみる。ただ種類が多いのでグループ化する。
setagaya_cleaned <- setagaya_cleaned %>%
mutate(is_rc_pc = case_when(
kouzou %in% c('RC','鉄骨造','SRC','RC、鉄骨造','SRC、RC','SRC、鉄骨造') ~ 1,
TRUE ~ 0
))
model_kouzou <- formula(price ~ nobeyuka_menseki_number + age + is_rc_pc + factor(transaction_year))
setagaya_model_kouzou_fit <- lm(model_kouzou, data = setagaya_cleaned)
display(setagaya_model_kouzou_fit)
lm(formula = model_kouzou, data = setagaya_cleaned)
coef.est coef.se
(Intercept) 4214.85 672.13
nobeyuka_menseki_number 49.96 0.58
age -150.13 7.78
is_rc_pc 2284.12 302.89
factor(transaction_year)2006 1016.84 758.17
factor(transaction_year)2007 462.99 764.52
factor(transaction_year)2008 179.12 774.12
factor(transaction_year)2009 -1148.35 782.30
factor(transaction_year)2010 -1323.67 812.07
factor(transaction_year)2011 -1432.33 777.89
factor(transaction_year)2012 -1745.17 780.93
factor(transaction_year)2013 -852.30 765.78
factor(transaction_year)2014 -1494.41 763.67
factor(transaction_year)2015 490.31 765.15
factor(transaction_year)2016 226.20 763.37
factor(transaction_year)2017 283.30 760.56
factor(transaction_year)2018 2394.61 762.61
factor(transaction_year)2019 1429.74 776.30
factor(transaction_year)2020 575.26 756.32
factor(transaction_year)2021 2911.45 841.71
---
n = 4746, k = 20
residual sd = 7284.34, R-Squared = 0.72
グラフで見た時は木造が一番高そうに見えたが、築年や延床面積を考慮すると、やはり鉄筋コンクリートなどの方が高いようだ。係数は2284で、つまり鉄筋コンクリートであれば価格が2284万円高い、ということになる。R-Squareは0.72とあまり変わらない。
モデルの改善3:地域による差を考慮する
多分不動産の実務家の方々からツッコミがありそうなのが、「いやいや、世田谷区って広いし、世田谷区の中でもいろんな地域があるから、地域間の相場の違いを見ないと意味ないのでは?」というものです。それはもっともなので、価格差が地域でどれぐらいあるのか見てみます。
setagaya_boxplot_unit_price_by_area <- setagaya_cleaned %>%
ggplot(aes(x=reorder(chikumei, unit_price), y=unit_price)) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) +
theme(axis.title = element_text(size = 20)) +
geom_boxplot() +
scale_y_continuous(limits=c(0,150)) +
labs(x="地区名", y="平米単価(万円)")
print(setagaya_boxplot_unit_price_by_area)
グラフの左側にある地域が平米単価が安い地域、右側に行くほど平米単価が高い地域となっています。グラフからだと見づらいので、安いところ、高いところのTop 5を見てみます。
setagaya_cleaned %>% group_by(chikumei) %>%
summarise(unit_price = mean(unit_price),
record_count = n()) %>%
arrange(desc(unit_price)) %>%
head(5)
# chikumei unit_price record_count
# 1 玉川 81.1 28
#2 東玉川 74.7 54
#3 瀬田 74.7 68
#4 北沢 73.7 133
#5 桜新町 71.5 23
# 安い地域
setagaya_cleaned %>% group_by(chikumei) %>%
summarise(unit_price = mean(unit_price),
record_count = n()) %>%
arrange(desc(unit_price)) %>%
tail(5)
# chikumei unit_price record_count
# 1 八幡山 48.2 34
#2 北烏山 44.1 83
#3 玉川田園調布 36.7 4
#4 宇奈根 34.5 9
#5 喜多見 32.3 22
高い方は平米単価が70万以上しますが、安い地域では30万から40万と、かなり価格差があるようです。地図で見ると、喜多見は世田谷区の西の端で、狛江市のすぐ隣みたいです。価格帯としては狛江市と同じなのかもしれません。
対して世田谷区玉川は、二子玉川駅の周辺で、確かにこの辺りは再開発も進んで高い地域なのは納得です。
という訳で、地域もモデルに組み込んでみます(長いので一部結果を割愛)。
model_chiiki <- formula(price ~ nobeyuka_menseki_number + age +
is_rc_pc +
factor(transaction_year) +
factor(chikumei))
setagaya_model_chiiki_fit <- lm(model_chiiki, data = setagaya_cleaned)
display(setagaya_model_chiiki_fit)
lm(formula = model_chiiki, data = setagaya_cleaned)
coef.est coef.se
(Intercept) 3315.17 1152.42
nobeyuka_menseki_number 50.00 0.57
age -154.68 7.61
is_rc_pc 1747.61 300.29
factor(chikumei)代沢 3379.19 1223.36
factor(chikumei)代田 2542.01 1084.32
factor(chikumei)八幡山 -1269.07 1532.13
factor(chikumei)北沢 5131.16 1118.20
factor(chikumei)南烏山 -233.01 1159.21
factor(chikumei)喜多見 -9064.50 1775.99
factor(chikumei)太子堂 6770.31 1139.19
factor(chikumei)奥沢 3322.75 1086.85
factor(chikumei)宇奈根 -225.72 2537.36
factor(chikumei)成城 3536.15 1317.19
factor(chikumei)新町 3332.77 1630.54
factor(chikumei)東玉川 2823.53 1342.04
factor(chikumei)玉川 8076.34 1628.48
factor(chikumei)玉川台 3918.68 1594.40
factor(chikumei)玉川田園調布 -10732.53 3657.32
factor(chikumei)用賀 4192.68 1355.19
---
n = 4746, k = 78
residual sd = 7048.39, R-Squared = 0.74
地域は多くが有意ではないみたいです。さっき出た玉川、玉川大、玉川田園調布、用賀、成城、喜多見、北沢、などなど、一部地域だけみたいで、あとは相場がそこまで変わらない地域と言えそうです。ちなみにちゃんと説明してこなかったですが、地域による違いの推定値は、基準となる地域に対してどれぐらい違うか、ということを表しています。ここでは基準地域は三宿となっていています。例えば玉川だと推定値が8076なので、築年や広さに変わりがないとすると、三宿に比べて価格が8076万円高い、ということです。さっき見た喜多見は-9064なので、逆に9064万円やすい、ということになります。
モデルの改善4:地域による差を変数でも考慮する
次に出てくる疑問として、年ダミーや築年などの影響も、地域によって異なるのでは、というものです。例えば再開発が進んだ二子玉川では、年ごとのトレンドが他の地域とは大きく異なると予想されます。また、高級住宅街では築年が古くても値段が下がらないということも考えられます。これまでのモデルだと、地域や取引時点での相場の違いは考慮していますが、築年の影響はどの地域でも一律1年当たりマイナス150万円、というように固定されていました。地域によっては値段がほとんど下がらず、マイナス10万ぐらい、ということも考えられます。まずは先ほど見た価格が高い地域、安い地域を取り出して、築年と年ごとの影響を見てみます。
setagaya_scatter_age_vs_unit_price_by_area <- setagaya_cleaned %>%
filter(chikumei %in% c('玉川','東玉川','瀬田','北沢','桜新町',
'八幡山','北烏山','玉川田園調布','宇奈根','喜多見')) %>%
mutate(chikumei_factor = factor(chikumei,
levels=c('玉川','東玉川','瀬田','北沢','桜新町',
'八幡山','北烏山','玉川田園調布','宇奈根','喜多見'))) %>%
ggplot(aes(x=age, y=unit_price)) +
geom_point() +
theme(axis.title = element_text(size = 20)) +
facet_wrap(~chikumei_factor, nrow=2) +
geom_smooth(method=lm) +
labs(x="築年", y="平米単価(万円)")
print(setagaya_scatter_age_vs_unit_price_by_area)
グラフからだとはっきりとはわからないが、多少築年の影響が異なっていそう。微妙に傾きが異なるように見える。瀬田という地域だと若干右肩下がりなように見える。逆に玉川ではほぼフラットのように見える。
次に年間のトレンドを見てみる。
setagaya_scatter_year_vs_unit_price_by_area <- setagaya_cleaned %>%
filter(chikumei %in% c('玉川','東玉川','瀬田','北沢','桜新町',
'八幡山','北烏山','玉川田園調布','宇奈根','喜多見')) %>%
mutate(chikumei_factor = factor(chikumei,
levels=c('玉川','東玉川','瀬田','北沢','桜新町',
'八幡山','北烏山','玉川田園調布','宇奈根','喜多見'))) %>%
group_by(chikumei_factor, transaction_year) %>%
summarise(average_price = mean(unit_price),
median_price = median(unit_price),
p10_price = quantile(unit_price, p=0.1),
p90_price = quantile(unit_price, p=0.9)) %>%
ggplot(aes(x=transaction_year, y=average_price))+
geom_point() +
geom_ribbon(aes(ymin=p10_price, ymax=p90_price), alpha=0.2) +
theme(axis.title = element_text(size = 20)) +
labs(x="取引時点(年)", y="平米単価(万円)") +
facet_wrap(~chikumei_factor, nrow=2)
print(setagaya_scatter_year_vs_unit_price_by_area)
データ数が少なく、うまく推定の幅が描けないが、玉川だと価格の上下があるのに、八幡山や北烏山などはあまり変化がない。なので、取引時点については、地域によって推定値を変えるようなことをモデル化した方が良いのかもしれない。
このモデル化はちょっと複雑なので、次回に続く。
まとめ
世田谷の不動産価格を分析しました。最初はシンプルなモデルを作り、最終的に地域による差も考慮したモデルに改良しました。次回はベイズモデルを使って、最後できなかったモデル化をやる予定。
(追伸:築年の影響を地域で分ける分析をやってみました。詳細はこちら。不動産価格データを使った相場分析ー世田谷区一棟マンション)