先给出本次参赛的地址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入门之预测房价。完整代码阅读原文。