0
[導(dǎo)讀]Kaggle 的房?jī)r(jià)預(yù)測(cè)競(jìng)賽從 2016 年 8 月開(kāi)始,到 2017 年 2 月結(jié)束。這段時(shí)間內(nèi),超過(guò) 2000 多人參與比賽,選手采用高級(jí)回歸技術(shù),基于我們給出的 79 個(gè)特征,對(duì)房屋的售價(jià)進(jìn)行了準(zhǔn)確的預(yù)測(cè)。今天我們介紹的是目前得票數(shù)最高的優(yōu)勝方案:《用 Python 進(jìn)行全面數(shù)據(jù)探索》,該方案在數(shù)據(jù)探索,特征工程上都有十分出色的表現(xiàn)。
作者 Pedro Marcelino 在競(jìng)賽中使用的主要方法是關(guān)注數(shù)據(jù)科學(xué)處理方法,以及尋找能夠指導(dǎo)工作的有力文獻(xiàn)資料。作者主要參考《多元數(shù)據(jù)分析》(Multivariate Data Analysis, Hair et al., 2014)中的第三章 “檢查你的數(shù)據(jù)”。作者將自己研究的方法歸為以下三步:
定義要解決的問(wèn)題;
查閱相關(guān)文獻(xiàn);
對(duì)他們進(jìn)行修改以適合自己的要求。
“不過(guò)是站在巨人的肩膀上?!薄?nbsp;Pedro Marcelino
下面我們就一起來(lái)看看作者是如何對(duì)數(shù)據(jù)進(jìn)行分析的。
了解你的數(shù)據(jù)
方法框架:
理解問(wèn)題:查看每個(gè)變量并且根據(jù)他們的意義和對(duì)問(wèn)題的重要性進(jìn)行哲學(xué)分析。
單因素研究:只關(guān)注因變量( SalePrice),并且進(jìn)行更深入的了解。
多因素研究:分析因變量和自變量之間的關(guān)系。
基礎(chǔ)清洗:清洗數(shù)據(jù)集并且對(duì)缺失數(shù)據(jù),異常值和分類(lèi)數(shù)據(jù)進(jìn)行一些處理。
檢驗(yàn)假設(shè):檢查數(shù)據(jù)是否和多元分析方法的假設(shè)達(dá)到一致。
開(kāi)始之前:
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as npfrom scipy.stats
import normfrom sklearn.preprocessing
import StandardScalerfrom scipy
import stats
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline
#bring in the six packs
df_train = pd.read_csv('../input/train.csv')
#check the decoration
df_train.columns
Index(['Id', 'MSSubClass', 'MSZoning','LotFrontage', 'LotArea', 'Street',
'Alley', 'LotShape', 'LandContour', 'Utilities','LotConfig',
'LandSlope', 'Neighborhood', 'Condition1','Condition2', 'BldgType',
'HouseStyle', 'OverallQual', 'OverallCond','YearBuilt', 'YearRemodAdd',
'RoofStyle', 'RoofMatl', 'Exterior1st','Exterior2nd', 'MasVnrType',
'MasVnrArea', 'ExterQual', 'ExterCond','Foundation', 'BsmtQual',
'BsmtCond', 'BsmtExposure', 'BsmtFinType1','BsmtFinSF1',
'BsmtFinType2', 'BsmtFinSF2', 'BsmtUnfSF','TotalBsmtSF', 'Heating',
'HeatingQC', 'CentralAir', 'Electrical', '1stFlrSF','2ndFlrSF',
'LowQualFinSF', 'GrLivArea', 'BsmtFullBath','BsmtHalfBath', 'FullBath',
'HalfBath', 'BedroomAbvGr', 'KitchenAbvGr','KitchenQual',
'TotRmsAbvGrd', 'Functional', 'Fireplaces','FireplaceQu', 'GarageType',
'GarageYrBlt', 'GarageFinish', 'GarageCars','GarageArea', 'GarageQual',
'GarageCond', 'PavedDrive', 'WoodDeckSF','OpenPorchSF',
'EnclosedPorch', '3SsnPorch', 'ScreenPorch','PoolArea', 'PoolQC',
'Fence', 'MiscFeature', 'MiscVal', 'MoSold','YrSold', 'SaleType',
'SaleCondition', 'SalePrice'],
dtype='object')
準(zhǔn)備工作——我們可以期望什么?
為了了解我們的數(shù)據(jù),我們可以分析每個(gè)變量并且嘗試?yán)斫馑麄兊囊饬x和與該問(wèn)題的相關(guān)程度。
首先建立一個(gè) Excel 電子表格,有如下目錄:
變量 – 變量名。
類(lèi)型 – 該變量的類(lèi)型。這一欄只有兩個(gè)可能值,“數(shù)據(jù)” 或 “類(lèi)別”。 “數(shù)據(jù)” 是指該變量的值是數(shù)字,“類(lèi)別” 指該變量的值是類(lèi)別標(biāo)簽。
劃分 – 指示變量劃分. 我們定義了三種劃分:建筑,空間,位置。
期望 – 我們希望該變量對(duì)房?jī)r(jià)的影響程度。我們使用類(lèi)別標(biāo)簽 “高”,“中” 和 “低” 作為可能值。
結(jié)論 – 我們得出的該變量的重要性的結(jié)論。在大概瀏覽數(shù)據(jù)之后,我們認(rèn)為這一欄和 “期望” 的值基本一致。
評(píng)論 – 我們看到的所有一般性評(píng)論。
我們首先閱讀了每一個(gè)變量的描述文件,同時(shí)思考這三個(gè)問(wèn)題:
我們買(mǎi)房子的時(shí)候會(huì)考慮這個(gè)因素嗎?
如果考慮的話(huà),這個(gè)因素的重要程度如何?
這個(gè)因素帶來(lái)的信息在其他因素中出現(xiàn)過(guò)嗎?
我們根據(jù)以上內(nèi)容填好了電子表格,并且仔細(xì)觀察了 “高期望” 的變量。然后繪制了這些變量和房?jī)r(jià)之間的散點(diǎn)圖,填在了 “結(jié)論” 那一欄,也正巧就是對(duì)我們的期望值的校正。
我們總結(jié)出了四個(gè)對(duì)該問(wèn)題起到至關(guān)重要的作用的變量:
OverallQual
YearBuilt.
TotalBsmtSF.
GrLivArea.
最重要的事情——分析 “房?jī)r(jià)”
描述性數(shù)據(jù)總結(jié):
df_train['SalePrice'].describe()
count 1460.000000
mean 180921.195890
std 79442.502883
min 34900.000000
25% 129975.000000
50% 163000.000000
75% 214000.000000
max 755000.000000
Name: SalePrice, dtype: float64
繪制直方圖
sns.distplot(df_train['SalePrice']);
從直方圖中可以看出:
偏離正態(tài)分布
數(shù)據(jù)正偏
有峰值
數(shù)據(jù)偏度和峰度度量:
print("Skewness: %f" % df_train['SalePrice'].skew())
print("Kurtosis: %f" % df_train['SalePrice'].kurt())
Skewness: 1.882876
Kurtosis: 6.536282
“房?jī)r(jià)” 的相關(guān)變量分析
與數(shù)字型變量的關(guān)系:
1. Grlivarea 與 SalePrice 散點(diǎn)圖
var = 'GrLivArea'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000));
可以看出 SalePrice 和 GrLivArea 關(guān)系很密切,并且基本呈線(xiàn)性關(guān)系。
2. TotalBsmtSF 與 SalePrice 散點(diǎn)圖
var = 'TotalBsmtSF'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000));
TotalBsmtSF 和 SalePrice 關(guān)系也很密切,從圖中可以看出基本呈指數(shù)分布,但從最左側(cè)的點(diǎn)可以看出特定情況下 TotalBsmtSF 對(duì) SalePrice 沒(méi)有產(chǎn)生影響。
與類(lèi)別型變量的關(guān)系
1.‘OverallQual’與‘SalePrice’箱型圖
var = 'OverallQual'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
f, ax = plt.subplots(figsize=(8, 6))
fig = sns.boxplot(x=var, y="SalePrice", data=data)
fig.axis(ymin=0, ymax=800000);
可以看出 SalePrice 與 OverallQual 分布趨勢(shì)相同。
2. YearBuilt 與 SalePrice 箱型圖
var = 'YearBuilt'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
f, ax = plt.subplots(figsize=(16, 8))
fig = sns.boxplot(x=var, y="SalePrice", data=data)
fig.axis(ymin=0, ymax=800000);plt.xticks(rotation=90);
兩個(gè)變量之間的關(guān)系沒(méi)有很強(qiáng)的趨勢(shì)性,但是可以看出建筑時(shí)間較短的房屋價(jià)格更高。
總結(jié):
GrLivArea 和 TotalBsmtSF 與 SalePrice 似乎線(xiàn)性相關(guān),并且都是正相關(guān)。 對(duì)于 TotalBsmtSF 線(xiàn)性關(guān)系的斜率十分的高。
OverallQual 和 YearBuilt 與 SalePrice 也有關(guān)系。OverallQual 的相關(guān)性更強(qiáng), 箱型圖顯示了隨著整體質(zhì)量的增長(zhǎng),房?jī)r(jià)的增長(zhǎng)趨勢(shì)。
我們只分析了四個(gè)變量,但是還有許多其他變量我們也應(yīng)該分析,這里的技巧在于選擇正確的特征(特征選擇)而不是定義他們之間的復(fù)雜關(guān)系(特征工程)。
客觀分析
1. 相關(guān)系數(shù)矩陣
corrmat = df_train.corr()
f, ax = plt.subplots(figsize=(12, 9))
sns.heatmap(corrmat, vmax=.8, square=True);
首先兩個(gè)紅色的方塊吸引到了我,第一個(gè)是 TotalBsmtSF 和 1stFlrSF 變量的相關(guān)系數(shù),第二個(gè)是 GarageX 變量群。這兩個(gè)示例都顯示了這些變量之間很強(qiáng)的相關(guān)性。實(shí)際上,相關(guān)性的程度達(dá)到了一種多重共線(xiàn)性的情況。我們可以總結(jié)出這些變量幾乎包含相同的信息,所以確實(shí)出現(xiàn)了多重共線(xiàn)性。
另一個(gè)引起注意的地方是 SalePrice 的相關(guān)性。我們可以看到我們之前分析的 GrLivArea,TotalBsmtSF和 OverallQual 的相關(guān)性很強(qiáng),除此之外也有很多其他的變量應(yīng)該進(jìn)行考慮,這也是我們下一步的內(nèi)容。
2. SalePrice 相關(guān)系數(shù)矩陣
k = 10 #number ofvariables for heatmap
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
cm = np.corrcoef(df_train[cols].values.T)
sns.set(font_scale=1.25)
hm = sns.heatmap(cm, cbar=True, annot=True, square=True, fmt='.2f', annot_kws={'size': 10},
yticklabels=cols.values, xticklabels=cols.values)
plt.show()
從圖中可以看出:
OverallQual,GrLivArea 以及 TotalBsmtSF 與 SalePrice 有很強(qiáng)的相關(guān)性。
GarageCars 和 GarageArea 也是相關(guān)性比較強(qiáng)的變量. 車(chē)庫(kù)中存儲(chǔ)的車(chē)的數(shù)量是由車(chē)庫(kù)的面積決定的,它們就像雙胞胎,所以不需要專(zhuān)門(mén)區(qū)分 GarageCars 和 GarageAre,所以我們只需要其中的一個(gè)變量。這里我們選擇了 GarageCars,因?yàn)樗c SalePrice 的相關(guān)性更高一些。
TotalBsmtSF 和 1stFloor 與上述情況相同,我們選擇 TotalBsmtS 。
FullBath 幾乎不需要考慮。
TotRmsAbvGrd 和 GrLivArea 也是變量中的雙胞胎。
YearBuilt 和 SalePrice 相關(guān)性似乎不強(qiáng)。
3. SalePrice 和相關(guān)變量之間的散點(diǎn)圖
sns.set()
cols = ['SalePrice', 'OverallQual', 'GrLivArea','GarageCars', 'TotalBsmtSF', 'FullBath', 'YearBuilt']
sns.pairplot(df_train[cols], size = 2.5)
plt.show();
盡管我們已經(jīng)知道了一些主要特征,這一豐富的散點(diǎn)圖給了我們一個(gè)關(guān)于變量關(guān)系的合理想法。
其中,TotalBsmtSF 和 GrLiveArea 之間的散點(diǎn)圖是很有意思的。我們可以看出這幅圖中,一些點(diǎn)組成了線(xiàn),就像邊界一樣。大部分點(diǎn)都分布在那條線(xiàn)下面,這也是可以解釋的。地下室面積和地上居住面積可以相等,但是一般情況下不會(huì)希望有一個(gè)比地上居住面積還大的地下室。
SalePrice 和 YearBuilt 之間的散點(diǎn)圖也值得我們思考。在 “點(diǎn)云” 的底部,我們可以觀察到一個(gè)幾乎呈指數(shù)函數(shù)的分布。我們也可以看到 “點(diǎn)云” 的上端也基本呈同樣的分布趨勢(shì)。并且可以注意到,近幾年的點(diǎn)有超過(guò)這個(gè)上端的趨勢(shì)。
缺失數(shù)據(jù)
關(guān)于缺失數(shù)據(jù)需要思考的重要問(wèn)題:
這一缺失數(shù)據(jù)的普遍性如何?
缺失數(shù)據(jù)是隨機(jī)的還是有律可循?
這些問(wèn)題的答案是很重要的,因?yàn)槿笔?shù)據(jù)意味著樣本大小的縮減,這會(huì)阻止我們的分析進(jìn)程。除此之外,以實(shí)質(zhì)性的角度來(lái)說(shuō),我們需要保證對(duì)缺失數(shù)據(jù)的處理不會(huì)出現(xiàn)偏離或隱藏任何難以忽視的真相。
total= df_train.isnull().sum().sort_values(ascending=False)
percent = (df_train.isnull().sum()/df_train.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total','Percent'])
missing_data.head(20)
當(dāng)超過(guò) 15% 的數(shù)據(jù)都缺失的時(shí)候,我們應(yīng)該刪掉相關(guān)變量且假設(shè)該變量并不存在。
根據(jù)這一條,一系列變量都應(yīng)該刪掉,例如 PoolQC,MiscFeature,Alley 等等,這些變量都不是很重要,因?yàn)樗麄兓径疾皇俏覀冑I(mǎi)房子時(shí)會(huì)考慮的因素。
GarageX 變量群的缺失數(shù)據(jù)量都相同,由于關(guān)于車(chē)庫(kù)的最重要的信息都可以由 GarageCars 表達(dá),并且這些數(shù)據(jù)只占缺失數(shù)據(jù)的 5%,我們也會(huì)刪除上述的 GarageX 變量群。同樣的邏輯也適用于 BsmtX 變量群。
對(duì)于 MasVnrArea 和 MasVnrType,我們可以認(rèn)為這些因素并不重要。除此之外,他們和 YearBuilt 以及 OverallQual 都有很強(qiáng)的關(guān)聯(lián)性,而這兩個(gè)變量我們已經(jīng)考慮過(guò)了。所以刪除 MasVnrArea 和 MasVnrType 并不會(huì)丟失信息。
最后,由于 Electrical 中只有一個(gè)損失的觀察值,所以我們刪除這個(gè)觀察值,但是保留這一變量。
df_train= df_train.drop((missing_data[missing_data['Total'] > 1]).index,1)
df_train= df_train.drop(df_train.loc[df_train['Electrical'].isnull()].index)
df_train.isnull().sum().max() #justchecking that there's no missing data missing...
異常值
單因素分析
這里的關(guān)鍵在于如何建立閾值,定義一個(gè)觀察值為異常值。我們對(duì)數(shù)據(jù)進(jìn)行正態(tài)化,意味著把數(shù)據(jù)值轉(zhuǎn)換成均值為 0,方差為 1 的數(shù)據(jù)。
saleprice_scaled= StandardScaler().fit_transform(df_train['SalePrice'][:,np.newaxis]);
low_range = saleprice_scaled[saleprice_scaled[:,0].argsort()][:10]
high_range= saleprice_scaled[saleprice_scaled[:,0].argsort()][-10:]
print('outer range (low) of the distribution:')
print(low_range)
print('\nouter range (high) of thedistribution:')
print(high_range)
進(jìn)行正態(tài)化后,可以看出:
低范圍的值都比較相似并且在 0 附近分布。
高范圍的值離 0 很遠(yuǎn),并且七點(diǎn)幾的值遠(yuǎn)在正常范圍之外。
雙變量分析
1. GrLivArea 和 SalePrice 雙變量分析
var = 'GrLivArea'
data = pd.concat([df_train['SalePrice'], df_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice', ylim=(0,800000));
從圖中可以看出:
有兩個(gè)離群的 GrLivArea 值很高的數(shù)據(jù),我們可以推測(cè)出現(xiàn)這種情況的原因?;蛟S他們代表了農(nóng)業(yè)地區(qū),也就解釋了低價(jià)。 這兩個(gè)點(diǎn)很明顯不能代表典型樣例,所以我們將它們定義為異常值并刪除。
圖中頂部的兩個(gè)點(diǎn)是七點(diǎn)幾的觀測(cè)值,他們雖然看起來(lái)像特殊情況,但是他們依然符合整體趨勢(shì),所以我們將其保留下來(lái)。
刪除點(diǎn)
df_train.sort_values(by = 'GrLivArea',ascending = False)[:2]
df_train = df_train.drop(df_train[df_train['Id'] == 1299].index)
df_train = df_train.drop(df_train[df_train['Id'] == 524].index)
2. TotalBsmtSF 和 SalePrice 雙變量分析
var = 'TotalBsmtSF'
data = pd.concat([df_train['SalePrice'],df_train[var]], axis=1)
data.plot.scatter(x=var, y='SalePrice',ylim=(0,800000));
核心部分
“房?jī)r(jià)” 到底是誰(shuí)?
這個(gè)問(wèn)題的答案,需要我們驗(yàn)證根據(jù)數(shù)據(jù)基礎(chǔ)進(jìn)行多元分析的假設(shè)。
我們已經(jīng)進(jìn)行了數(shù)據(jù)清洗,并且發(fā)現(xiàn)了 SalePrice 的很多信息,現(xiàn)在我們要更進(jìn)一步理解 SalePrice 如何遵循統(tǒng)計(jì)假設(shè),可以讓我們應(yīng)用多元技術(shù)。
應(yīng)該測(cè)量 4 個(gè)假設(shè)量:
正態(tài)性
同方差性
線(xiàn)性
相關(guān)錯(cuò)誤缺失
正態(tài)性:
應(yīng)主要關(guān)注以下兩點(diǎn):
直方圖 – 峰度和偏度。
正態(tài)概率圖 – 數(shù)據(jù)分布應(yīng)緊密跟隨代表正態(tài)分布的對(duì)角線(xiàn)。
1. SalePrice
繪制直方圖和正態(tài)概率圖:
sns.distplot(df_train['SalePrice'], fit=norm);
fig = plt.figure()
res = stats.probplot(df_train['SalePrice'], plot=plt)
可以看出,房?jī)r(jià)分布不是正態(tài)的,顯示了峰值,正偏度,但是并不跟隨對(duì)角線(xiàn)。
可以用對(duì)數(shù)變換來(lái)解決這個(gè)問(wèn)題
進(jìn)行對(duì)數(shù)變換:
df_train['SalePrice']= np.log(df_train['SalePrice'])
繪制變換后的直方圖和正態(tài)概率圖:
sns.distplot(df_train['SalePrice'], fit=norm);
fig = plt.figure()
res = stats.probplot(df_train['SalePrice'], plot=plt)
2. GrLivArea
繪制直方圖和正態(tài)概率曲線(xiàn)圖:
sns.distplot(df_train['GrLivArea'], fit=norm);
fig = plt.figure()
res = stats.probplot(df_train['GrLivArea'], plot=plt)
進(jìn)行對(duì)數(shù)變換:
df_train['GrLivArea']= np.log(df_train['GrLivArea'])
繪制變換后的直方圖和正態(tài)概率圖:
sns.distplot(df_train['GrLivArea'], fit=norm);
fig = plt.figure()
res = stats.probplot(df_train['GrLivArea'], plot=plt)
3. TotalBsmtSF
繪制直方圖和正態(tài)概率曲線(xiàn)圖:
sns.distplot(df_train['TotalBsmtSF'],fit=norm);
fig = plt.figure()
res = stats.probplot(df_train['TotalBsmtSF'],plot=plt)
從圖中可以看出:
顯示出了偏度
大量為 0 的觀察值(沒(méi)有地下室的房屋)
含 0 的數(shù)據(jù)無(wú)法進(jìn)行對(duì)數(shù)變換
我們建立了一個(gè)變量,可以得到有沒(méi)有地下室的影響值(二值變量),我們選擇忽略零值,只對(duì)非零值進(jìn)行對(duì)數(shù)變換。這樣我們既可以變換數(shù)據(jù),也不會(huì)損失有沒(méi)有地下室的影響。
df_train['HasBsmt']= pd.Series(len(df_train['TotalBsmtSF']), index=df_train.index)
df_train['HasBsmt'] = 0
df_train.loc[df_train['TotalBsmtSF']>0,'HasBsmt'] = 1
進(jìn)行對(duì)數(shù)變換:
df_train['TotalBsmtSF']= np.log(df_train['TotalBsmtSF'])
繪制變換后的直方圖和正態(tài)概率圖:
sns.distplot(df_train['TotalBsmtSF'], fit=norm);
fig = plt.figure()
res = stats.probplot(df_train['TotalBsmtSF'], plot=plt)
同方差性:
最好的測(cè)量?jī)蓚€(gè)變量的同方差性的方法就是圖像。
1. SalePrice 和 GrLivArea 同方差性
繪制散點(diǎn)圖:
plt.scatter(df_train['GrLivArea'],df_train['SalePrice']);
2. SalePrice with TotalBsmtSF 同方差性
繪制散點(diǎn)圖:
plt.scatter(df_train[df_train['TotalBsmtSF']>0]['TotalBsmtSF'], df_train[df_train['TotalBsmtSF']>0]['SalePrice']);
可以看出 SalePrice 在整個(gè) TotalBsmtSF 變量范圍內(nèi)顯示出了同等級(jí)別的變化。
虛擬變量
將類(lèi)別變量轉(zhuǎn)換為虛擬變量:
df_train = pd.get_dummies(df_train)
結(jié)論
整個(gè)方案中,我們使用了很多《多元數(shù)據(jù)分析》中提出的方法。我們對(duì)變量進(jìn)行了哲學(xué)分析,不僅對(duì) SalePrice 進(jìn)行了單獨(dú)分析,還結(jié)合了相關(guān)程度最高的變量進(jìn)行分析。我們處理了缺失數(shù)據(jù)和異常值,我們驗(yàn)證了一些基礎(chǔ)統(tǒng)計(jì)假設(shè),并且將類(lèi)別變量轉(zhuǎn)換為虛擬變量。
但問(wèn)題還沒(méi)有結(jié)束,我們還需要預(yù)測(cè)房?jī)r(jià)的變化趨勢(shì),房?jī)r(jià)預(yù)測(cè)是否適合線(xiàn)性回歸正則化的方法?是否適合組合方法?或者一些其他的方法?
希望你可以進(jìn)行自己的探索發(fā)現(xiàn)。
雷鋒網(wǎng)按:本文原載于36大數(shù)據(jù)。
雷峰網(wǎng)版權(quán)文章,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見(jiàn)轉(zhuǎn)載須知。