kaggle專題:利用Python分析房價

公衆號:尤而小屋
作者:Peter
編輯:Peter

大家好,我是Peter~

這個是Kaggle專欄的第二篇,賽題名是: House Prices - Advanced Regression Techniques。在本文中,你將會學習到:

  • 單、多變量分析
  • 相關性分析
  • 缺失值和異常值處理
  • 啞變量轉換

原notebook地址:https://www.kaggle.com/pmarcelino/comprehensive-data-exploration-with-python

排名榜

讓我們看下排名榜,第一名真的是碾壓其他選手呀~所以,今天我們一起看看這個第一名的方案到底是多棒?

數據介紹

這份波士頓房價的數據集有4份數據,訓練集train+測試集test+數據集的描述description+提交模板sample

其中訓練集有81個特徵,1460條數據;測試集81個特徵,1459條數據。看下部分屬性介紹:

數據EDA

導入模塊和數據,並進行數據探索:

導入庫

import pandas as pd
import numpy as np
# 繪圖相關
import plotly.express as px
import matplotlib.pyplot as plt
import seaborn as sns
plt.style.use("fivethirtyeight")

# 數據建模
from scipy.stats import norm
from scipy import stats
from sklearn.preprocessing import StandardScaler

# 警告
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline

導入數據

數據信息

訓練集整體是1460*81;而且很多的存在字段都存在缺失值

描述統計信息:

銷售價格SalePrice分析

前原notebook文檔中,作者分析了很多自己關於這個題目和字段的看法,具體不闡述。下面介紹的是重點部分:

統計信息

單單看這個字段的統計信息:

分佈直方圖如下,我們明顯感受到:

  • 價格的分佈偏離了正態分佈
  • 有明顯的正偏度現象
  • 有明顯的峯值出現

偏度和峯度(skewness and kurtosis)

知識加油站:偏度和峯度

詳細的解釋參見文章:https://zhuanlan.zhihu.com/p/53184516

  • 偏度:衡量隨機變臉概率分佈的不對稱性,是相對於平均值不對稱程度的度量,通過對偏度係數的測量,我們能夠判定數據分佈的不對稱程度以及方向。
  • 峯度:是研究數據分佈陡峭或者平滑的統計量,通過對峯度係數的測量,我們能夠判定數據相對於正態分佈而言是更陡峭還是更平緩。峯度接近0,數據呈現正態分佈;峯度>0,高尖分佈;峯度<0,矮胖分佈

偏度的兩種分佈情況:

  • 如果是左偏,則偏度小於0
  • 如果是右偏,則偏度大於0

峯度的兩種分佈情況:

  • 如果是高瘦型,則峯度大於0
  • 如果是矮胖型,則峯度小於0
# 打印銷售價格的偏度和峯度

print("Skewness(偏度): %f" % train['SalePrice'].skew())
print("Kurtosis(峯度): %f" % train['SalePrice'].kurt())

Skewness(偏度): 1.882876
Kurtosis(峯度): 6.536282

偏度和峯度值都是正的,明顯說明數據是右偏且高尖分佈

SalePrice和數值型字段的關係

首先我們考察和居住面積的關係:

plt.figure(1,figsize=(12,6))
sns.scatterplot(x="GrLivArea",y="SalePrice",data=data)
plt.show()
# plotly版本
px.scatter(data,x="GrLivArea",y="SalePrice",trendline="ols")

TotalBsmtSF VS SalePrice

# 2、TotalBsmtSF 
data = train[["SalePrice","TotalBsmtSF"]]

plt.figure(1,figsize=(12,6))
sns.scatterplot(x="TotalBsmtSF",y="SalePrice",data=data)
plt.show()

小結:我們可以觀察到這兩個特徵和銷售價格之間是存在一定的線性關係。

價格和分類型字段的關係

1、OverallQual VS SalePrice

# 1、OverallQual:整體房屋質量

# 總共10個類別
train["OverallQual"].value_counts()
5     397
6     374
7     319
8     168
4     116
9      43
3      20
10     18
2       3
1       2
Name: OverallQual, dtype: int64
data = train[["SalePrice","OverallQual"]]

# 房屋整體質量和房價的關係
# 繪製子圖:1號位
f,ax = plt.subplots(1,figsize=(12,6))
fig = sns.boxplot(x="OverallQual",y="SalePrice",data=data)
# y軸的刻度範圍
fig.axis(ymin=0,ymax=800000)
plt.show()

2、YearBuilt VS SalePrice

住在建造年份和銷售價格的關係

data = train[["SalePrice","YearBuilt"]]

# 建造年份和房價的關係
f,ax = plt.subplots(1,figsize=(16,8))
fig = sns.boxplot(x="YearBuilt",y="SalePrice",data=data)
# y軸的刻度範圍
fig.axis(ymin=0,ymax=800000)
plt.show()

小結:銷售價格和住宅的整體質量有很強的關係;但是和建築年份的關係不大。但是在實際的買房過程中,我們還是會很在意年份

小結

對上面分析的一點小結:

  1. 地面生活區(GrLivArea)、地下室面積(GrLivArea)和銷售價格SalePrice都是呈現正向的線性相關
  2. 房屋的整體質量(OverallQual)和建造年份(YearBuilt)好像也和銷售價格線性相關。常識來說,整體的質量越好,價格越貴

相關性分析

爲了探索衆多屬性之間的關係,進行如下的分析:

  • 兩兩屬性間的相關性(熱力圖)
  • 銷售價格saleprice和其他屬性的關係(熱力圖)
  • 關聯性最大的屬性間的關係(散點圖)

整體相關性

分析每兩個屬性的相關性,並繪製熱力圖

上圖中有兩個值得關注的點:

  • TotalBsmtSF and 1stFlrSF
  • GarageCar and GarageArea

這兩組變量都是強相關的,我們後續的分析只取其中一個

縮放相關矩陣(銷售價格saleprice)

上面的熱力圖中選擇和SalePrice相關性最強的前10個特徵來繪製熱力圖

sns.set(font_scale=1.25)
hm = sns.heatmap(
    cm,  # 繪圖數據
    cbar=True,  # 是否將顏色條作爲圖例,默認True
    annot=True,  # 是否顯示數值
    square=True,  # 是否使熱力圖每個單元爲正方形,默認爲False
    fmt='.2f',  # 保留兩位小數
    annot_kws={'size':10},
    xticklabels=cols.values, # xy軸設置
    yticklabels=cols.values)

plt.show()

小結1

通過上面的縮放熱力圖,我們可以得到下面的結論:

  • 'OverallQual', 'GrLivArea' and 'TotalBsmtSF'是真的和'SalePrice'呈現強相關
  • 'GarageCars' and 'GarageArea' 也是兩個相關性比較強的特徵;而且他們都是同時出現,後續選取GarageCars進行分析
  • 建築年限'YearBuilt'相對來說,相關性比較低

變量離散圖

將銷售價格SalePrice和幾個相關性比較強的特徵放在一起,繪製變量離散圖

sns.set()
# 待分析的變量
cols = ['SalePrice', 'OverallQual', 'GrLivArea', 'GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']
sns.pairplot(train[cols],size=2.5)
plt.show()

小結2

正對角線方向上是變量的直方圖,解釋變量和被解釋變量SalePrice,其他的則是散點圖。

如果圖中呈現直線或者橫線的散點,則說明該變量是離散的,比如第1行4列的變量,y軸是SalePrice,x軸是YearBuilt,直線說明YearBuilt是離散的

缺失值處理

針對缺失值的情況,主要是討論兩點:

  • 缺失值分佈情況怎麼樣?
  • 缺失值是隨機的?還有具有某種規律

缺失值佔比

1、查看每個字段的缺失值情況

# 每個字段的缺失值數量:降序
total = train.isnull().sum().sort_values(ascending=False)
total.head()
PoolQC         1453
MiscFeature    1406
Alley          1369
Fence          1179
FireplaceQu     690
dtype: int64

2、轉成百分比

# 每個字段的缺失值 / 總數
percent = (train.isnull().sum() / train.isnull().count()).sort_values(ascending=False)
percent.head()
PoolQC         0.995205
MiscFeature    0.963014
Alley          0.937671
Fence          0.807534
FireplaceQu    0.472603
dtype: float64

3、數據合併,整體的缺失值情況:

刪除缺失值

原文中分析了很多,最後的結論:

In summary, to handle missing data,

1、we'll delete all the variables with missing data, except the variable 'Electrical'.

2、In 'Electrical' we'll just delete the observation with missing data.

# 步驟1:需要刪除的字段
missing_data[missing_data["Total"] > 1].index
Index(['PoolQC', 'MiscFeature', 'Alley', 'Fence', 'FireplaceQu', 'LotFrontage',
       'GarageYrBlt', 'GarageCond', 'GarageType', 'GarageFinish', 'GarageQual',
       'BsmtFinType2', 'BsmtExposure', 'BsmtQual', 'BsmtCond', 'BsmtFinType1',
       'MasVnrArea', 'MasVnrType'],
      dtype='object')
# 第一步
train = train.drop(missing_data[missing_data["Total"] > 1].index,1)
#   第二步
train = train.drop(train.loc[train["Electrical"].isnull()].index)

離羣點out liars

查找離羣點

## 數據標準化standardizing data
# np.newaxis 增加數據維度,一維變成二維
saleprice_scaled = StandardScaler().fit_transform(train["SalePrice"][:,np.newaxis])
saleprice_scaled[:5]
array([[ 0.34704187],
       [ 0.0071701 ],
       [ 0.53585953],
       [-0.5152254 ],
       [ 0.86943738]])
# 查看前10和最後10位的數據
# argsort:返回的是索引值;默認是升序排列,最小的在最前面,最大的在最後

low_range = saleprice_scaled[saleprice_scaled[:,0].argsort()][:10]

high_range = saleprice_scaled[saleprice_scaled[:,0].argsort()][-10:]

print(low_range)
print('----------')
print(high_range)

小結3

  • low_range接近,且離0比較近
  • high_range離0很遠;且7+的數據就應該是離羣點了

單變量分析1

data = train[["SalePrice","GrLivArea"]]
data.plot.scatter(x="GrLivArea",y="SalePrice",ylim=(0,800000))
plt.show()

很明顯的,兩個變量(屬性)存在一種線性關係

刪除離羣點

指定刪除某個字段爲具體值的方法:

單變量分析2

data = train[["SalePrice","TotalBsmtSF"]]   # 待分析的兩個變量
data.plot.scatter(x="TotalBsmtSF",y="SalePrice",ylim=(0,800000))
plt.show()

深入理解SalePrice

主要從以下幾個方面來深入研究銷售價格:

  • Normality:歸一化
  • Homoscedasticity:同方差性
  • Linearity:線性特質
  • Absence of correlated errors:相關誤差

Normality歸一化(SalePrice)

sns.distplot(train["SalePrice"],fit=norm)
fig = plt.figure()
res = stats.probplot(train["SalePrice"], plot=plt)

我們發現:銷售價格不是正態分佈的,出現了右偏度;同時也不遵循對數變化的規律。

爲了解決這個問題:實施對數變換

## 對數變換
train["SalePrice"] = np.log(train["SalePrice"])

sns.distplot(train["SalePrice"],fit=norm)
fig = plt.figure()
res = stats.probplot(train["SalePrice"], plot=plt)

實施對數變換後效果好了很多的

Normality-歸一化(GrLivArea)

sns.distplot(train["GrLivArea"],fit=norm)
fig = plt.figure()
res = stats.probplot(train["GrLivArea"], plot=plt)

對數變換前的效果:

執行對數變換及效果:

# 執行相同的對數操作
train["GrLivArea"] = np.log(train["GrLivArea"])

sns.distplot(train["GrLivArea"],fit=norm)
fig = plt.figure()
res = stats.probplot(train["GrLivArea"], plot=plt)

Normality-歸一化(TotalBsmtSF)

sns.distplot(train["TotalBsmtSF"],fit=norm)
fig = plt.figure()
res = stats.probplot(train["TotalBsmtSF"], plot=plt)

處理之前的效果:

如何處理上面的特殊部分?

# 增加一列數據
train['HasBsmt'] = 0

# 當TotalBsmtSF>0 則賦值1
train.loc[train['TotalBsmtSF']>0,'HasBsmt'] = 1

# 對數轉換:等於1的部分
train.loc[train['HasBsmt']==1,'TotalBsmtSF'] = np.log(train['TotalBsmtSF'])

# 繪圖
data = train[train['TotalBsmtSF']>0]['TotalBsmtSF']
sns.distplot(data,fit=norm)
fig = plt.figure()
res = stats.probplot(data, plot=plt)

同方差性

檢驗兩個變量之間的同方差性最好的方法就是作圖。

The best approach to test homoscedasticity for two metric variables is graphically

1、討論:'SalePrice' 和'GrLivArea'之間的關係

2、討論SalePrice' 和 'TotalBsmtSF'

We can say that, in general, 'SalePrice' exhibit equal levels of variance across the range of 'TotalBsmtSF'. Cool!

從上面的兩張圖中,我們看到:銷售價格和另外兩個變量都是呈現一定的正向關係

生成啞變量

虛擬變量( Dummy Variables) 又稱虛設變量、名義變量或啞變量,用以反映質的屬性的一個人工變量,是量化了的自變量,通常取值爲0或1。

Pandas中的get_dummies函數能夠實現:

train = pd.get_dummies(train)  # 生成啞變量
train

總結

至此,我們完成了以下的內容:

  1. 整體變量間的相關性分析
  2. 重點分析了變量“SalePrice”
  3. 處理缺失值和異常值(離羣點)
  4. 做了一些統計分析,將分類變量變成了啞變量

自己需要後續補充深入學習的點:

  • 多元統計分析
  • 偏度和峯度
  • 啞變量的深入
  • 標準化和歸一化

關於數據集的領取,公衆號後臺回覆:房價。看完整篇文章的分析過程,有什麼感受呢?

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章