Bootstrap

kaggle--House Price(房价预测)--线性回归模型

关于kaggle–House Price(房价预测)的入门级解答
本文只涉及入门级的完成,所以对于数据的处理和模型较为粗略,并不涉及详细优化,所以kaggle的提交测试了一下应该是处于中间水平,后续优化请按照个人参考修改。

数据集的读取与导入

import numpy as np
import pandas as pd
train = pd.read_csv("路径/train.csv")
test = pd.read_csv("路径/test.csv")

探索性可视化(ExploratoryVisualization)

查看分布:
首先查看预测值分布如何,在此处预测值为‘’SalePrice‘’

import seaborn as sns
sns.distplot(train["SalePrice"])  
plt.show()

观察发现图像不服从标准的正态分布,一般希望特征分布最好符合正态分布。是否符合则是检测数据的偏度skewness。如果skew()值大于0.75, 则需要进行分布变换。

具体可参考特征工程的特征分布

1

 train["SalePrice"].skew()
 1.8828757597682129

这里skewness明显大于0.75,是显著的左偏分布,故使用对数进行变换:

y = np.log(train["SalePrice"])

查看各个指标与目标值的关联程度:
各个数值属性与Y值的关联程度,去除关联程度非常低的属性
corr()返回相关系数矩阵,绝对值越接近1,线性相关越强烈

data = train.corr()
sns.heatmap(data)
plt.show()

在这里插入图片描述
热力图如果显示的不明显,尤其属性特别多的时候,可以选择直接查看。

data = train.corr()
data["SalePrice"].sort_values()

1
可以按照线性相关性对于部分项目进行剔除

数据清洗预处理及特征工程

数据清洗包括检查数据一致性,寻找异常值处理缺失值,而特征工程是指对数据特征值做进一步的提取处理。
特征工程决定了机器学习模型的上限,因为本篇是入门级只做了最基础的量纲消除特征工程,也就决定了这个模型的上限不会很高

寻找异常值:

sns.lmplot(x="GrLivArea", y="SalePrice", 
data=train,fit_reg=False,scatter=True)
plt.show()

在这里插入图片描述
根据异常值删除数据:

train = train[-((train.SalePrice < 200000) &  (train.GrLivArea > 4000))]

填补缺失值:
看各属性里面的空值情况,根据该属性的分布,对空值进行处理。在竞赛中提供了说明文档,用以说明各个属性代表的信息,例如泳池质量代表有无,此处可以用None值填充,而关于面积等则用0填充,对于像LotFrontage这样的特殊属性,是与LotAreaCut和Neighborhood有比较大的关系,所以这里可以用这两个属性分组后的中位数进行插补。
查看训练集下的属性空值个数:

aa = train.isnull().sum()
aa[aa>0].sort_values(ascending=False)

在这里插入图片描述
因为本例中的属性很多,以上填充都是较为繁琐的填充方法,所以我们采取一种更直接的方法(但会影响精确度)
这里有个地方需要注意:不止train的数据里面有空值,test数据里面也会有空值。而且可能分布在不同属性里面。所以,需要一开始对train和test的数据进行汇总,根据二者的总体分布来处理空值。
如果某个属性空值过多,直接从数据中删除该属性。
如果空值占比不大,如果是数字类型,就填写均值。如果是字符串类型,就填写出现次数最多的字符串。

#一半是删除过多空值的属性,一半是删除无关联的属性 
 train = train.drop(["MiscFeature", "Id", "PoolQC", "Alley", "Fence","GarageFinish", "KitchenAbvGr", "EnclosedPorch", "MSSubClass", "OverallCond", "YrSold", "LowQualFinSF", "MiscVal", "BsmtHalfBath", "BsmtFinSF2", "3SsnPorch", "MoSold", "PoolArea"], axis=1)

 test = test.drop(["MiscFeature", "PoolQC", "Alley", "Fence","GarageFinish", "KitchenAbvGr", "EnclosedPorch", "MSSubClass", "OverallCond", "YrSold", "LowQualFinSF", "MiscVal", "BsmtHalfBath", "BsmtFinSF2", "3SsnPorch", "MoSold", "PoolArea"], axis=1)

#汇总train和test的数据
all_data = pd.concat((train, test))
#如果数字,填写均值。如果字符串,填写次数最多的
for col in train.columns:
    if train[col].isnull().sum() > 0:
        if train[col].dtypes == 'object':
            val = all_data[col].dropna().value_counts().idxmax()
            train[col] = train[col].fillna(val)
        else:
            val = all_data[col].dropna().mean()
            train[col] = train[col].fillna(val)
for col in test.columns:
     if test[col].isnull().sum() > 0:
         if test[col].dtypes == 'object':
             val = all_data[col].dropna().value_counts().idxmax()
             test[col] = test[col].fillna(val)
         else:
             val = all_data[col].dropna().mean()
             test[col] = test[col].fillna(val)

特征工程无量纲化:
因为不同属性的量纲不同,人的性别有男女,祖国有中国,美国,法国等。
这些特征值并不是连续的,而是离散的,无序的。通常我们需要对其进行特征数字化。
这里使用get_dummies()来对train数据和test数据进行转换。有个地方要注意:test数据里面属性的取值范围可能跟train数据里面属性的取值范围部分不同。这样如果直接对test数据和train数据做get_dummies,很可能会导致test和train数据转化后出现了不同的列。所以需要综合处理。

#综合处理,转值类型
for col in all_data.select_dtypes(include = [object]).columns:
      train[col] = train[col].astype('category', categories = all_data[col].dropna().unique())
      test[col] = test[col].astype('category', categories = all_data[col].dropna().unique())

for col in train.columns:
      if train[col].dtype.name == 'category':
         tmp = pd.get_dummies(train[col], prefix = col)
         train = train.join(tmp)
         train = train.drop(col, axis=1)

for col in test.columns:
      if test[col].dtype.name == 'category':
           tmp = pd.get_dummies(test[col], prefix = col)
           test = test.join(tmp)
           test = test.drop(col, axis=1)

建立线性回归模型&交叉验证

使用linear_model.LinearRegression建立线性回归模型
linear_model.LinearRegression()线性回归实例:
https://www.cnblogs.com/FYZHANG/p/12030202.html
使用cross_val_score进行交叉验证
cross_val_score讲解:
https://blog.csdn.net/qq_36523839/article/details/80707678

from sklearn.model_selection import cross_val_score
from sklearn import linear_model
from sklearn import metrics    
lr = linear_model.LinearRegression()
X = train.drop("SalePrice", axis=1)
y = np.log(train["SalePrice"])
score = cross_val_score(lr, X,y, scoring='mean_squared_error')
print (score)

预测并提交结果

lr = lr.fit(X, y)
results = lr.predict(test.drop("Id", axis = 1))
final = np.exp(results)
   
   
submission = pd.DataFrame()
submission['Id'] = test.Id
submission['SalePrice'] = final
submission.to_csv("路径/submission.csv", index= False)

附录:全代码

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

train = pd.read_csv("路径/train.csv")
test = pd.read_csv("路径/test.csv")
#plt.figure(figsize=(15,8))
#sns.boxplot(train.YearBuilt, train.SalePrice)


#一半是删除过多空值的属性,一半是删除无关联的属性 
train = train.drop(["MiscFeature", "Id", "PoolQC", "Alley", "Fence","GarageFinish", "KitchenAbvGr", "EnclosedPorch", "MSSubClass", "OverallCond", "YrSold", "LowQualFinSF", "MiscVal", "BsmtHalfBath", "BsmtFinSF2", "3SsnPorch", "MoSold", "PoolArea"], axis=1)

test = test.drop(["MiscFeature", "PoolQC", "Alley", "Fence","GarageFinish", "KitchenAbvGr", "EnclosedPorch", "MSSubClass", "OverallCond", "YrSold", "LowQualFinSF", "MiscVal", "BsmtHalfBath", "BsmtFinSF2", "3SsnPorch", "MoSold", "PoolArea"], axis=1)

#汇总train和test的数据
all_data = pd.concat((train, test))

#汇总train和test的数据
all_data = pd.concat((train, test))
#如果数字,填写均值。如果字符串,填写次数最多的
for col in train.columns:
    if train[col].isnull().sum() > 0:
        if train[col].dtypes == 'object':
            val = all_data[col].dropna().value_counts().idxmax()
            train[col] = train[col].fillna(val)
        else:
            val = all_data[col].dropna().mean()
            train[col] = train[col].fillna(val)
for col in test.columns:
     if test[col].isnull().sum() > 0:
         if test[col].dtypes == 'object':
             val = all_data[col].dropna().value_counts().idxmax()
             test[col] = test[col].fillna(val)
         else:
             val = all_data[col].dropna().mean()
             test[col] = test[col].fillna(val)
             
             
             
#综合处理,转值类型
for col in all_data.select_dtypes(include = [object]).columns:
      train[col] = train[col].astype('category', categories = all_data[col].dropna().unique())
      test[col] = test[col].astype('category', categories = all_data[col].dropna().unique())

for col in train.columns:
      if train[col].dtype.name == 'category':
         tmp = pd.get_dummies(train[col], prefix = col)
         train = train.join(tmp)
         train = train.drop(col, axis=1)

for col in test.columns:
      if test[col].dtype.name == 'category':
           tmp = pd.get_dummies(test[col], prefix = col)
           test = test.join(tmp)
           test = test.drop(col, axis=1)
           
from sklearn.model_selection import cross_val_score
from sklearn import linear_model
from sklearn import metrics    
lr = linear_model.LinearRegression()
X = train.drop("SalePrice", axis=1)
y = np.log(train["SalePrice"])
score = cross_val_score(lr, X,y, scoring='mean_squared_error')
print (score)


lr = lr.fit(X, y)
results = lr.predict(test.drop("Id", axis = 1))
final = np.exp(results)
   
   
submission = pd.DataFrame()
submission['Id'] = test.Id
submission['SalePrice'] = final
submission.to_csv("路径/submission.csv", index= False)
;