關於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, 則需要進行分佈變換。
具體可參考特徵工程的特徵分佈
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()
可以按照線性相關性對於部分項目進行剔除
數據清洗預處理及特徵工程
數據清洗包括檢查數據一致性,尋找異常值處理缺失值,而特徵工程是指對數據特徵值做進一步的提取處理。
特徵工程決定了機器學習模型的上限,因爲本篇是入門級只做了最基礎的量綱消除特徵工程,也就決定了這個模型的上限不會很高
尋找異常值:
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)