背景・目的・分析方針

背景

東京都の不動産市場は、地域特性・法規制・物件属性など多様な要因によって価格が決定される複雑な市場である。 本分析では、国土交通省が公表している「不動産取引価格情報」(宅地・土地と建物、東京都、2024年第1〜4四半期)を用いて、 価格決定要因を実証的に分析する。

分析結果の応用として、実在する中古戸建物件(東京都新宿区原町1丁目、都営大江戸線「牛込柳町」駅徒歩1分、 木造3階建・土地43.75㎡・延床64.24㎡・2023年2月築・販売価格1億4800万円)を対象に、 推定モデルによる市場適正価格の予測値と実際の販売価格を比較する。

目的

回帰モデルを推定することにより、以下の問いに答える。

  • 物件の面積・築年数・駅距離などの属性は価格にどの程度影響するか。
  • 市区町村(地域効果)と都市計画(法規制)のどちらが価格の説明力として大きいか。
  • 推定されたモデルを用いて、対象物件(新宿区原町1丁目)の市場適正価格を予測し、 実際の販売価格(1億4800万円)と比較できるか。

分析方針

  1. データの前処理(列名変換・文字列変数の数値化・外れ値除外)
  2. 記述統計および分布・相関の確認
  3. 複数の OLS 回帰モデルを推定し、モデル間で決定係数と係数の頑健性を比較
  4. Model 2(地域効果モデル)を主モデルとしてターゲット物件の価格を予測し、誤差項の正規分布を仮定した補正を施す

データと前処理

パッケージの読み込み

library(tidyverse)
library(stargazer)
library(knitr)
library(kableExtra)
library(car)        # VIF計算用
library(patchwork)  # 図の並列表示用
library(lmtest)     # coeftest用
library(sandwich)   # hccm(ロバスト標準誤差)用

データの読み込み

raw <- read.csv(
  "data/residential_property_tokyo_2024.csv",
  fileEncoding = "CP932",
  stringsAsFactors = FALSE
)

列名の英語化

df_raw <- raw %>%
  rename(
    price         = `取引価格.総額.`,
    area          = `面積...`,
    floor_area    = `延床面積...`,
    distance      = `最寄駅.距離.分.`,
    build_year    = `建築年`,
    structure     = `建物の構造`,
    municipality  = `市区町村名`,
    city_planning = `都市計画`
  ) %>%
  select(price, area, floor_area, distance,
         build_year, structure, municipality, city_planning)

データの前処理(クリーニング)

建築年 → 築年数の変換

df_clean <- df_raw %>%
  mutate(
    year_num = as.numeric(str_extract(build_year, "\\d{4}")),
    age      = 2024 - year_num
  )

駅距離の数値化

「30分~60分」は中間値 45 分として扱い、空白は欠損値とする。

df_clean <- df_clean %>%
  mutate(
    distance_num = case_when(
      distance == "30分~60分" ~ 45,
      distance == ""           ~ NA_real_,
      TRUE                     ~ as.numeric(distance)
    )
  )

価格・面積の数値化

df_clean <- df_clean %>%
  mutate(
    price      = as.numeric(price),
    area       = as.numeric(area),
    floor_area = as.numeric(floor_area)
  )

外れ値の除外と欠損値の除去

price_q  <- quantile(df_clean$price,  c(0.01, 0.99), na.rm = TRUE)
area_q99 <- quantile(df_clean$area,   0.99, na.rm = TRUE)

dat <- df_clean %>%
  filter(
    !is.na(price),  !is.na(area),  !is.na(floor_area),
    !is.na(distance_num), !is.na(age),
    !is.na(structure), structure != "",
    !is.na(municipality), municipality != "",
    !is.na(city_planning), city_planning != "",
    price      >= price_q[1]  & price      <= price_q[2],
    area       >= 10          & area        <= area_q99,
    floor_area > 0,
    age        >= 0           & age         <= 80
  ) %>%
  mutate(
    log_price     = log(price),
    structure     = as.factor(structure),
    municipality  = as.factor(municipality),
    city_planning = as.factor(city_planning)
  )

cat("前処理後のサンプル数:", nrow(dat), "\n")
## 前処理後のサンプル数: 3890

多重共線性の懸念について: 容積率は都市計画区域と高い相関を持つため、回帰モデルからは除外した。


記述統計

主要変数の要約統計

desc_vars <- dat %>%
  select(price, area, floor_area, distance_num, age) %>%
  rename(
    "取引価格(万円)" = price,
    "土地面積(㎡)"   = area,
    "延床面積(㎡)"   = floor_area,
    "駅距離(分)"     = distance_num,
    "築年数(年)"     = age
  ) %>%
  mutate(`取引価格(万円)` = `取引価格(万円)` / 1e4)

desc_table <- data.frame(
  変数     = names(desc_vars),
  平均     = sapply(desc_vars, mean),
  標準偏差 = sapply(desc_vars, sd),
  最小値   = sapply(desc_vars, min),
  第1四分位 = sapply(desc_vars, function(x) quantile(x, 0.25)),
  中央値   = sapply(desc_vars, median),
  第3四分位 = sapply(desc_vars, function(x) quantile(x, 0.75)),
  最大値   = sapply(desc_vars, max)
)

kable(desc_table,
      digits  = 2,
      caption = "表:主要変数の要約統計(N = 3,890)",
      row.names = FALSE)
表:主要変数の要約統計(N = 3,890)
変数 平均 標準偏差 最小値 第1四分位 中央値 第3四分位 最大値
取引価格(万円) 5836.63 3227.42 800 3700 5200 7100 21000
土地面積(㎡) 100.09 43.08 25 70 95 120 280
延床面積(㎡) 99.80 30.21 30 85 95 110 440
駅距離(分) 13.46 5.68 5 10 15 15 45
築年数(年) 17.74 14.28 0 6 15 26 76

カテゴリ変数の確認

dat %>% group_by(structure) %>%
  summarise(n = n(), median_price_man = median(price) / 1e4) %>%
  kable(caption = "建物構造の内訳と中央値価格(万円)")
建物構造の内訳と中央値価格(万円)
structure n median_price_man
RC 64 9700
SRC 2 10250
ブロック造 1 5600
軽量鉄骨造 185 6300
鉄骨造 118 6650
木造 3520 5100

注意: SRC(2件)・ブロック造(1件)は件数が非常に少なく、回帰係数が不安定になりやすい。 特にブロック造は1件のみであり、係数の解釈には十分な注意が必要である(付録1参照)。

目的変数(取引価格)の分布

p1 <- ggplot(dat, aes(x = price / 1e4)) +
  geom_histogram(bins = 50, fill = "steelblue", color = "white", alpha = 0.8) +
  labs(x = "取引価格(万円)", y = "頻度", title = "取引価格(水準)")

p2 <- ggplot(dat, aes(x = log_price)) +
  geom_histogram(bins = 50, fill = "tomato", color = "white", alpha = 0.8) +
  labs(x = "log(取引価格)", y = "頻度", title = "取引価格(対数変換後)")

p1 + p2
図1:取引価格の分布(左:水準, 右:対数)

図1:取引価格の分布(左:水準, 右:対数)

主要変数間の相関と散布図

cor(dat[, c("price", "area", "floor_area", "distance_num", "age")])
##                   price      area  floor_area distance_num         age
## price         1.0000000 0.1527376  0.44890439  -0.26267912 -0.24434799
## area          0.1527376 1.0000000  0.59082719   0.20433846  0.10500250
## floor_area    0.4489044 0.5908272  1.00000000  -0.00725058  0.05733891
## distance_num -0.2626791 0.2043385 -0.00725058   1.00000000 -0.02857845
## age          -0.2443480 0.1050025  0.05733891  -0.02857845  1.00000000
par(family = if (knitr::is_latex_output()) "IPAexGothic" else "")
plot(dat[, c("price", "area", "floor_area", "distance_num", "age")],
     labels = c("Price", "Area", "Floor area", "Distance", "Age"),
     pch = 20, cex = 0.3)
図2:主要変数の散布図行列

図2:主要変数の散布図行列


回帰分析

モデルの設定

モデル 説明変数
Model 1(ベース) 面積・延床面積・駅距離・築年数・建物構造
Model 2(地域効果) Model 1 + 市区町村固定効果
Model 3(法規制効果) Model 1 + 都市計画固定効果
Model 4(統合モデル) Model 1 + 市区町村 + 都市計画
m1 <- lm(log_price ~ area + floor_area + distance_num + age + structure,
         data = dat)

m2 <- lm(log_price ~ area + floor_area + distance_num + age + structure
         + municipality,
         data = dat)

m3 <- lm(log_price ~ area + floor_area + distance_num + age + structure
         + city_planning,
         data = dat)

m4 <- lm(log_price ~ area + floor_area + distance_num + age + structure
         + municipality + city_planning,
         data = dat)

Model 2 の推定結果(詳細)

各カテゴリ変数の基準カテゴリは以下のとおりである。 建物構造の基準カテゴリはRC造、市区町村の基準カテゴリはRのデフォルト因子順(五十音順)による先頭の市区町村である。 基準市区町村を以下のコードで確認する。

# 建物構造の基準カテゴリ
levels(dat$structure)[1]
## [1] "RC"
# 市区町村の基準カテゴリ
levels(dat$municipality)[1]
## [1] "あきる野市"
summary(m2)
## 
## Call:
## lm(formula = log_price ~ area + floor_area + distance_num + age + 
##     structure + municipality, data = dat)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.47442 -0.13081  0.00884  0.14158  1.07577 
## 
## Coefficients:
##                              Estimate Std. Error t value             Pr(>|t|)
## (Intercept)                16.4965681  0.0621248 265.539 < 0.0000000000000002
## area                        0.0038698  0.0001530  25.287 < 0.0000000000000002
## floor_area                  0.0046604  0.0001899  24.544 < 0.0000000000000002
## distance_num               -0.0139060  0.0007637 -18.209 < 0.0000000000000002
## age                        -0.0171735  0.0002841 -60.451 < 0.0000000000000002
## structureSRC             0.1223114  0.1751752   0.698             0.485080
## structureブロック造         1.3129548  0.2480225   5.294     0.00000012659506
## structure軽量鉄骨造        -0.0116711  0.0361021  -0.323             0.746500
## structure鉄骨造            -0.0323831  0.0383430  -0.845             0.398407
## structure木造              -0.1534317  0.0318826  -4.812     0.00000154877104
## municipality稲城市          0.7252332  0.0652170  11.120 < 0.0000000000000002
## municipality羽村市          0.3626559  0.0848545   4.274     0.00001967946069
## municipality葛飾区          0.8376497  0.0531546  15.759 < 0.0000000000000002
## municipality江戸川区        0.9510757  0.0514997  18.468 < 0.0000000000000002
## municipality江東区          1.1678904  0.0569786  20.497 < 0.0000000000000002
## municipality港区            2.1864642  0.1193272  18.323 < 0.0000000000000002
## municipality荒川区          1.1404920  0.0611940  18.637 < 0.0000000000000002
## municipality国分寺市        0.9604468  0.0562357  17.079 < 0.0000000000000002
## municipality国立市          0.9878298  0.0697378  14.165 < 0.0000000000000002
## municipality狛江市          0.9749431  0.0619840  15.729 < 0.0000000000000002
## municipality三鷹市          1.1805906  0.0577285  20.451 < 0.0000000000000002
## municipality渋谷区          1.7831626  0.0684931  26.034 < 0.0000000000000002
## municipality小金井市        1.0408575  0.0558477  18.637 < 0.0000000000000002
## municipality小平市          0.7308418  0.0544489  13.423 < 0.0000000000000002
## municipality昭島市          0.5348000  0.0637666   8.387 < 0.0000000000000002
## municipality新宿区          1.5562999  0.0595247  26.145 < 0.0000000000000002
## municipality杉並区          1.4053625  0.0507315  27.702 < 0.0000000000000002
## municipality世田谷区        1.5214923  0.0501201  30.357 < 0.0000000000000002
## municipality清瀬市          0.5030555  0.0723525   6.953     0.00000000000419
## municipality西多摩郡瑞穂町 -0.0727100  0.0904550  -0.804             0.421548
## municipality西東京市        0.8724798  0.0544320  16.029 < 0.0000000000000002
## municipality青梅市          0.0486512  0.0575031   0.846             0.397571
## municipality足立区          0.7797171  0.0508742  15.326 < 0.0000000000000002
## municipality多摩市          0.6366086  0.0609327  10.448 < 0.0000000000000002
## municipality台東区          1.4193719  0.1106273  12.830 < 0.0000000000000002
## municipality大田区          1.2678384  0.0512232  24.751 < 0.0000000000000002
## municipality中央区          1.5248362  0.1792588   8.506 < 0.0000000000000002
## municipality中野区          1.3299461  0.0554235  23.996 < 0.0000000000000002
## municipality町田市          0.6077544  0.0514183  11.820 < 0.0000000000000002
## municipality調布市          1.0233285  0.0551002  18.572 < 0.0000000000000002
## municipality東久留米市      0.6539178  0.0599102  10.915 < 0.0000000000000002
## municipality東村山市        0.5148567  0.0549533   9.369 < 0.0000000000000002
## municipality東大和市        0.4172005  0.0630689   6.615     0.00000000004230
## municipality日野市          0.4859646  0.0557718   8.713 < 0.0000000000000002
## municipality八王子市        0.3417011  0.0522328   6.542     0.00000000006878
## municipality板橋区          1.0369205  0.0524905  19.754 < 0.0000000000000002
## municipality品川区          1.4890239  0.0560438  26.569 < 0.0000000000000002
## municipality府中市          0.8006421  0.0547951  14.612 < 0.0000000000000002
## municipality武蔵村山市      0.3493247  0.0748723   4.666     0.00000318216055
## municipality武蔵野市        1.4395999  0.0675545  21.310 < 0.0000000000000002
## municipality福生市          0.2587313  0.0705492   3.667             0.000248
## municipality文京区          1.7707152  0.0644230  27.486 < 0.0000000000000002
## municipality豊島区          1.4249432  0.0576946  24.698 < 0.0000000000000002
## municipality北区            1.1105343  0.0566208  19.614 < 0.0000000000000002
## municipality墨田区          1.1348670  0.0583650  19.444 < 0.0000000000000002
## municipality目黒区          1.7590893  0.0557982  31.526 < 0.0000000000000002
## municipality立川市          0.6522864  0.0591665  11.025 < 0.0000000000000002
## municipality練馬区          1.1292005  0.0504649  22.376 < 0.0000000000000002
##                               
## (Intercept)                ***
## area                       ***
## floor_area                 ***
## distance_num               ***
## age                        ***
## structureSRC               
## structureブロック造        ***
## structure軽量鉄骨造           
## structure鉄骨造               
## structure木造              ***
## municipality稲城市         ***
## municipality羽村市         ***
## municipality葛飾区         ***
## municipality江戸川区       ***
## municipality江東区         ***
## municipality港区           ***
## municipality荒川区         ***
## municipality国分寺市       ***
## municipality国立市         ***
## municipality狛江市         ***
## municipality三鷹市         ***
## municipality渋谷区         ***
## municipality小金井市       ***
## municipality小平市         ***
## municipality昭島市         ***
## municipality新宿区         ***
## municipality杉並区         ***
## municipality世田谷区       ***
## municipality清瀬市         ***
## municipality西多摩郡瑞穂町    
## municipality西東京市       ***
## municipality青梅市            
## municipality足立区         ***
## municipality多摩市         ***
## municipality台東区         ***
## municipality大田区         ***
## municipality中央区         ***
## municipality中野区         ***
## municipality町田市         ***
## municipality調布市         ***
## municipality東久留米市     ***
## municipality東村山市       ***
## municipality東大和市       ***
## municipality日野市         ***
## municipality八王子市       ***
## municipality板橋区         ***
## municipality品川区         ***
## municipality府中市         ***
## municipality武蔵村山市     ***
## municipality武蔵野市       ***
## municipality福生市         ***
## municipality文京区         ***
## municipality豊島区         ***
## municipality北区           ***
## municipality墨田区         ***
## municipality目黒区         ***
## municipality立川市         ***
## municipality練馬区         ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2429 on 3832 degrees of freedom
## Multiple R-squared:  0.8132, Adjusted R-squared:  0.8104 
## F-statistic: 292.6 on 57 and 3832 DF,  p-value: < 0.00000000000000022

都市計画FEのカテゴリ確認

都市計画FEは,国交省データの「都市計画」欄に入るカテゴリ(本データでは準工業地域・近隣商業地域などの用途地域系カテゴリ)の固定効果であり,都市計画区域内ダミー(0/1)ではない。Model 4 における各カテゴリの係数は以下のとおりである。

coef_m4 <- summary(m4)$coefficients
cityplan_rows <- grep("^city_planning", rownames(coef_m4))
round(coef_m4[cityplan_rows, ], 4)
##                       Estimate Std. Error t value Pr(>|t|)
## city_planning1中住専   0.0062     0.0150  0.4171   0.6766
## city_planning1低住専  -0.0086     0.0153 -0.5616   0.5744
## city_planning2種住居   0.1475     0.0663  2.2250   0.0261
## city_planning2中住専   0.0123     0.0323  0.3823   0.7023
## city_planning2低住専   0.0154     0.0446  0.3449   0.7302
## city_planning近隣商業   0.0426     0.0223  1.9089   0.0563
## city_planning工業      -0.0841     0.0538 -1.5636   0.1180
## city_planning工業専用  -0.2722     0.2434 -1.1182   0.2636
## city_planning準工業    -0.0430     0.0180 -2.3960   0.0166
## city_planning準住居    -0.1213     0.0491 -2.4680   0.0136

4モデルの推定結果の比較

stargazer(
  m1, m2, m3, m4,
  type          = out_type,
  title         = "表1:回帰分析結果(被説明変数:log(取引価格))",
  column.labels = c("(1) Base", "(2) +Municipality", "(3) +CityPlan", "(4) Integrated"),
  covariate.labels = c(
    "土地面積(㎡)",
    "延床面積(㎡)",
    "駅距離(分)",
    "築年数(年)",
    "建物構造:SRC",
    "建物構造:ブロック造",
    "建物構造:軽量鉄骨造",
    "建物構造:鉄骨造",
    "建物構造:木造"
  ),
  omit          = c("municipality", "city_planning"),
  add.lines     = list(
    c("市区町村FE", "No", "Yes", "No", "Yes"),
    c("都市計画FE",  "No", "No",  "Yes", "Yes")
  ),
  omit.stat     = c("f", "ser"),
  digits        = 4,
  star.cutoffs  = c(0.05, 0.01, 0.001),
  notes         = "* p<0.05, ** p<0.01, *** p<0.001. 建物構造の基準カテゴリ:RC造",
  notes.append  = FALSE,
  header        = FALSE,
  no.space      = TRUE,
  font.size     = "small"
)
表1:回帰分析結果(被説明変数:log(取引価格))
Dependent variable:
log_price
  1. Base
  1. +Municipality
  1. +CityPlan
  1. Integrated
(1) (2) (3) (4)
土地面積(㎡) -0.0010*** 0.0039*** -0.0021*** 0.0039***
(0.0002) (0.0002) (0.0002) (0.0002)
延床面積(㎡) 0.0085*** 0.0047*** 0.0093*** 0.0046***
(0.0003) (0.0002) (0.0003) (0.0002)
駅距離(分) -0.0251*** -0.0139*** -0.0259*** -0.0137***
(0.0012) (0.0008) (0.0012) (0.0008)
築年数(年) -0.0169*** -0.0172*** -0.0168*** -0.0172***
(0.0005) (0.0003) (0.0005) (0.0003)
建物構造:SRC 0.1067 0.1223 0.0815 0.1048
(0.3013) (0.1752) (0.2958) (0.1749)
建物構造:ブロック造 1.1235** 1.3130*** 1.2825** 1.3047***
(0.4241) (0.2480) (0.4165) (0.2478)
建物構造:軽量鉄骨造 -0.1654** -0.0117 -0.1221* -0.0110
(0.0618) (0.0361) (0.0607) (0.0360)
建物構造:鉄骨造 -0.3231*** -0.0324 -0.2464*** -0.0277
(0.0652) (0.0383) (0.0644) (0.0384)
建物構造:木造 -0.3385*** -0.1534*** -0.3079*** -0.1537***
(0.0545) (0.0319) (0.0535) (0.0318)
Constant 17.9554*** 16.4966*** 17.9087*** 16.4918***
(0.0653) (0.0621) (0.0661) (0.0631)
市区町村FE No Yes No Yes
都市計画FE No No Yes Yes
Observations 3,890 3,890 3,890 3,890
R2 0.4359 0.8132 0.4591 0.8147
Adjusted R2 0.4346 0.8104 0.4564 0.8114
Note:
  • p<0.05, ** p<0.01, *** p<0.001. 建物構造の基準カテゴリ:RC造

多重共線性の確認

m_vif <- lm(log_price ~ area + floor_area + distance_num + age, data = dat)
vif(m_vif)
##         area   floor_area distance_num          age 
##     1.662664     1.578035     1.074740     1.014037

不均一分散の確認とロバスト標準誤差

図3の残差診断(後掲)から、当てはめ値が大きい領域で残差のばらつきがやや拡大する 傾向が見られる。OLS標準誤差は不均一分散のもとで一致性を持つものの非効率であり、 t値・p値の信頼性が低下する可能性がある。 以下ではHC1型ロバスト標準誤差(heteroscedasticity-consistent covariance matrix)を用いて 主要係数の有意性を再確認する。 なお、HC3型はブロック造(1件)の観測値においてレバレッジ値が1に近く \((1 - h_{ii})^2 \approx 0\)となるため分散の推定値がNaNになる。 そのため本分析ではHC1型を採用した。

# HC1型ロバスト標準誤差によるModel 2の再推定
# (HC3はブロック造1件のレバレッジ≒1により分母≒0となりNaNが生じるためHC1を使用)
coeftest_robust <- coeftest(m2, vcov = vcovHC(m2, type = "HC1"))

# 主要な連続変数のみ抜粋して比較
rows_key <- c("area", "floor_area", "distance_num", "age")
comparison_se <- data.frame(
  変数           = c("土地面積", "延床面積", "駅距離", "築年数"),
  OLS係数        = round(coef(m2)[rows_key], 5),
  OLS標準誤差    = round(summary(m2)$coefficients[rows_key, "Std. Error"], 5),
  OLS_p値        = round(summary(m2)$coefficients[rows_key, "Pr(>|t|)"], 5),
  Robust標準誤差 = round(coeftest_robust[rows_key, "Std. Error"], 5),
  Robust_p値     = round(coeftest_robust[rows_key, "Pr(>|t|)"], 5)
)

kable(comparison_se,
      caption = "表2:OLS標準誤差とHC1型ロバスト標準誤差の比較(Model 2)",
      row.names = FALSE)
表2:OLS標準誤差とHC1型ロバスト標準誤差の比較(Model 2)
変数 OLS係数 OLS標準誤差 OLS_p値 Robust標準誤差 Robust_p値
土地面積 0.00387 0.00015 0 0.00022 0
延床面積 0.00466 0.00019 0 0.00033 0
駅距離 -0.01391 0.00076 0 0.00077 0
築年数 -0.01717 0.00028 0 0.00038 0

モデル診断

par(mfrow = c(1, 2), family = if (knitr::is_latex_output()) "IPAexGothic" else "")

plot(fitted(m2), residuals(m2),
     xlab = "当てはめ値(fitted values)",
     ylab = "残差(residuals)",
     main = "残差 vs. 当てはめ値",
     pch = 16, cex = 0.4, col = adjustcolor("steelblue", alpha.f = 0.4))
abline(h = 0, col = "red", lty = 2)

qqnorm(residuals(m2),
       main = "QQプロット(残差の正規性)",
       pch = 16, cex = 0.4, col = adjustcolor("tomato", alpha.f = 0.4))
qqline(residuals(m2), col = "red", lty = 2)
図3:Model 2 の残差診断

図3:Model 2 の残差診断

par(mfrow = c(1, 1))

価格予測(Model 2 を使用)

ターゲット物件の定義

実在する中古戸建物件(SUUMO掲載、情報提供日:2026年4月13日)を対象とする。

属性
所在地 東京都新宿区原町1丁目
最寄駅 都営大江戸線「牛込柳町」駅 徒歩1分
土地面積 43.75 ㎡
延床面積 64.24 ㎡
築年数 1年(2023年2月築、基準年2024年)
建物構造 木造
市区町村 新宿区
販売価格(実績) 1億4800万円

築年数の処理について: 本物件は2023年2月築であり、データの基準年2024年との差は厳密には 取引時期に応じて1〜2年の間となる。本分析では保守的に age = 1(最小値)を採用しており、 築年数をわずかに若く見積もっているため、予測価格はやや上方バイアスを持つ可能性がある。

予測の手順

Step 1. 対数価格を予測する。

\[ \log\hat{y}_V = \hat{\beta}_0 + 0.0039 \times 43.75 + 0.0047 \times 64.24 - 0.0139 \times 1 - 0.0172 \times 1 + (\text{木造係数}) + (\text{新宿区係数}) \]

Step 2. 誤差項 \(\epsilon_i \sim N(0, \sigma^2)\) を仮定すると \(E[\exp(\epsilon_i)] = \exp(\sigma^2/2)\) が成立するため、 元の価格スケールへの変換時に補正が必要である。

\[ \hat{y}_V = \exp\!\left(\log\hat{y}_V + \frac{\hat{\sigma}^2}{2}\right) \]

価格予測の実行

# ターゲット物件の属性(実在物件:新宿区原町1丁目)
target <- data.frame(
  area          = 43.75,
  floor_area    = 64.24,
  distance_num  = 1,
  age           = 1,      # 2023年2月築、基準年2024年(保守的にage=1を採用)
  structure     = factor("木造",   levels = levels(dat$structure)),
  municipality  = factor("新宿区", levels = levels(dat$municipality))
)

# 対数価格の予測値
log_price_hat <- predict(m2, newdata = target)
log_price_hat
##        1 
## 18.33705
# 残差標準誤差と残差分散
summary(m2)$sigma
## [1] 0.2428674
sigma2_hat <- summary(m2)$sigma^2
sigma2_hat
## [1] 0.05898456
# 補正なし予測価格(万円)
exp(log_price_hat) / 1e4
##        1 
## 9197.669
# 補正あり予測価格(万円):E[y] の不偏推定
price_pred_corrected_man <- exp(log_price_hat + sigma2_hat / 2) / 1e4
price_pred_corrected_man
##        1 
## 9472.969
# 95% 予測区間(万円)
pred_interval <- predict(m2, newdata = target,
                         interval = "prediction", level = 0.95)
exp(pred_interval) / 1e4
##        fit     lwr      upr
## 1 9197.669 5685.17 14880.31
# 実際の販売価格
actual_price_man <- 14800
cat("予測値(補正あり):", round(price_pred_corrected_man, 0), "万円\n")
## 予測値(補正あり): 9473 万円
cat("実際の販売価格:    ", actual_price_man, "万円\n")
## 実際の販売価格:     14800 万円
cat("差(予測 - 実際): ", round(price_pred_corrected_man - actual_price_man, 0), "万円\n")
## 差(予測 - 実際):  -5327 万円

予測結果の可視化と実際価格との比較

price_pred_corrected <- exp(log_price_hat + sigma2_hat / 2)
pi_lower <- exp(pred_interval[, "lwr"])
pi_upper <- exp(pred_interval[, "upr"])

similar <- dat %>%
  filter(structure == "木造", municipality == "新宿区")

cat("木造・新宿区のサンプル数:", nrow(similar), "\n")
## 木造・新宿区のサンプル数: 46
ggplot(similar, aes(x = price / 1e4)) +
  geom_histogram(bins = 20, fill = "steelblue", alpha = 0.6, color = "white") +
  geom_vline(xintercept = price_pred_corrected / 1e4,
             color = "red", linewidth = 1.2, linetype = "solid") +
  geom_vline(xintercept = actual_price_man,
             color = "darkgreen", linewidth = 1.2, linetype = "solid") +
  geom_vline(xintercept = pi_lower / 1e4,
             color = "orange", linewidth = 0.8, linetype = "dashed") +
  geom_vline(xintercept = pi_upper / 1e4,
             color = "orange", linewidth = 0.8, linetype = "dashed") +
  annotate("text",
           x = price_pred_corrected / 1e4,
           y = Inf, vjust = 2, hjust = 1.1,
           label = paste0("予測値\n", round(price_pred_corrected / 1e4, 0), "万円"),
           color = "red", size = 3.5) +
  annotate("text",
           x = actual_price_man,
           y = Inf, vjust = 4, hjust = -0.1,
           label = paste0("販売価格\n", actual_price_man, "万円"),
           color = "darkgreen", size = 3.5) +
  labs(x = "取引価格(万円)", y = "件数",
       title = "予測価格と実績分布の比較(木造・新宿区)",
       caption = "赤線: 補正済み予測値, 緑線: 実際の販売価格, オレンジ破線: 95%予測区間\n※木造・新宿区のサンプルは限られるため分布の形状の解釈には注意が必要")
図4:予測価格・実際価格と95%予測区間(同属性物件の実績分布との比較)。木造・新宿区のサンプルは限られるため、分布の形状の解釈には注意が必要である。

図4:予測価格・実際価格と95%予測区間(同属性物件の実績分布との比較)。木造・新宿区のサンプルは限られるため、分布の形状の解釈には注意が必要である。

付録

付録1:SRCおよびブロック造の感度分析

SRC(2件)およびブロック造(1件)はサンプル数が極端に少なく、Model 2 における推定値が不安定である可能性が高い(特にブロック造の係数は約 1.31 と不自然に大きい)。以下では、これら2つの構造を「その他」カテゴリに統合し、主要な連続変数および建物構造の各係数への影響を確認する。

library(forcats)

# SRCとブロック造を「その他」に統合
dat_sens4 <- dat %>%
  mutate(structure_sens = fct_collapse(structure,
                                       "その他" = c("SRC", "ブロック造")))

m2_sens4 <- lm(log_price ~ area + floor_area + distance_num + age +
                 structure_sens + municipality,
               data = dat_sens4)

# 比較する変数のリスト
rows_orig <- c("area", "floor_area", "distance_num", "age",
               "structure軽量鉄骨造", "structure鉄骨造", "structure木造")
rows_sens <- c("area", "floor_area", "distance_num", "age",
               "structure_sens軽量鉄骨造", "structure_sens鉄骨造", "structure_sens木造")

coef_orig <- summary(m2)$coefficients
coef_sens <- summary(m2_sens4)$coefficients

comparison <- data.frame(
  変数          = c("土地面積", "延床面積", "駅距離", "築年数",
                    "建物構造:軽量鉄骨造", "建物構造:鉄骨造", "建物構造:木造"),
  元モデル係数  = round(coef_orig[rows_orig, "Estimate"], 5),
  感度分析係数  = round(coef_sens[rows_sens, "Estimate"], 5)
)

kable(comparison, caption = "表A1:小サンプル構造統合前後の主要係数比較")
表A1:小サンプル構造統合前後の主要係数比較
変数 元モデル係数 感度分析係数
area 土地面積 0.00387 0.00390
floor_area 延床面積 0.00466 0.00461
distance_num 駅距離 -0.01391 -0.01389
age 築年数 -0.01717 -0.01715
structure軽量鉄骨造 建物構造:軽量鉄骨造 -0.01167 -0.01329
structure鉄骨造 建物構造:鉄骨造 -0.03238 -0.03233
structure木造 建物構造:木造 -0.15343 -0.15511
cat("元モデル 調整済みR²:  ", round(summary(m2)$adj.r.squared, 4), "\n")
## 元モデル 調整済みR²:   0.8104
cat("感度分析 調整済みR²:  ", round(summary(m2_sens4)$adj.r.squared, 4), "\n")
## 感度分析 調整済みR²:   0.8097
target_sens4 <- data.frame(
  area            = 43.75,
  floor_area      = 64.24,
  distance_num    = 1,
  age             = 1,
  structure_sens  = factor("木造", levels = levels(dat_sens4$structure_sens)),
  municipality    = factor("新宿区", levels = levels(dat$municipality))
)

log_pred_sens4  <- predict(m2_sens4, newdata = target_sens4)
sigma2_sens4    <- summary(m2_sens4)$sigma^2
price_sens4_man <- exp(log_pred_sens4 + sigma2_sens4 / 2) / 1e4

cat("元モデル 予測価格:", round(price_pred_corrected_man, 0), "万円\n")
## 元モデル 予測価格: 9473 万円
cat("感度分析 予測価格:", round(price_sens4_man, 0), "万円\n")
## 感度分析 予測価格: 9472 万円

付録2:「30分〜60分」の感度分析(駅距離変数に関する追加分析)

「30分〜60分」(269件、全体の約5%)を中間値45分として扱う現行の処理に対し、 これらを除外した場合の主要係数と R² を確認する。

dat_sens5 <- dat %>% filter(distance_num != 45)
cat("「30分~60分」除外後のサンプル数:", nrow(dat_sens5), "\n")
## 「30分~60分」除外後のサンプル数: 3875
m2_sens5 <- lm(log_price ~ area + floor_area + distance_num + age +
                 structure + municipality,
               data = dat_sens5)

# 主要係数の比較
rows_key <- c("area", "floor_area", "distance_num", "age", "structure木造")
comparison5 <- data.frame(
  変数          = c("土地面積", "延床面積", "駅距離", "築年数", "木造"),
  元モデル係数  = round(coef_orig[rows_key, "Estimate"], 5),
  除外時係数    = round(summary(m2_sens5)$coefficients[rows_key, "Estimate"], 5)
)
kable(comparison5, caption = "表A2:「30分〜60分」除外前後の主要係数比較")
表A2:「30分〜60分」除外前後の主要係数比較
変数 元モデル係数 除外時係数
area 土地面積 0.00387 0.00388
floor_area 延床面積 0.00466 0.00465
distance_num 駅距離 -0.01391 -0.01405
age 築年数 -0.01717 -0.01714
structure木造 木造 -0.15343 -0.15282
cat("元モデル 調整済みR²:  ", round(summary(m2)$adj.r.squared, 4), "\n")
## 元モデル 調整済みR²:   0.8104
cat("除外モデル 調整済みR²:", round(summary(m2_sens5)$adj.r.squared, 4), "\n")
## 除外モデル 調整済みR²: 0.8094