LoginSignup
2
3

scikit-learn カリフォルニア住宅価格データの前処理に関する見解(コピペ利用可)

Last updated at Posted at 2023-01-17

scikit-learnのボストン住宅価格のデータをインポートすると、以下のメッセージが出力されます。倫理的な問題があり、scikit-learnとしてはカリフォルニア住宅価格データの利用を推奨しています。したがって今後は、カリフォルニア住宅価格データの活用が増える可能性があります。そこで、この記事では、カリフォルニア住宅価格データの前処理について見解を述べたいと思います。

Image from Gyazo

カリフォルニア住宅価格データは、どのようなデータか?

scikit-learnからカリフォルニア住宅価格データを取得し、DESCRキーの情報を確認します。

import pandas as pd
import seaborn as sns
from sklearn.datasets import fetch_california_housing
dataset = fetch_california_housing()
print(dataset.DESCR)

Image from Gyazo

以下のように解釈可能です。

  • 1990年のアメリカの国勢調査に基づく以下のデータ
  • 一定のエリア(以下ブロックと記載)で集計
  • レコード数は20640
  • カラムの構成は以下の通り
日(直訳)
MedInc ブロックの所得中央値
HouseAge ブロックの家屋年齢の中央値
AveRooms 1世帯あたりの平均部屋数
AveBedrms 1世帯あたりの平均寝室数
Population ブロックの人口
AveOccup 世帯人数の平均値
Latitude 緯度
Longitude 経度
Price 住宅価格

実際のデータを確認

DataFrameで実データを確認します。

df = pd.DataFrame(dataset.data, columns=dataset.feature_names)
df['Price'] = dataset.target
df.head()

Image from Gyazo

基本情報を確認

基本情報も確認します。

df.describe()

Image from Gyazo

df.info()

Image from Gyazo

欠損はないことが分かります。

各カラムのデータ分布

各カラムの分布を確認します。

df.hist(bins=30, figsize=(15, 10))

Image from Gyazo

いくつか怪しげな分布があるので、順に確認します。

Medinc(所得中央値)

Image from Gyazo

特に前処理の必要性は見当たりません。

AveRooms(平均部屋数), AveBedrms(平均寝室数)

Image from Gyazo

大きい値が確認しづらいため、散布図で表示します。

sns.scatterplot(data=df, x='AveRooms', y='AveBedrms')

Image from Gyazo

突出したデータが2件あります。抽出して詳細を確認します。

df.query('AveRooms > 100')

Image from Gyazo

最初に確認したDESCRキーの説明で以下の記載がありました。おそらく、これに該当する2件と考えられます。

An household is a group of people residing within a home. 
Since the average number of rooms and bedrooms in this dataset 
are provided per household, 
these columns may take surpinsingly large values 
for block groups with few households and many empty houses, 
such as vacation resorts.

世帯とは、家庭内に居住する人々の集団である。
このデータセットでは、1世帯あたりの平均的な部屋数と寝室数を示しているため、
別荘地など世帯数が少なく空家が多いブロックでは、
これらの列が突出して大きな値をとることがある。
※DeepL(https://www.deepl.com/translator)による翻訳

緯度・経度からGoogle Mapで確認します。

緯度, 経度 Google Map
38.91, -120.08 https://goo.gl/maps/5EtYsaVJXWcT5sYa9
38.80, -120.08 https://goo.gl/maps/JjbTB2Fou1Fq4Vnu5

Image from Gyazo

レイクタホの別荘かもしれません。
上記のようなデータが生まれる背景として、AveRooms(平均部屋数), AveBedrms(平均寝室数)は、AllRooms(ブロックの全部屋数), AllBedrms(ブロックの全寝室数), Household(世帯数)という元データがあり、以下の計算によって算出されていると推測できます。

  • AllRooms ÷ Household = AveRooms
  • AllBedrms ÷ Household = AveBedrms

別のカラムの情報として、Population(ブロックの人口), AveOccup(世帯人数の平均値)があります。同様に、以下の計算によって算出されていると推測できます。

  • Population ÷ Household = AveOccup

上記3つの算出ロジックが正しい場合、Population(ブロックの人口)とAveOccup(世帯人数の平均値)から、Household(世帯数)を算出できます。さらに、AveRooms(平均部屋数), AveBedrms(平均寝室数), Household(世帯数)から、AllRooms(ブロックの全部屋数), AllBedrms(ブロックの全寝室数)を算出できます。

一度計算してみます。

df['Household'] = df['Population']/df['AveOccup']
df['AllRooms'] = df['AveRooms']*df['Household']
df['AllBedrms'] = df['AveBedrms']*df['Household']
df.head()

Image from Gyazo

きれいな整数で出力されました。推測の正しさを補強する結果です。新たに生成したHousehold(世帯数), AllRooms(ブロックの全部屋数), AllBedrms(ブロックの全寝室数)の分布を確認します。

df[['Household', 'AllRooms', 'AllBedrms']].hist(bins=30, figsize=(15, 10))

Image from Gyazo

大きな値のデータが確認しづらいので、散布図で確認します。

sns.stripplot(data = df['Household'])

Image from Gyazo

Household(世帯数)について、目立った外れ値は見当たりません。

sns.scatterplot(data=df, x='AllRooms', y='AllBedrms')

Image from Gyazo

AllRooms(ブロックの全部屋数), AllBedrms(ブロックの全寝室数)はきれいに相関しており、目立った外れ値も見当たりません。

したがって、AveRooms(平均部屋数), AveBedrms(平均寝室数)よりも、その元データと推測されるHousehold(世帯数), AllRooms(ブロックの全部屋数), AllBedrms(ブロックの全寝室数)の活用をおすすめします。

Population(ブロックの人口)

Image from Gyazo

大きな値のデータが確認しづらいので、散布図で確認します。

sns.stripplot(data = df['Population'])

Image from Gyazo

突出している2つデータを抽出して確認します。

df.query('Population > 20000')

Image from Gyazo

緯度・経度から、どの場所を指しているか確認します。

緯度, 経度 Google Map
36.64, -121.79 https://goo.gl/maps/zfyzHtN5V4ns8S5EA
33.35, -117.42 https://goo.gl/maps/EvH6GN6DyDd8n6r77

Image from Gyazo

森林・山岳地帯のため、Population(ブロックの人口)の値のエラーが疑われます。一方で、AveOccup(世帯人数の平均値)は通常範囲の値を示しています。AveOccup(世帯人数の平均値)が「Population ÷ Household = AveOccup」で算出されているという前提が正しい場合、Population(ブロックの人口)がエラーとなれば、AveOccup(世帯人数の平均値)の値にも影響がでます。

したがって、Population(ブロックの人口)の値は正常であり、集計単位であるブロックの領域が広いために、Population(ブロックの人口)の値が大きくなっていると考える方が妥当でしょう。

AveOccup(世帯人数の平均値)

Image from Gyazo

大きな値のデータが確認しづらいので、散布図で確認します。

sns.stripplot(data = df['AveOccup'])

Image from Gyazo

上位4つデータを抽出して確認します。

df.query('AveOccup > 200')

Image from Gyazo

緯度・経度から、どの場所を指しているか確認します。

緯度, 経度 Google Map
40.41, -120.51 https://goo.gl/maps/JVo1yj2XbrGfdYMj6
38.69, -121.15 https://goo.gl/maps/zJZVsaYLef3h9CZh7
35.32, -120.70 https://goo.gl/maps/PU6JvRJQ7nUh5Q889
38.32, -121.98 https://goo.gl/maps/FNwkDhbgoSif3RGD7

Image from Gyazo

それぞれ、近くに刑務所(High Desert State Prison, California State Prison - Sacramento, California Men's Colony, California State Prison Solano)があります。

Population(ブロックの人口)は実際に居住している人数、Household(世帯数)はドキュメント上(例えば、住民票や世帯主数など)の数値であり、その結果、刑務所エリアでAveOccup(世帯人数の平均値)の数値が高まっていると考えられます。

AveOccup(世帯人数の平均値)についても、Household(世帯数)で割ることで大きな値が発生しているため、代わりに元データと推測されるPopulation(ブロックの人口), Household(世帯数)の活用をおすすめします。

Latitude(緯度), Longitude(経度)

Image from Gyazo

とくに目立った外れ値は確認できません。散布図にプロットすると、カリフォルニアの地形をほぼ網羅していることを確認できます。

sns.scatterplot(data=df, x='Longitude', y='Latitude')

Image from Gyazo

引用:Google Map https://goo.gl/maps/McF5JYkYddyY7SWX8

住宅価格の予測において、多くの場合、沿岸部と内陸部という指標は有効に機能します。カリフォルニアの地理から、「南西→北東」方向を「海岸→内陸」方向と近似することが可能です。「南西→北東方向」軸の指標として「緯度と経度の合計値」を活用するなど、新しい列を追加しても良いでしょう。

HouseAge(ブロックの家屋年齢の中央値), Price(住宅価格)

Image from Gyazo

一番右のバーが不自然に突出しています。

Image from Gyazo

HouseAge(ブロックの家屋年齢の中央値), Price(住宅価格)それぞれの最大値は上記のとおり、52と5.00001です。それぞれ最大値となっているデータ数を確認します。

print(df.query('HouseAge == 52').shape)
print(df.query('Price == 5.00001').shape)

Image from Gyazo

最大値のデータが、それぞれ1000データ近くあることを意味しています。多くのデータが一致することは現実的に考えづらく、おそらく国勢調査で、52以上のデータ、5.00001以上のデータとして処理されていると推測されます。したがって、数値として取り扱う必要がある場合は、それぞれ最大値のデータのみ除外することが推奨されます。

df = df[df['HouseAge'] != 52]
df = df[df['Price'] != 5.00001]

まとめ

各カラムに対する見解は以下の通りです。

日(直訳) 見解
MedInc ブロックの所得中央値 前処理不要
HouseAge ブロックの家屋年齢の中央値 最大値52のデータを削除
AveRooms 1世帯あたりの平均部屋数 利用しない
AveBedrms 1世帯あたりの平均寝室数 利用しない
Population ブロックの人口 前処理不要
AveOccup 世帯人数の平均値 利用しない
Latitude 緯度 前処理不要
Longitude 経度 前処理不要
Price 住宅価格 最大値5.00001のデータを削除
Household 世帯数 PopulationとAveOccupから新規に作成
AllRooms ブロックの全部屋数 HouseholdとAveRoomsから新規に作成
AllBedrms ブロックの全寝室数 HouseholdとAveBedrmsから新規に作成

前処理は、実際のデータを見る(今回の場合はGoogle Mapを見る)というアクションが重要だと、改めて再認識しました。1日でアメリカの刑務所を4つも調べたのは、初めての体験でした。

前処理の技術的な側面は、以下のコンテンツ(私が制作したもの)がおすすめです。前処理の部分が一部無料で見られます。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3