露一手,用 python 分析房價!
大家好,我是 Jack~
這個是Kaggle的賽題,賽題名是:House Prices - Advanced Regression Techniques。
一個很好的學(xué)習(xí)數(shù)據(jù)分析的小比賽,在本文中你將會學(xué)習(xí)到:
單、多變量分析 相關(guān)性分析 缺失值和異常值處理 啞變量轉(zhuǎn)換

原notebook地址:
https://www.kaggle.com/pmarcelino/comprehensive-data-exploration-with-python
一、排名榜
讓我們看下排名榜,第一名真的是碾壓其他選手呀~所以,今天我們一起看看這個第一名的方案到底是多棒?

二、數(shù)據(jù)介紹
這份波士頓房價的數(shù)據(jù)集有4份數(shù)據(jù),訓(xùn)練集train+測試集test+數(shù)據(jù)集的描述description+提交模板sample

其中訓(xùn)練集有81個特征,1460條數(shù)據(jù);測試集81個特征,1459條數(shù)據(jù)。看下部分屬性介紹:


三、數(shù)據(jù)EDA
導(dǎo)入模塊和數(shù)據(jù),并進(jìn)行數(shù)據(jù)探索:
導(dǎo)入庫
import?pandas?as?pd
import?numpy?as?np
#?繪圖相關(guān)
import?plotly.express?as?px
import?matplotlib.pyplot?as?plt
import?seaborn?as?sns
plt.style.use("fivethirtyeight")
#?數(shù)據(jù)建模
from?scipy.stats?import?norm
from?scipy?import?stats
from?sklearn.preprocessing?import?StandardScaler
#?警告
import?warnings
warnings.filterwarnings('ignore')
%matplotlib?inline
導(dǎo)入數(shù)據(jù)

數(shù)據(jù)信息
訓(xùn)練集整體是1460*81;而且很多的存在字段都存在缺失值

描述統(tǒng)計信息:

四、銷售價格SalePrice分析
原notebook文檔中,作者分析了很多自己關(guān)于這個題目和字段的看法,具體不闡述。下面介紹的是重點部分:
統(tǒng)計信息
單單看這個字段的統(tǒng)計信息:

分布直方圖如下,我們明顯感受到:
價格的分布偏離了正態(tài)分布 有明顯的正偏度現(xiàn)象 有明顯的峰值出現(xiàn)

偏度和峰度(skewness and kurtosis)
知識加油站:偏度和峰度
詳細(xì)的解釋參見文章:https://zhuanlan.zhihu.com/p/53184516
偏度:衡量隨機(jī)變臉概率分布的不對稱性,是相對于平均值不對稱程度的度量,通過對偏度系數(shù)的測量,我們能夠判定數(shù)據(jù)分布的不對稱程度以及方向。 峰度:是研究數(shù)據(jù)分布陡峭或者平滑的統(tǒng)計量,通過對峰度系數(shù)的測量,我們能夠判定數(shù)據(jù)相對于正態(tài)分布而言是更陡峭還是更平緩。峰度接近0,數(shù)據(jù)呈現(xiàn)正態(tài)分布;峰度>0,高尖分布;峰度<0,矮胖分布
偏度的兩種分布情況:
如果是左偏,則偏度小于0 如果是右偏,則偏度大于0

峰度的兩種分布情況:
如果是高瘦型,則峰度大于0 如果是矮胖型,則峰度小于0

#?打印銷售價格的偏度和峰度
print("Skewness(偏度):?%f"?%?train['SalePrice'].skew())
print("Kurtosis(峰度):?%f"?%?train['SalePrice'].kurt())
Skewness(偏度):?1.882876
Kurtosis(峰度):?6.536282
偏度和峰度值都是正的,明顯說明數(shù)據(jù)是右偏且高尖分布
SalePrice和數(shù)值型字段的關(guān)系
首先我們考察和居住面積的關(guān)系:

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

小結(jié):我們可以觀察到這兩個特征和銷售價格之間是存在一定的線性關(guān)系。
價格和分類型字段的關(guān)系
1、OverallQual VS SalePrice
# 1、OverallQual:整體房屋質(zhì)量
#?總共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"]]
#?房屋整體質(zhì)量和房價的關(guān)系
#?繪制子圖: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
住宅建造年份和銷售價格的關(guān)系
data?=?train[["SalePrice","YearBuilt"]]
#?建造年份和房價的關(guān)系
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()

小結(jié):銷售價格和住宅的整體質(zhì)量有很強(qiáng)的關(guān)系;但是和建筑年份的關(guān)系不大。但是在實際的買房過程中,我們還是會很在意年份
小結(jié)
對上面分析的一點小結(jié):
地面生活區(qū)(GrLivArea)、地下室面積(GrLivArea)和銷售價格SalePrice都是呈現(xiàn)正向的線性相關(guān) 房屋的整體質(zhì)量(OverallQual)和建造年份(YearBuilt)好像也和銷售價格線性相關(guān)。常識來說,整體的質(zhì)量越好,價格越貴
五、相關(guān)性分析
為了探索眾多屬性之間的關(guān)系,進(jìn)行如下的分析:
兩兩屬性間的相關(guān)性(熱力圖) 銷售價格saleprice和其他屬性的關(guān)系(熱力圖) 關(guān)聯(lián)性最大的屬性間的關(guān)系(散點圖)
整體相關(guān)性
分析每兩個屬性的相關(guān)性,并繪制熱力圖


上圖中有兩個值得關(guān)注的點:
TotalBsmtSF and 1stFlrSF GarageCar and GarageArea
這兩組變量都是強(qiáng)相關(guān)的,我們后續(xù)的分析只取其中一個
縮放相關(guān)矩陣(銷售價格saleprice)
從上面的熱力圖中選擇和SalePrice相關(guān)性最強(qiáng)的前10個特征來繪制熱力圖


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

小結(jié)1
通過上面的縮放熱力圖,我們可以得到下面的結(jié)論:
'OverallQual', 'GrLivArea' and 'TotalBsmtSF'是真的和'SalePrice'呈現(xiàn)強(qiáng)相關(guān) 'GarageCars' and 'GarageArea' 也是兩個相關(guān)性比較強(qiáng)的特征;而且他們都是同時出現(xiàn),后續(xù)選取GarageCars進(jìn)行分析 建筑年限'YearBuilt'相對來說,相關(guān)性比較低
變量離散圖
將銷售價格SalePrice和幾個相關(guān)性比較強(qiáng)的特征放在一起,繪制變量離散圖
sns.set()
#?待分析的變量
cols?=?['SalePrice',?'OverallQual',?'GrLivArea',?'GarageCars',?'TotalBsmtSF',?'FullBath',?'YearBuilt']
sns.pairplot(train[cols],size=2.5)
plt.show()

小結(jié)2
正對角線方向上是變量的直方圖,解釋變量和被解釋變量SalePrice,其他的則是散點圖。
如果圖中呈現(xiàn)直線或者橫線的散點,則說明該變量是離散的,比如第1行4列的變量,y軸是SalePrice,x軸是YearBuilt,直線說明YearBuilt是離散的
六、缺失值處理
針對缺失值的情況,主要是討論兩點:
缺失值分布情況怎么樣? 缺失值是隨機(jī)的?還有具有某種規(guī)律
缺失值占比
1、查看每個字段的缺失值情況
#?每個字段的缺失值數(shù)量:降序
total?=?train.isnull().sum().sort_values(ascending=False)
total.head()
PoolQC?????????1453
MiscFeature????1406
Alley??????????1369
Fence??????????1179
FireplaceQu?????690
dtype:?int64
2、轉(zhuǎn)成百分比
#?每個字段的缺失值?/?總數(shù)
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、數(shù)據(jù)合并,整體的缺失值情況:

刪除缺失值
原文中分析了很多,最后的結(jié)論:
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
查找離群點
##?數(shù)據(jù)標(biāo)準(zhǔn)化standardizing?data
#?np.newaxis?增加數(shù)據(jù)維度,一維變成二維
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位的數(shù)據(jù)
# argsort:返回的是索引值;默認(rèn)是升序排列,最小的在最前面,最大的在最后
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)

小結(jié)3
low_range接近,且離0比較近 high_range離0很遠(yuǎn);且7+的數(shù)據(jù)就應(yīng)該是離群點了
單變量分析1
data?=?train[["SalePrice","GrLivArea"]]
data.plot.scatter(x="GrLivArea",y="SalePrice",ylim=(0,800000))
plt.show()

很明顯的,兩個變量(屬性)存在一種線性關(guān)系
刪除離群點
指定刪除某個字段為具體值的方法:

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

八、深入理解SalePrice
主要從以下幾個方面來深入研究銷售價格:
Normality:歸一化 Homoscedasticity:同方差性 Linearity:線性特質(zhì) Absence of correlated errors:相關(guān)誤差
Normality歸一化(SalePrice)
sns.distplot(train["SalePrice"],fit=norm)
fig?=?plt.figure()
res?=?stats.probplot(train["SalePrice"],?plot=plt)

我們發(fā)現(xiàn):銷售價格不是正態(tài)分布的,出現(xiàn)了右偏度;同時也不遵循對數(shù)變化的規(guī)律。
為了解決這個問題:實施對數(shù)變換
##?對數(shù)變換
train["SalePrice"]?=?np.log(train["SalePrice"])
sns.distplot(train["SalePrice"],fit=norm)
fig?=?plt.figure()
res?=?stats.probplot(train["SalePrice"],?plot=plt)

實施對數(shù)變換后效果好了很多的
Normality-歸一化(GrLivArea)
sns.distplot(train["GrLivArea"],fit=norm)
fig?=?plt.figure()
res?=?stats.probplot(train["GrLivArea"],?plot=plt)
對數(shù)變換前的效果:

執(zhí)行對數(shù)變換及效果:
#?執(zhí)行相同的對數(shù)操作
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)
處理之前的效果:

如何處理上面的特殊部分?
#?增加一列數(shù)據(jù)
train['HasBsmt']?=?0
#?當(dāng)TotalBsmtSF>0?則賦值1
train.loc[train['TotalBsmtSF']>0,'HasBsmt']?=?1
#?對數(shù)轉(zhuǎn)換:等于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'之間的關(guān)系

2、討論SalePrice' 和 'TotalBsmtSF'

We can say that, in general, 'SalePrice' exhibit equal levels of variance across the range of 'TotalBsmtSF'. Cool!
從上面的兩張圖中,我們看到:銷售價格和另外兩個變量都是呈現(xiàn)一定的正向關(guān)系
十、生成啞變量
虛擬變量( Dummy Variables) 又稱虛設(shè)變量、名義變量或啞變量,用以反映質(zhì)的屬性的一個人工變量,是量化了的自變量,通常取值為0或1。
Pandas中的get_dummies函數(shù)能夠?qū)崿F(xiàn):
train?=?pd.get_dummies(train)??#?生成啞變量
train

十一、總結(jié)
至此,我們完成了以下的內(nèi)容:
整體變量間的相關(guān)性分析 重點分析了變量“SalePrice” 處理缺失值和異常值(離群點) 做了一些統(tǒng)計分析,將分類變量變成了啞變量
自己需要后續(xù)補(bǔ)充深入學(xué)習(xí)的點:
多元統(tǒng)計分析 偏度和峰度 啞變量的深入 標(biāo)準(zhǔn)化和歸一化
關(guān)于數(shù)據(jù)集的領(lǐng)取,公眾號后臺回復(fù):房價。看完整篇文章的分析過程,有什么感受呢?

推薦閱讀
?? ?女媧算法,殺瘋了?? ?這個項目,我能玩一年????從高考到程序員的成長之路
