露一手,利用Python分析房價

語言: CN / TW / HK

theme: smartblue

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

大家好,我是Peter~

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

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

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

排名榜

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

資料介紹

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

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

資料EDA

匯入模組和資料,並進行資料探索:

匯入庫

```python 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)

知識加油站:偏度和峰度

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

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

偏度的兩種分佈情況:

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

峰度的兩種分佈情況:

  • 如果是高瘦型,則峰度大於0
  • 如果是矮胖型,則峰度小於0

```python

列印銷售價格的偏度和峰度

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

Skewness(偏度): 1.882876 Kurtosis(峰度): 6.536282 ```

偏度和峰度值都是正的,明顯說明資料是右偏且高尖分佈

SalePrice和數值型欄位的關係

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

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

```python

plotly版本

px.scatter(data,x="GrLivArea",y="SalePrice",trendline="ols") ```

TotalBsmtSF VS SalePrice

```python

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

```python

1、OverallQual:整體房屋質量

總共10個類別

train["OverallQual"].value_counts() ```

python 5 397 6 374 7 319 8 168 4 116 9 43 3 20 10 18 2 3 1 2 Name: OverallQual, dtype: int64

```python 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

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

```python 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個特徵來繪製熱力圖

```python 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和幾個相關性比較強的特徵放在一起,繪製變數離散圖

```python 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、檢視每個欄位的缺失值情況

```python

每個欄位的缺失值數量:降序

total = train.isnull().sum().sort_values(ascending=False) total.head() ```

python PoolQC 1453 MiscFeature 1406 Alley 1369 Fence 1179 FireplaceQu 690 dtype: int64

2、轉成百分比

```python

每個欄位的缺失值 / 總數

percent = (train.isnull().sum() / train.isnull().count()).sort_values(ascending=False) percent.head() ```

python 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.

```python

步驟1:需要刪除的欄位

missing_data[missing_data["Total"] > 1].index ```

python Index(['PoolQC', 'MiscFeature', 'Alley', 'Fence', 'FireplaceQu', 'LotFrontage', 'GarageYrBlt', 'GarageCond', 'GarageType', 'GarageFinish', 'GarageQual', 'BsmtFinType2', 'BsmtExposure', 'BsmtQual', 'BsmtCond', 'BsmtFinType1', 'MasVnrArea', 'MasVnrType'], dtype='object')

```python

第一步

train = train.drop(missing_data[missing_data["Total"] > 1].index,1)

第二步

train = train.drop(train.loc[train["Electrical"].isnull()].index) ```

離群點out liars

查詢離群點

```python

資料標準化standardizing data

np.newaxis 增加資料維度,一維變成二維

saleprice_scaled = StandardScaler().fit_transform(train["SalePrice"][:,np.newaxis]) saleprice_scaled[:5] ```

python array([[ 0.34704187], [ 0.0071701 ], [ 0.53585953], [-0.5152254 ], [ 0.86943738]])

```python

檢視前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

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

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

刪除離群點

指定刪除某個欄位為具體值的方法:

單變數分析2

python 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)

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

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

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

```python

對數變換

train["SalePrice"] = np.log(train["SalePrice"])

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

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

Normality-歸一化(GrLivArea)

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

對數變換前的效果:

執行對數變換及效果:

```python

執行相同的對數操作

train["GrLivArea"] = np.log(train["GrLivArea"])

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

Normality-歸一化(TotalBsmtSF)

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

處理之前的效果:

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

```python

增加一列資料

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函式能夠實現:

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

總結

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

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

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

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

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