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入门之预测房价。完整代码阅读原文。

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