先給出本次參賽的地址House Prices: Advanced Regression Techniques
這是一個非常經典機器學習題目,給出衆多與房價相關的特徵,根據這些數據特徵來預測房價。
理解問題與數據
首先當然是導入數據了,建議此類數據分析使用anaconda來完成,會非常方便高效。
1import seaborn as sns 2import matplotlib.pyplot as plt 3import pandas as pd 4import numpy as np 5from sklearn.model_selection import cross_val_score 6from sklearn import linear_model 7from sklearn import metrics 8 9train = pd.read_csv('/Machine-Learning/all/train.csv') 10test = pd.read_csv('/Machine-Learning/all/test.csv')
先整體查看下數據
1sns.distplot(train['SalePrice'])
1train['SalePrice'].describe()
1count 1460.000000 2mean 180921.195890 3std 79442.502883 4min 34900.000000 525% 129975.000000 650% 163000.000000 775% 214000.000000 8max 755000.000000 9Name: SalePrice, dtype: float64
1#skewness and kurtosis 2print("偏度: %f" % train['SalePrice'].skew()) 3print("峯度: %f" % train['SalePrice'].kurt())
1偏度: 1.882876 2峯度: 6.536282
偏度能夠反應分佈的對稱情況,右偏(也叫正偏),在圖像上表現爲數據右邊脫了一個長長的尾巴,這時大多數值分佈在左側,有一小部分值分佈在右側。
峯度反應的是圖像的尖銳程度:峯度越大,表現在圖像上面是中心點越尖銳。在相同方差的情況下,中間一大部分的值方差都很小,爲了達到和正太分佈方差相同的目的,必須有一些值離中心點越遠,所以這就是所說的“厚尾”,反應的是異常點增多這一現象。
查看熱圖
1data = train.corr() 2sns.heatmap(data)
越是白色越是關聯緊密。可以觀察SalePrice跟哪些屬性關聯更緊密。
直接查看
熱力圖顯示有很多時候顯示不全,尤其屬性特別多的時候。這個時候,可能直接查看更方便
1data['SalePrice'].sort_values()
1KitchenAbvGr -0.135907 2EnclosedPorch -0.128578 3MSSubClass -0.084284 4OverallCond -0.077856 5YrSold -0.028923 6LowQualFinSF -0.025606 7Id -0.021917 8MiscVal -0.021190 9BsmtHalfBath -0.016844 10BsmtFinSF2 -0.011378 113SsnPorch 0.044584 12MoSold 0.046432 13PoolArea 0.092404 14ScreenPorch 0.111447 15BedroomAbvGr 0.168213 16BsmtUnfSF 0.214479 17BsmtFullBath 0.227122 18LotArea 0.263843 19HalfBath 0.284108 20OpenPorchSF 0.315856 212ndFlrSF 0.319334 22WoodDeckSF 0.324413 23LotFrontage 0.351799 24BsmtFinSF1 0.386420 25Fireplaces 0.466929 26MasVnrArea 0.477493 27GarageYrBlt 0.486362 28YearRemodAdd 0.507101 29YearBuilt 0.522897 30TotRmsAbvGrd 0.533723 31FullBath 0.560664 321stFlrSF 0.605852 33TotalBsmtSF 0.613581 34GarageArea 0.623431 35GarageCars 0.640409 36GrLivArea 0.708624 37OverallQual 0.790982 38SalePrice 1.000000 39Name: SalePrice, dtype: float64
可以看到有不少值是負的,還有很多值低於0.2,我們可以直接把這些feature從我們的模型裏面去掉。
數據處理
處理異常數據
1sns.lmplot(x='GrLivArea', y='SalePrice', data=train, fit_reg=False, scatter=True)
可以看到有兩個面積特別大的房子,售價卻很低。故我們在訓練數據中刪除這兩個數據。
1train = train[-((train.SalePrice < 200000) & (train.GrLivArea > 4000))]
缺失數據的處理
查看缺失數據
1for col in train.columns: 2 if train[col].isnull().sum() > 0: 3 print(col, train[col].isnull().sum())
1LotFrontage 259 2Alley 1367 3MasVnrType 8 4MasVnrArea 8 5BsmtQual 37 6BsmtCond 37 7BsmtExposure 38 8BsmtFinType1 37 9BsmtFinType2 38 10Electrical 1 11FireplaceQu 690 12GarageType 81 13GarageYrBlt 81 14GarageFinish 81 15GarageQual 81 16GarageCond 81 17PoolQC 1452 18Fence 1177 19MiscFeature 1404
處理缺失數據
1#一半是刪除過多空值的屬性,一半是刪除無關聯的屬性 2train = train.drop(["MiscFeature", "Id", "PoolQC", "Alley", "Fence","GarageFinish", "KitchenAbvGr", "EnclosedPorch", "MSSubClass", "OverallCond", "YrSold", "LowQualFinSF", "MiscVal", "BsmtHalfBath", "BsmtFinSF2", "3SsnPorch", "MoSold", "PoolArea"], axis=1) 3 4test = test.drop(["MiscFeature", "PoolQC", "Alley", "Fence","GarageFinish", "KitchenAbvGr", "EnclosedPorch", "MSSubClass", "OverallCond", "YrSold", "LowQualFinSF", "MiscVal", "BsmtHalfBath", "BsmtFinSF2", "3SsnPorch", "MoSold", "PoolArea"], axis=1) 5 6#彙總train和test的數據 7all_data = pd.concat((train, test)) 8#如果數字,填寫均值。如果字符串,填寫次數最多的 9for col in train.columns: 10 if train[col].isnull().sum() > 0: 11 if train[col].dtypes == 'object': 12 val = all_data[col].dropna().value_counts().idxmax() 13 train[col] = train[col].fillna(val) 14 else: 15 val = all_data[col].dropna().mean() 16 train[col] = train[col].fillna(val) 17 18for col in test.columns: 19 if test[col].isnull().sum() > 0: 20 if test[col].dtypes == 'object': 21 val = all_data[col].dropna().value_counts().idxmax() 22 test[col] = test[col].fillna(val) 23 else: 24 val = all_data[col].dropna().mean() 25 test[col] = test[col].fillna(val)
轉非數
對非數字的屬性進行轉換。這裏我使用最簡單粗暴的get_dummies()來對train數據和test數據進行轉換。這裏也有個地方要注意:test數據裏面屬性的取值範圍可能跟train數據裏面屬性的取值範圍部分不同。這樣如果直接對test數據和train數據做get_dummies,很可能會導致test和train數據轉化後出現了不同的列。所以需要綜合處理。
1#綜合處理,轉值類型 2for col in all_data.select_dtypes(include = [object]).columns: 3 train[col] = train[col].astype('category', categories = all_data[col].dropna().unique()) 4 test[col] = test[col].astype('category', categories = all_data[col].dropna().unique()) 5 6for col in train.columns: 7 if train[col].dtype.name == 'category': 8 tmp = pd.get_dummies(train[col], prefix = col) 9 train = train.join(tmp) 10 train = train.drop(col, axis=1) 11 12for col in test.columns: 13 if test[col].dtype.name == 'category': 14 tmp = pd.get_dummies(test[col], prefix = col) 15 test = test.join(tmp) 16 test = test.drop(col, axis=1)
建模&&預測
1lr = linear_model.LinearRegression() 2X = train.drop("SalePrice", axis=1) 3y = np.log(train["SalePrice"]) 4 5lr = lr.fit(X, y) 6results = lr.predict(test.drop("Id", axis = 1)) 7final = np.exp(results) 8 9submission = pd.DataFrame() 10submission['Id'] = test.Id 11submission['SalePrice'] = final 12 13submission.head()
1Id SalePrice 20 1461 121738.894467 31 1462 160600.237304 42 1463 186313.100909 53 1464 197581.617513 64 1465 198611.414415
1submission.to_csv("submission1.csv", index= False)
大功告成!
總結
重新回顧,用到了哪些知識?
首先當然是pandas和seaborn的使用,一個用來處理數據,這部分通常會花費很多時間,一個用來可視化,用圖來代替數據,直觀明瞭;處理完數據後直接使用sklearn.linear_model.LinearRegression進行線性迴歸,看看簡單例子
1>>> from sklearn import linear_model 2>>> clf = linear_model.LinearRegression() 3>>> X = [[0,0],[1,1],[2,2]] 4>>> y = [0,1,2] 5>>> clf.fit(X,y) 6>>> clf.coef_ 7[ 0.5 0.5] 8>>> clf.intercept_ 91.11022302463e-16
第一次參加Kaggle,最終名次是 2316,提交過一次。還需要好好看看別人的辦法,可以在Kernels下找到好多,基本上都是英文的,不過也有兩個中文的,看着很親切了。這裏是我寫的不走,有空來看看 Kaggle入門之預測房價。完整代碼閱讀原文。