見出し画像

不動産データを使って相場を推測するー大阪編

以前の記事で東京都世田谷区の不動産価格データを使って、相場の推測をしました。別の地域でも試してみようと大阪のデータを触ってみました。せっかくなので別の記事で紹介したretiパッケージを活用します。

大阪の中古マンション価格データのパターン

まずはデータを読み込むところからです。国土交通省の不動産価格取引情報検索を使って2005年の第3四半期から2022年の第1四半期までのデータをダウンロードします。大阪のデータは「
27_Osaka Prefecture_20053_20221.csv」などと名前がついているので、csvを読み込みます。今回は中古マンションだけを取りたいので、reti_read_MSという関数を使います。

library(tidyverse)
library(reti)
osaka_condo <- reti_read_MS('27_Osaka Prefecture_20053_20221.csv')

大阪全部のデータを使うのは大変なので、件数が多い市区町村をピックアップします。

osaka_condo %>% group_by(市名) %>% summarise(cnt=n()) %>% arrange(desc(cnt))
 市名           cnt
   <fct>        <int>
 1 大阪市中央区  5832
 2 大阪市北区    5504
 3 吹田市        5252
 4 大阪市淀川区  4936
 5 豊中市        4693

大阪市中央区が一番件数が多いので、大阪市中央区の中古マンション価格データを使います。なお、retiパッケージによって戦前に建てられた物件のフラグや、面積が2000平米以上のフラグがついているので、それらのデータは省きます。特定の市区町村のデータを取るには"reti_filter_by_city"関数を使います。価格が一円単位になっていて見づらいので、1万円単位に直しておきます。また、この後のデータ可視化で使うので面積あたりの価格も作っておきます。

town_name <- "大阪市中央区"

condo_df <- reti_filter_by_city(osaka_condo, town_name)
# 戦前のデータは省く
# 2000平米を超える部屋も省く
condo <- condo_df %>%
  filter(building_before_war==FALSE) %>% 
  filter(huge_room==FALSE) %>% 
  # 価格を万円単位にする
  mutate(price = 取引総額/10000,
         unit_price = price/room_size) 

グラフ化するときに、極端に価格が高い物件や面積が狭すぎる物件などがあると少しのデータサンプルでグラフが見づらくなってしまうので、部屋の面積は大きくても200平米ぐらいだろうとしておいて、それよりも大きい部屋がある場合は99.9%タイル点で丸めた面積まで表示するようにします。

limit_condo_room_size = max(200, 
    ceiling(quantile(condo$room_size, p=0.999)/100)*100)

ここまで準備ができたらまずデータの可視化をして、価格と面積など関係ありそうな要素との関連を見ていきます。

価格と面積

部屋が広ければマンションの値段は普通高いです。

my_graph_theme <- theme_bw(base_family = "HiraKakuProN-W3") +
  theme(axis.title = element_text(size = 16),
        axis.text = element_text(size = 14),
        plot.title = element_text(size=20, hjust=0.5))

scatter_area_vs_price <- condo %>% 
  ggplot(aes(x=room_size, y=price)) +
  geom_point(alpha=1/5, size=0.5) +
  my_graph_theme + 
  labs(x="延べ床面積(㎡)", y="価格(万円)", title=town_name) + 
  scale_x_continuous(labels=scales::comma, limits=c(0, limit_condo_room_size)) + 
  scale_y_continuous(labels=scales::comma)
print(scatter_area_vs_price)

できたグラフはこちらです。

広ければ高い

部屋が広ければマンションの価格は高くなる、という当たり前の関係が確認できます。あとは部屋面積は大体100平米あたりぐらいまでで、150平米を超えるような物件はほぼないような感じです。中古マンションのデータなので、まあ納得のいく結果だと思います。

部屋面積あたりの価格

次に部屋面積あたりのマンションの価格がどうなっているか見てみます。

hist_unit_price <- condo %>% 
  ggplot(aes(x=unit_price)) +
  geom_histogram(binwidth=10) +
  my_graph_theme +
  labs(x="平米単価(万円)", y="物件数", title=town_name)
print(hist_unit_price)
100万円以下が普通

面積あたりの価格は、価格÷部屋面積で計算しています。大阪市中央区の場合は、大体100万円以下に収まっていて、50万前後が平均という感じです。

価格と築年の関係

面積あたりの価格にすることで、価格に影響しそうな他の要因と比較するときに、面積の影響を取り除くことができます。例えば面積が大きい物件は新しい物件が多い、ということがあると、価格が高いのが面積が広いからなのか、新しい物件が多いからなのか、どちらが要因となっているのかが分かりにくくなります。というわけで面積あたりの価格を出してから、まずは築年との関係を見てみます。(ちなみにここでretiの限界で令和に建てられた物件については築年が計算されないので、手計算しています。)

trend_unit_price_by_transaction_year <- condo %>% 
  group_by(t_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=t_year, y=average_price))+
  my_graph_theme +
  geom_point() + 
  geom_ribbon(aes(ymin=p10_price, ymax=p90_price), alpha=0.2) +
  labs(x="取引時点(年)", y="平米単価(万円)", title = town_name)
print(trend_unit_price_by_transaction_year)

綺麗に線形の関係があるわけではないですが、築20年ぐらいまでの価格帯と、築20年以上の中古マンションの価格帯は少し違って見えます。築20年以上の中古マンションの方が、面積あたりの価格は安く、ざっくり50万以下に見えます。築20年を切る物件だと高い方は100万円ぐらい、安くても30万以上はするような分布になっています。

古いと安い

価格と取引時点

売買された年によって相場が変わるというのは想像に難くないです。分かりやすくいうとバブル期には同じ物件でもかなり高くなっていたはずです。国土交通省の不動産価格データでは「取引時点」という情報があり、月日はわからないですが売買が発生した四半期が分かります。retiパッケージで取引時点はt_yearという変数に保存されています。

trend_unit_price_by_transaction_year <- condo %>% 
  group_by(t_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=t_year, y=average_price))+
  my_graph_theme +
  geom_point() + 
  geom_ribbon(aes(ymin=p10_price, ymax=p90_price), alpha=0.2) +
  labs(x="取引時点(年)", y="平米単価(万円)", title = town_name)
print(trend_unit_price_by_transaction_year)
だんだん値上がりしている

グラフの黒い点が面積あたりの価格の平均値です。グレーでハイライトされているエリアが、上位5%と下位5%の点です。面積あたりの90%がこのグレーでハイライトされているエリアに入る、と解釈します。なぜか理由はわかりませんが、2013年から2014年にかけて値段が急激に上がり、その後は徐々に毎年上がっています。2013年までは50万円を切っていたのが2014年に50万を超え、毎年数万円ぐらいずつ値上がりして2022年は60万円を超えているようです。

価格と地域

最後に地域ごとの面積あたり価格の分布を見てみます。同じ大阪市中央区でも地域によって値段の差はあると考えられます。

boxplot_unit_price_by_area <- condo %>% 
  ggplot(aes(x=reorder(地区名, unit_price), y=unit_price)) + 
  my_graph_theme +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1)) + 
  theme(axis.text.x = element_text(size=12)) + 
  geom_boxplot() + 
  scale_y_continuous(limits=c(0,150)) + 
  labs(x="地区名", y="平米単価(万円)", title=town_name)
print(boxplot_unit_price_by_area)
地域によって価格差が激しい

少し細かくて見づらいですが、一番右端が面積あたりの価格の平均が80万ぐらいと高い地域で「高麗橋」となっています。左の方に行くと値段が安い地域で、一番左端は「日本橋」が来ています。ただし、これは単純に地域ごとの価格のバラツキを見ただけで、本当にこれが地域ごとの相場なのかどうかはわかりません。なぜなら右端の方の物件は、面積が大きい物件や新しい物件が多いだけかもしれないからです。

というわけで、モデルを使って価格に影響を与えそうな要因を考慮して、面積や築年、地域による価格への影響がどうなっているのか見てみます。

モデルを使った相場推定

(やや専門的なので相場の推定結果だけ知りたい方は読み飛ばしてください)

東京都世田谷区のモデルと同様のモデルを使います。中古マンションの価格が、

  • 部屋面積

  • 築年

  • 取引された年

  • 地域

の四つに影響を受けていると仮定したモデルです。単純な線形モデルで当てはめると、

model_chiiki <- formula(price ~ room_size + age + 
                          factor(t_year) +
                          factor(地区名))
model_chiiki_fit <- lm(model_chiiki, data = condo)
summary(model_chiiki_fit)

Coefficients:
                          Estimate Std. Error t value Pr(>|t|)    
(Intercept)               756.9783   200.0534   3.784 0.000156 ***
room_size                  43.0757     0.4767  90.368  < 2e-16 ***
age                       -58.3807     1.1701 -49.894  < 2e-16 ***
factor(t_year)2006        121.4192   114.0657   1.064 0.287162    
factor(t_year)2007        105.6169   118.7043   0.890 0.373639    
(中略)
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 875.8 on 5701 degrees of freedom
Multiple R-squared:  0.7284,	Adjusted R-squared:  0.7246 
F-statistic: 191.2 on 80 and 5701 DF,  p-value: < 2.2e-16

R-squareが0.73とこれだけでまあまあの精度があることがわかります。今回はもうちょっと複雑にして、これをベイズモデルで解きます。ベイズモデルだと便利なのが、各パラメーターの推定値を信頼区間付きで推定できるのと、推定値のシミュレーションが簡単にできることです。

モデル式

数式で書くとこんなモデルになります。

$$
y_{i,t} = \beta_0 + \beta_1x_1+\beta_2x_2+\alpha_{t}+\gamma_{j}
$$

x1は面積、x2は築年で、これは取引年、物件、地域によらず一定と仮定しています。それに取引年によるダミー変数と地域によりダミー変数が加わります。このモデルには切片(beta0)と取引年によるダミーがあるので、地域ごとの相場を見ようと思ったら、これらも加えた推定値を求める必要があります。取引年は直近データの2022年と想定して、2022年に売買するとしたら、地域ごとの中古マンションの価格相場はどうなっているか、というのを求めることになります。つまり、

$$
\beta_0 + \alpha_{2022} + \gamma_j
$$

を推定します。ベイズモデリングはRのStanを使います。下記がStanコードです。最後のgenerated quantitiesのところで、切片、取引年、地域ダミーの推定値を足し算したものを計算しています。

// The input data is a vector 'y' of length 'N'.
data {
  int<lower=0> N;
  int<lower=0> K; // year effect index
  int<lower=0> J; // chiiki effect index
  vector[N] price;
  vector[N] floor_size;
  vector[N] age;
  int<lower=1, upper=K> year_effect_index[N]; // 1 = 2005, 2 = 2006, 3 = 2007, etc. 
  int<lower=1, upper=J> chiiki_effect_index[N]; // 
}

// The parameters accepted by the model. Our model
// accepts two parameters 'mu' and 'sigma'.
parameters {
  // real year_b0; // year effect base 
  real b0;
  real b1; // coef for the room size
  real b2; // coef for the age
  vector[K] year_b;
  vector[J] chiiki_b;
  real<lower=0> sigma; // sigma for the total rent
  real<lower=0> sigma_year; // sigma for the year effect
  real<lower=0> sigma_chiiki; // sigma for the chiiki effect
}

// The model to be estimated. We model the output
// 'y' to be normally distributed with mean 'mu'
// and standard deviation 'sigma'.
model {
  // prior 
  sigma ~ cauchy(0, 100);
  sigma_year ~ cauchy(0, 100);
  sigma_chiiki ~ cauchy(0, 100);
  b0 ~ normal(0, 10000);
  
  year_b ~ normal(0, sigma_year);
  chiiki_b ~ normal(0, sigma_chiiki);
  price ~ normal(b0 + year_b[year_effect_index] + 
    chiiki_b[chiiki_effect_index] +
    b1*floor_size + b2*age, sigma);
}

// add the intercept and chiiki dummy
generated quantities {
  vector[J] price_range_by_chiiki;
  for (j in 1:J){
    price_range_by_chiiki[j] = b0 + chiiki_b[j] + year_b[K];
  }
}

これを実行するRコードがこちら。

library(rstan)
library(bayesplot)
# https://github.com/stan-dev/rstan/wiki/RStan-Getting-Started
options(mc.cores = parallel::detectCores())
rstan_options(auto_write = TRUE)
# https://discourse.mc-stan.org/t/rstan-always-trying-to-download-rtools-when-its-already-installed/7682/20
# to avoid RStan always asks RTools installation.
options(buildtools.check = function(action) TRUE )

# 取引時点、地域のダミー変数を作る
first_transaction_year <- min(condo$t_year)
condo <- condo %>% 
  mutate(year_dummy = t_year - first_transaction_year + 1, # the smallest year, 2005 will be 1, and 2006 is 2, etc.
         chiiki_dummy = as.factor(地区名),
         chiiki_dummy_index = as.integer(chiiki_dummy) ) # add index number for each area


# 地域ダミーを加えたモデル。
# model 3: 
# price ~ nobeyuka_menseki_number + age + 
#  factor(transaction_year) +
#  factor(chikumei)

data_list_chiiki <- list(
  N = dim(condo)[1],
  K = max(condo$year_dummy),
  J = max(condo$chiiki_dummy_index),
  year_effect_index = condo$year_dummy,
  chiiki_effect_index = condo$chiiki_dummy_index,
  price = condo$price,
  age = condo$age,
  floor_size = condo$room_size
)

chiiki_fit <- stan(
  file = "./stan/chiiki_age_room_size_lm.stan",
  data = data_list_chiiki,
  iter=4000,
  seed = 1
)
chiiki_fit_mcmc_sample <- rstan::extract(chiiki_fit, permuted = FALSE)

事後分布を集めてグラフ化します。

chiiki_intervals <- mcmc_intervals_data(chiiki_fit_mcmc_sample, regex_pars = "^chiiki_b\\[", point_est="mean", 
                    prob = 0.95, prob_outer = 1) %>% 
  mutate(chiiki_name = levels(factor(condo$地区名)))

mcmc_pointrange_by_area <- chiiki_intervals %>% 
  ggplot(aes(x=reorder(x=chiiki_name, X=m), y=m, ymin=l, ymax=h)) +
  geom_pointrange() +
  coord_flip() +
  my_graph_theme +
  theme(axis.text.y = element_text(size = 10)) +
  labs(x="地区名", y="地区別相場(万円)")
print(mcmc_pointrange_by_town)

地域別相場の推定結果

結果がこちら。

高い地域、安い地域がある

ちょっと見づらいので、トップ5とボトム5だけ描画。

見やすくなった

これはモデルの中の地域ダミーの推定値をそのままとってきたグラフです。ただ、ボトム5の地域の結果を見るとマイナスになっていて、マイナス価格の相場ってどういうこと、と解釈が難しいです。なのでここにモデル推定結果の切片と、さらに2022年に売買されたものとして取引年ダミーの推定値も加えます。結果がこちらです。丸い点が相場推定値で、横棒で表されているのが推定値の95%信頼区間です。95%の確率でこの間に収まる、という推定値です。

だいぶ解釈しやすくなった

実際にはここに部屋面積と築年の影響が加わりますが、地域ごとを比較すると上記のような結果になります。

例えば一番値段が高いのが高麗橋で、大体4000万を少し超えたあたりの相場です。ざっくり3900万から4300万ぐらいという感じでしょうか。この地域だけ飛び抜けて高いです。一体何があるんでしょうか。Google Mapによると大阪城のやや西、梅田の南にあるところみたいです。名前からしてかっこいいです。昔からの貿易都市という感じがします。

高麗橋

次に高いのが3000万を少し超えるぐらいの北浜東と伏見町です。北浜東は高麗橋の北東あたりに位置しています。この辺りが大阪の一等地なんでしょうか。

北浜東。中之島に近い。
伏見町は高麗橋のすぐ南

逆に相場が低かった地域は神崎町、松屋町、瓦屋町などで、1500万円から1800万円ぐらいの相場です。地図で見ると、下の画像の下あたりの小さな区域です。高麗橋からはかなり離れています。

神崎町

ちなみに面積と築年にかかる係数(beta1とbeta2)はそれぞれ43と-58でした。例えば50平米で築10年の中古マンションを2022年に売買したとすると、

$$
43 \times 50 - 58 \times 10 = 1570
$$

になります。これを上記のトップ3、ボトム3の地域で当てはめると、相場は

  • 高麗橋: 5677万(5421万〜5944万)

  • 北浜東: 4685万(4320万〜5048万)

  • 伏見町: 4623万(4332万〜4917万)

  • 瓦屋町: 3188万(2952万〜3424万)

  • 松屋町: 3004万(2772万〜3236万)

  • 神崎町: 3000万(2568万〜3433万)

という結果です(括弧内は95%信頼区間)。

まとめ

というわけで大阪市中央区の中古マンションのデータを分析しました。案外地域による差が激しいのだなと思いました。


この記事が気に入ったらサポートをしてみませんか?