Kaggle入門之預測房價

先給出本次參賽的地址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入門之預測房價。完整代碼閱讀原文。

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