预测房价-Kaggle

版权声明:博客版权所有,转载注明出处。 https://blog.csdn.net/qq_33083551/article/details/86074714

个人对Kaggle预测房价的探讨,附思路和源代码。

受个人能力限制,存在诸多不足。

仅供参考。欢迎讨论。

目录

1:分析准备

1.1:数据对应中英文转换

1.2:阅读参考资料。

2:数据分析

3:初步尝试

4. 建模

5. git传送门

参考文献



1:分析准备

打开train文档,先熟悉数据。

先看看数据,到底什么东西:

import numpy as np
import pandas as pd

data =pd.read_csv(r'./source data/train.csv')
print(data.head())
print("----------------------------------")
print(format(data.shape))
print("----------------------------------")
print(data.info())

结果如下:

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1460 entries, 0 to 1459
Data columns (total 81 columns):
Id               1460 non-null int64
MSSubClass       1460 non-null int64
MSZoning         1460 non-null object
LotFrontage      1201 non-null float64
LotArea          1460 non-null int64
Street           1460 non-null object
Alley            91 non-null object
LotShape         1460 non-null object
LandContour      1460 non-null object
Utilities        1460 non-null object
LotConfig        1460 non-null object
LandSlope        1460 non-null object
Neighborhood     1460 non-null object
Condition1       1460 non-null object
Condition2       1460 non-null object
BldgType         1460 non-null object
HouseStyle       1460 non-null object
OverallQual      1460 non-null int64
OverallCond      1460 non-null int64
YearBuilt        1460 non-null int64
YearRemodAdd     1460 non-null int64
RoofStyle        1460 non-null object
RoofMatl         1460 non-null object
Exterior1st      1460 non-null object
Exterior2nd      1460 non-null object
MasVnrType       1452 non-null object
MasVnrArea       1452 non-null float64
ExterQual        1460 non-null object
ExterCond        1460 non-null object
Foundation       1460 non-null object
BsmtQual         1423 non-null object
BsmtCond         1423 non-null object
BsmtExposure     1422 non-null object
BsmtFinType1     1423 non-null object
BsmtFinSF1       1460 non-null int64
BsmtFinType2     1422 non-null object
BsmtFinSF2       1460 non-null int64
BsmtUnfSF        1460 non-null int64
TotalBsmtSF      1460 non-null int64
Heating          1460 non-null object
HeatingQC        1460 non-null object
CentralAir       1460 non-null object
Electrical       1459 non-null object
1stFlrSF         1460 non-null int64
2ndFlrSF         1460 non-null int64
LowQualFinSF     1460 non-null int64
GrLivArea        1460 non-null int64
BsmtFullBath     1460 non-null int64
BsmtHalfBath     1460 non-null int64
FullBath         1460 non-null int64
HalfBath         1460 non-null int64
BedroomAbvGr     1460 non-null int64
KitchenAbvGr     1460 non-null int64
KitchenQual      1460 non-null object
TotRmsAbvGrd     1460 non-null int64
Functional       1460 non-null object
Fireplaces       1460 non-null int64
FireplaceQu      770 non-null object
GarageType       1379 non-null object
GarageYrBlt      1379 non-null float64
GarageFinish     1379 non-null object
GarageCars       1460 non-null int64
GarageArea       1460 non-null int64
GarageQual       1379 non-null object
GarageCond       1379 non-null object
PavedDrive       1460 non-null object
WoodDeckSF       1460 non-null int64
OpenPorchSF      1460 non-null int64
EnclosedPorch    1460 non-null int64
3SsnPorch        1460 non-null int64
ScreenPorch      1460 non-null int64
PoolArea         1460 non-null int64
PoolQC           7 non-null object
Fence            281 non-null object
MiscFeature      54 non-null object
MiscVal          1460 non-null int64
MoSold           1460 non-null int64
YrSold           1460 non-null int64
SaleType         1460 non-null object
SaleCondition    1460 non-null object
SalePrice        1460 non-null int64
dtypes: float64(3), int64(35), object(43)
memory usage: 924.0+ KB
None

train的文档中,具有1460个样本,80个属性,而最后需要的结果只有一个:SalePrice,也就是房价。

所以第一件事,就是得进行整合和分析,看这么多属性分别都是什么,中文都是什么意思。

1.1:数据对应中英文转换

SalePrice 以美元出售的房产价格。 
MSSubClass 建筑类 
MSZoning 城市总体规划分区 
LotFrontage 连接物业的街道线 
LotArea: Lot size in square feet 方块大小
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 1型成品面积 
BsmtFinType2 第二成品区域的质量(如果存在) 
BsmtFinSF2 2型成品面积 
BsmtUnfSF 地下室面积 
TotalBsmtSF 地下室面积总计面积 
Heating 暖气方式 
HeatingQC 暖气质量与条件 
CentralAir 空调 
Electrical 电气系统 
1stFlrSF 一楼面积 
2ndFlrSF 二楼面积 
LowQualFinSF 低质量完工面积(所有楼层) 
GrLivArea 高档(地面)居住面积 
BsmtFullBath 地下室全浴室 
BsmtHalfBath 地下室半浴室 
FullBath 高档浴室 
HalfBath 半日以上洗澡浴室 
Bedroom 地下室层以上的卧室数 
Kitchen 厨房数量 
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 销售条件

把这些数据整理成Excel表格。发现很多东西看不明白。

1.2:阅读参考资料。

这么多属性,肯定不可能都用,最简单蠢的方法就是人为提取几个特征值,参考我国国情,考虑地段,面积,是否带泳池,材料等,选择十个八个属性直接进行预测。(不可取)

先看看别人是怎么进行的。

琢磨了半天,,,还是老老实实进行一步一步分析

2:数据分析

先看看需要预测的房价有什么特点,

''
train_data = pd.read_csv(r'./source data/train.csv')
test_data = pd.read_csv(r'./source data/test.csv')
#略过基本信息阶段

#ID这一栏基本没用,干扰信息,考虑是不是删了
train_ID = train_data['Id']
test_ID = test_data['Id']
#train_data.drop("Id", axis= 1, inplace= True)

#研究分析房价数据分布
print(train_data['SalePrice'].describe())
sns.set_style("whitegrid")
sns.distplot(train_data['SalePrice'])

结果如下:

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

可以看到,房价的平均值大概分布的段位,以及最高的房子,估计是别墅,也很贵。

没研究出什么关系。

GrLivArea 高档(地面)居住面积 

接下来看看这个,这个居住面积和房价肯定有关系吧,

#居住面积和房价
fig, ax =plt.subplots()
ax.scatter( x  = train_data['GrLivArea'], y = train_data['SalePrice'])
plt.ylabel('SalePrice')
plt.xlabel('GrLivArea')
plt.show()

结果如下

对应的面积越小,房价越便宜,符合我们日常的常识。

奇异点也比较少,完全可以解释,这部分数据看起来没问题。

同理,总房间数和房价应该也是正比。

其实到这会,我们可以看到,右边这个点,我完全可以把他当做干扰数据pass掉,,但是先保存着,

除此之外,新房应该比旧房子贵,这个没异议吧?我们看看数据。

emmm...大概是没问题的。

看下热力图:


corrmat = train_data.corr()
f, ax =plt.subplots()
sns.heatmap(corrmat, vmax=.8, square= True)

k=10
cols = corrmat.nlargest(k,'SalePrice')['SalePrice'].index
cm = np.corrcoef(train_data[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()

排名前三的有:住房质量,高档地面居住面积,车库容量大小。

感觉车库国人不在乎,国外的人人有车,那么问题来了。我什么时候买车????

还有一些变量之间有很强的相关性,  这意思要么2选一,要么线性组合--------这是一个思路

(就是可以降维,用A来表示B:B=0.82A+0.02)

删除多余数据

这有几个奇异点,不知道怎么处理,简单点,切了吧。


fig, ax = plt.subplots()
ax.scatter(x = train_data['GrLivArea'], y = train_data['SalePrice'])
plt.ylabel('SalePrice', fontsize=13)
plt.xlabel('GrLivArea', fontsize=13)
plt.show()

#挑除异常点
train_data = train_data.drop(train_data[train_data['GrLivArea']>4000].index)
fig, ax = plt.subplots()
ax.scatter(train_data['GrLivArea'], train_data['SalePrice'])
plt.ylabel('SalePrice')
plt.xlabel('GrLivArea')
plt.show()

其实我想把价格大于60万的也切了,会更整洁,后来思考下有点过分,那算了吧。

房价的数据不平滑,我们需要把离散的数据拟合成连续的平滑的数据。

用常用的log(x+1)

#让数据更加平滑
#log1p就是log(1+x)
train_data['SalePrice'] = np.log1p(train_data['SalePrice'])
sns.distplot(train_data['SalePrice'] )

确实平滑了,但是直接这样处理太过于粗糙。

看看还能做什么

1:拟合一下,需要导入两个库

from scipy import stats
from scipy.stats import norm,skew

#让数据更加平滑
#log1p就是log(1+x)
train_data['SalePrice'] = np.log1p(train_data['SalePrice'])
sns.distplot(train_data['SalePrice'] )

#看一下函数拟合
(mu, sigma) = norm.fit(train_data['SalePrice'])
print('\n mu ={:.2f} and sigma = {:.2f} \n' .format(mu,sigma))

#画个图,看下分布
plt.legend(['Normal dist. ($\mu=$ {:.2f} and $\sigma=$ {:.2f} )'.format(mu, sigma)],
            loc='best')
plt.ylabel('Frequency')
plt.title('SalePrice distribution')
#再话个QQ分布,不知道为啥,老外特别喜欢这个,
fig = plt.figure()
res = stats.probplot(train_data['SalePrice'], plot=plt)
plt.show()

结果为

 mu =12.02 and sigma = 0.40 

做到这一步可以开始初步的尝试了。

3:初步尝试

国际惯例,先把测试集和训练集结合在一起

#开始初步的尝试
#1.通用步骤,把test和train联合在一起。
train_data = train_data.drop(train_data[train_data['GrLivArea']>4000].index)
train= train_data.shape[0]
test = test_data.shape[0]
y_train = train_data.SalePrice.values
all_data = pd.concat((train_data, test_data)).reset_index(drop=True,)

all_data.drop(['SalePrice'], axis =1, inplace = True)

然后开始处理缺失数据,

有3种处理方式:

1:默认如果没有车库之类的,就没有车,这种硬相关的东西

2: 如果缺失值较少的,用众数弥补。

3:数据里面 比如地下室之类的,为Nan,说明没有地下室,把面积用0来填充,

符合常理(在提高里面就可以写,数据收到主观因素干扰,可以提升点。。。)


#用None补充的数据
all_data["PoolQC"] = all_data["PoolQC"].fillna("None")
all_data["MiscFeature"] = all_data["MiscFeature"].fillna("None")
all_data["Alley"] = all_data["Alley"].fillna("None")
all_data["Fence"] = all_data["Fence"].fillna("None")
all_data["FireplaceQu"] = all_data["FireplaceQu"].fillna("None")
#LotFrontage这个属性,假定为同一个街道的属性相似。

all_data["LotFrontage"] = all_data.groupby("Neighborhood")["LotFrontage"].transform(
    lambda x: x.fillna(x.median()))
#  'GarageType', 'GarageFinish', 'GarageQual' and 'GarageCond' 这几个属性的空缺,十有八九是没有
for col in ('GarageType', 'GarageFinish', 'GarageQual', 'GarageCond'):
    all_data[col] = all_data[col].fillna('None')
#有一些硬件,没有就是零,然后同一个街道默认为一样
#同时,假定没有车库就没车,(确实不合理,但是好统计)
for col in ('GarageYrBlt', 'GarageArea', 'GarageCars'):
    all_data[col] = all_data[col].fillna(0)

#'BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF','TotalBsmtSF', 'BsmtFullBath', 'BsmtHalfBath' 这些没有代表面积为0
for col in ('BsmtFinSF1', 'BsmtFinSF2', 'BsmtUnfSF','TotalBsmtSF', 'BsmtFullBath', 'BsmtHalfBath'):
    all_data[col] = all_data[col].fillna(0)

for col in ('BsmtQual', 'BsmtCond', 'BsmtExposure', 'BsmtFinType1', 'BsmtFinType2'):
    all_data[col] = all_data[col].fillna('None')

all_data["MasVnrType"] = all_data["MasVnrType"].fillna("None")
all_data["MasVnrArea"] = all_data["MasVnrArea"].fillna(0)
all_data['MSZoning'] = all_data['MSZoning'].fillna(all_data['MSZoning'].mode()[0])

#Utilities这个属性对数据的影响不大,可以将剔除出去
all_data = all_data.drop(['Utilities'], axis=1)
all_data["Functional"] = all_data["Functional"].fillna("Typ")
#接下来的数据里面,缺失值比较少,用众数来弥补
all_data['Electrical'] = all_data['Electrical'].fillna(all_data['Electrical'].mode()[0])
all_data['KitchenQual'] = all_data['KitchenQual'].fillna(all_data['KitchenQual'].mode()[0])
all_data['Exterior1st'] = all_data['Exterior1st'].fillna(all_data['Exterior1st'].mode()[0])
all_data['Exterior2nd'] = all_data['Exterior2nd'].fillna(all_data['Exterior2nd'].mode()[0])
all_data['SaleType'] = all_data['SaleType'].fillna(all_data['SaleType'].mode()[0])

all_data['MSSubClass'] = all_data['MSSubClass'].fillna("None")

4. 建模

这里直接使用sklearn库。

需要导入几个相关库文件

from sklearn.ensemble import RandomForestRegressor,GradientBoostingRegressor
import xgboost as xgb
import lightgbm as lgb
from sklearn.model_selection import KFold, cross_val_score, train_test_split
from sklearn.metrics import mean_squared_error

然后个人习惯,10次交叉验证:

#10次交叉
n_folds = 10

def rmsle_cv(model):
    kf = KFold(n_folds, shuffle=True, random_state=42).get_n_splits(train.values)
    rmse= np.sqrt(-cross_val_score(model, train.values, y_train, scoring="neg_mean_squared_error", cv = kf))
    return(rmse)

接下来就是直接使用自带的

rfc=RandomForestRegressor(n_estimators=1000)
GBoost = GradientBoostingRegressor(n_estimators=3000, learning_rate=0.05,
                                   max_depth=4, max_features='sqrt',
                                   min_samples_leaf=15, min_samples_split=10, 
                                   loss='huber', random_state =5)
model_xgb = xgb.XGBRegressor(colsample_bytree=0.4603, gamma=0.0468, 
                             learning_rate=0.05, max_depth=3, 
                             min_child_weight=1.7817, n_estimators=2200,
                             reg_alpha=0.4640, reg_lambda=0.8571,
                             subsample=0.5213, silent=1,
                             random_state =7, nthread = -1)
model_lgb = lgb.LGBMRegressor(objective='regression',num_leaves=5,
                              learning_rate=0.05, n_estimators=720,
                              max_bin = 55, bagging_fraction = 0.8,
                              bagging_freq = 5, feature_fraction = 0.2319,
                              feature_fraction_seed=9, bagging_seed=9,
                              min_data_in_leaf =6, min_sum_hessian_in_leaf = 11)

预测:

GBoost.fit(train,y_train)
GBoost_train_pred = GBoost.predict(train)
GB_pred = np.expm1(GBoost.predict(test.values))

预测的结果

生成提交文件:

sub = pd.DataFrame()
sub['Id'] = test_ID
sub['SalePrice'] = GB_pred
sub.to_csv('submission.csv',index=False)

上传结果

5. git传送门

https://github.com/PANBOHE/HousePrices

-----------------暂时到这告一段落------------

后续继续更新优化。

HPV01-11012019:陆陆续续换了4天整理出来,马马虎虎将就看吧

 

欢迎关注:

AI盼大家都博学
AI盼大家都博学

 

 

参考文献

【1】周志华,西瓜书(懂的人自然懂)

【2】廖雪峰老师的python教程

【3】Kaggle--房价预测

https://blog.csdn.net/d_i_k_y/article/details/80954546#%E4%B8%80%E8%AE%A4%E8%AF%86%E6%95%B0%E6%8D%AE

【4】Beginner Approach with XGBoost , LightGBM and EDA 

https://www.kaggle.com/nephalem98/beginner-approach-with-xgboost-lightgbm-and-eda

猜你喜欢

转载自blog.csdn.net/qq_33083551/article/details/86074714