1. 程式人生 > >利用線性迴歸模型進行kaggle房價預測

利用線性迴歸模型進行kaggle房價預測

最近剛學線性迴歸的一些基礎知識,就想利用kaggle中的一個入門級比賽 House Prices: Advanced Regression Techniques進行一下鞏固,發現建模之前的資料清洗與特徵選擇非常重要。

1. 資料清洗

1.1 匯入資料   

將train.csv與test.csv檔案匯入,放到一起直接預處理,處理完畢後再分開。

def load_file(path):    #匯入資料
    f = open(path)
    train_set = pd.read_csv(f, index_col=0)
    return train_set

train_path = "G:\practice.pycharm\house_price_predict\\train.csv"
train_set = load_file(train_path)
test_path = "G:\practice.pycharm\house_price_predict\\all\\test.csv"
all_set = pd.concat([train_set,load_file(train_path)])

可以利用shape函式得到train與all的大小,便於處理後分割

print(train_set.shape)
(1460, 80)
print(all_set.shape)
(2919, 80)

1.2 資料預處理

1.2.1 資料去重

使用drop_duplicates函式去掉重複值:

DataFrame.drop_duplicates(subset=None, keep='first', inplace=False)

這裡因為我們需要對所有列進行重複行刪除,保留第一個值即可,這裡直接使用預設引數。

all_set.drop_duplicates(keep='first',inplace=True)

shape檢視發現沒有重複值:

(2919, 80)

1.2.2 缺失值處理

na_count = all_set.shape[0]-all_set.count().sort_values()
na_rate = na_count/all_set.shape[0]
na_det = pd.concat([na_count,na_rate],axis=1,keys=['nan count','nan ratio'])
print(na_det.head(36))
              nan count  nan ratio
PoolQC             2909   0.996574
MiscFeature        2814   0.964029
Alley              2721   0.932169
Fence              2348   0.804385
SalePrice          1459   0.499829
FireplaceQu        1420   0.486468
LotFrontage         486   0.166495
GarageYrBlt         159   0.054471
GarageFinish        159   0.054471
GarageCond          159   0.054471
GarageQual          159   0.054471
GarageType          157   0.053786
BsmtCond             82   0.028092
BsmtExposure         82   0.028092
BsmtQual             81   0.027749
BsmtFinType2         80   0.027407
BsmtFinType1         79   0.027064
MasVnrType           24   0.008222
MasVnrArea           23   0.007879
MSZoning              4   0.001370
Utilities             2   0.000685
BsmtFullBath          2   0.000685
BsmtHalfBath          2   0.000685
Functional            2   0.000685
SaleType              1   0.000343
KitchenQual           1   0.000343
TotalBsmtSF           1   0.000343
BsmtFinSF1            1   0.000343
Electrical            1   0.000343
GarageCars            1   0.000343
GarageArea            1   0.000343
BsmtFinSF2            1   0.000343
Exterior2nd           1   0.000343
Exterior1st           1   0.000343
BsmtUnfSF             1   0.000343
RoofMatl              0   0.000000

一共發現有35個包含缺失值的列,一般的,當一列資料缺失值超過15%時,就應該刪除該列,注意到SalePrice列為我們要預測的列,所有除SalePice外其餘6列全部予以刪除。

all_set.drop('PoolQC',axis = 1,inplace = True)
all_set.drop('MiscFeature', axis=1, inplace=True)
all_set.drop('Alley', axis=1, inplace=True)
all_set.drop('Fence', axis=1, inplace=True)
all_set.drop('FireplaceQu', axis=1, inplace=True)
all_set.drop('LotFrontage', axis=1, inplace=True)

而後面GarageX的項,應該是一些列強相關的項,因為有GarageCars這個特徵表徵,也可以刪去。

all_set.drop('GarageYrBlt', axis=1, inplace=True)
all_set.drop('GarageFinish', axis=1, inplace=True)
all_set.drop('GarageCond', axis=1, inplace=True)
all_set.drop('GarageQual', axis=1, inplace=True)
all_set.drop('GarageType', axis=1, inplace=True)

對於BsmtX同樣刪除。

all_set.drop('BsmtCond', axis=1, inplace=True)
all_set.drop('BsmtExposure', axis=1, inplace=True)
all_set.drop('BsmtQual', axis=1, inplace=True)
all_set.drop('BsmtFinType2', axis=1, inplace=True)
all_set.drop('BsmtFinType1', axis=1, inplace=True)

對於MasVnr也同樣刪除。

all_set.drop('MasVnrType', axis=1, inplace=True)
all_set.drop('MasVnrArea', axis=1, inplace=True)

檢視另外18列含有缺失值的屬性。

              nan count  nan ratio    dtype
SalePrice          1459   0.499829  float64
MSZoning              4   0.001370   object
Utilities             2   0.000685   object
BsmtFullBath          2   0.000685  float64
BsmtHalfBath          2   0.000685  float64
Functional            2   0.000685   object
Exterior1st           1   0.000343   object
GarageCars            1   0.000343  float64
Exterior2nd           1   0.000343   object
SaleType              1   0.000343   object
Electrical            1   0.000343   object
GarageArea            1   0.000343  float64
BsmtUnfSF             1   0.000343  float64
BsmtFinSF2            1   0.000343  float64
BsmtFinSF1            1   0.000343  float64
TotalBsmtSF           1   0.000343  float64
KitchenQual           1   0.000343   object
Neighborhood          0   0.000000   object

發現這些列中有的是object屬性,有的是float屬性,分別進行處理,對於object屬性的列,使用出現頻率最高的值進行代替,對於float屬性的列,一般為“無”,所以不填,故使用0填充。

all_set['MSZoning'].fillna('C (all)',inplace=True)
all_set['Utilities'].fillna('AllPub',inplace=True)
all_set['Functional'].fillna('Typ',inplace=True)
all_set['Exterior1st'].fillna('VinylSd',inplace=True)
all_set['Exterior2nd'].fillna('VinylSd',inplace=True)
all_set['SaleType'].fillna('WD',inplace=True)
all_set['Electrical'].fillna('SBrkr',inplace=True)
all_set['KitchenQual'].fillna('TA',inplace=True)
all_set['BsmtFullBath'].fillna(0., inplace=True)
all_set['BsmtHalfBath'].fillna(0., inplace=True)
all_set['BsmtUnfSF'].fillna(0., inplace=True)
all_set['GarageArea'].fillna(0., inplace=True)
all_set['GarageCars'].fillna(0., inplace=True)
all_set['TotalBsmtSF'].fillna(0., inplace=True)
all_set['BsmtFinSF1'].fillna(0., inplace=True)
all_set['BsmtFinSF2'].fillna(0., inplace=True)

再次對缺失值進行檢查,發現除我們要預測的SalePrice列外沒有缺失值,缺失值處理完畢。

              nan count  nan ratio    dtype
SalePrice          1459   0.499829  float64
1stFlrSF              0   0.000000    int64
LandSlope             0   0.000000   object
LotArea               0   0.000000    int64
LotConfig             0   0.000000   object
LotShape              0   0.000000   object
LowQualFinSF          0   0.000000    int64
MSSubClass            0   0.000000    int64
MSZoning              0   0.000000   object
MiscVal               0   0.000000    int64

1.2.3 定性量啞編碼

對資料集進行onehot啞編碼,將定性量轉化為啞編碼方式,便於後續訓練模型,將原資料集中的SalePrice列刪除。

data_set.drop('SalePrice',axis = 1,inplace = True)
data_set_num = pd.DataFrame()
data_set_ob = pd.DataFrame()
for i in data_set.columns.values:
    if data_set[i].dtypes == 'object':
        data_set_ob = pd.concat([data_set_ob,data_set[i]],axis=1)
    else:
        data_set_num = pd.concat([data_set_num,data_set[i]],axis=1)
data_set_ob = pd.get_dummies(data_set)

得到啞編碼後的資料集,檢視shape:

(2918, 221)

1.2.4 連續值標準化

為提高收斂速度,對資料集標準化,對價格取對數。選擇sklearn中的StandardScaler進行標準化,價格採用log1p函式。

num_col = data_set_num.columns
data_set_num = pd.DataFrame(preprocessing.StandardScaler().fit_transform(data_set_num),columns=num_col)
data_y = np.log1p(data_y)

檢視對數化之前與之後的分佈:

對數化後更加符合正態分佈。

1.2.5 離群值刪除

首先拿到所有單列對於價格的散點圖:

發現GrLivArea明顯有兩個偏離點,找到刪除。

data_x.drop(data_x.index[[1298,523]],inplace = True)
data_y.drop(data_y.index[[1298,523]],inplace = True)

離群點刪除完畢。

2. 資料建模

2.1 資料分割

將資料集按7:3切割為訓練集和測試集。

x_train,x_test,y_train,y_test = cross_validation.train_test_split(data_x,data_y,test_size=0.3)

2.2 線性迴歸模型

利用sklearn中的線性模型對訓練集進行建模。

model = linear_model.LinearRegression()
model.fit(x_train,y_train)

使用多元線性迴歸擬合數據,檢視截距與係數:

係數: [-1.85543669e+07 -8.04763021e+06  8.74505546e-02 -8.41983585e-02
  2.60674291e+10  7.04799731e+09  8.07989649e-02 -2.37079067e-02
  1.07890706e+10  9.29348469e-02  1.55423164e-01  8.64651203e-02
  1.88232660e-01  1.80189371e-01  2.06861132e+07  3.56459618e-02
 -8.52451324e-02  7.75563359e-01 -4.14657567e+06 -7.68175125e-02
 -5.87408125e-01  1.83105469e-03  1.02868974e-02  4.62743044e-01
  6.69234022e-01  1.10272944e-01  1.84955835e-01  1.72290325e-01
 -2.82197009e+10  3.00650597e-02  4.03986931e-01  7.40909576e-02
 -2.11348534e-02 -2.70690585e+10 -2.70690585e+10 -2.70690585e+10
 -2.70690585e+10 -2.70690585e+10  1.53694722e+10  1.53694722e+10
  5.55073126e+08  5.55073126e+08  5.55073126e+08  5.55073126e+08
  5.55073126e+08  5.55073126e+08  5.55073126e+08  5.55073126e+08
  5.55073126e+08 -1.71070683e+10 -1.71070683e+10 -1.71070683e+10
 -2.20707567e+10 -1.71070683e+10 -1.71070683e+10 -1.71070683e+10
 -1.71070683e+10  3.77141831e+10  3.77141831e+10  3.77141831e+10
 -3.58089763e+10  3.77141831e+10  6.11169150e+09  6.11169150e+09
  6.11169150e+09  6.11169150e+09  6.11169150e+09 -6.32708343e+08
 -6.32708343e+08 -6.32708343e+08 -6.32708343e+08 -9.89338552e+09
 -9.89338552e+09 -9.89338552e+09 -9.89338552e+09 -1.68585564e+10
 -9.89338552e+09 -9.89338552e+09 -9.89338552e+09 -9.89338552e+09
 -9.89338552e+09 -9.89338552e+09 -9.89338552e+09 -9.89338552e+09
 -9.89338552e+09 -9.89338552e+09  1.43397977e+10  1.43397977e+10
  1.43397977e+10  1.43397977e+10  2.13049686e+10  1.43397977e+10
  1.43397977e+10  1.43397977e+10  1.43397977e+10  3.21889821e+10
  1.43397977e+10  1.43397977e+10  1.43397977e+10  1.43397977e+10
  1.43397977e+10  1.43397977e+10 -3.28284039e+09 -3.28284039e+09
 -3.28284039e+09 -3.28284039e+09 -3.28284039e+09 -3.28284039e+09
  1.02802487e+09  1.02802487e+09  1.02802487e+09  1.02802487e+09
  1.02802487e+09 -1.73231695e+09  1.02802487e+09  1.65177921e+09
  1.65177921e+09  1.65177921e+09  1.65177921e+09  1.65177921e+09
  1.65177921e+09 -5.89256168e+10 -5.89256168e+10 -5.89256168e+10
  2.93173824e+09 -5.89256168e+10 -2.05874740e+10 -2.05874740e+10
 -2.05874740e+10 -2.05874740e+10 -2.05874740e+10 -2.05874740e+10
 -2.05874740e+10 -2.05874740e+10 -1.88074328e+10 -1.88074328e+10
 -1.88074328e+10 -1.88074328e+10 -8.77449366e+09 -8.77449366e+09
 -8.77449366e+09 -8.77449366e+09  3.12362451e+10  3.12362451e+10
  3.12362451e+10 -6.76533101e+09 -6.76533101e+09 -6.76533101e+09
 -6.76533101e+09 -6.76533101e+09  1.74194848e+10  1.74194848e+10
  1.74194848e+10  1.74194848e+10 -2.32040189e+10 -2.32040189e+10
 -2.32040189e+10 -2.32040189e+10 -2.32040189e+10 -9.22089572e+09
 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09
 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09
 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09
 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09
 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09
 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09 -9.22089572e+09
  1.05481999e+10  1.05481999e+10  1.05481999e+10  2.45233811e+08
  2.45233811e+08  2.45233811e+08  2.45233811e+08  2.45233811e+08
  2.45233811e+08  2.45233811e+08  2.45233811e+08 -1.65389315e+08
 -1.65389315e+08 -1.65389315e+08 -1.65389315e+08 -1.65389315e+08
 -1.65389315e+08 -4.98004278e+08 -4.98004278e+08 -4.98004278e+08
 -4.98004278e+08 -4.98004278e+08 -4.98004278e+08 -1.40919590e+10
 -1.40919590e+10 -1.40919590e+10 -1.40919590e+10 -1.40919590e+10
 -1.40919590e+10 -1.40919590e+10 -1.40919590e+10 -1.40919590e+10
 -2.06193399e+09 -2.06193399e+09 -8.50851018e+08 -8.50851018e+08]
截距: 85719276156.30911

3. 模型評估

3.1 視覺化

將預測值與目標值放入一張圖進行比較。

y_pre = model.predict(x_test)
plt.scatter(y_pre,y_test,marker='o')
plt.scatter(y_test,y_test)
plt.show()

擬合度看起來還行, 看一下方差的大小。

print(metrics.mean_squared_error(y_test,y_pre))
0.015132547556096164

3.2  模型調整

3.2.1 正則化引數

線上性迴歸模型中加入正則化項,使用sklearn中的Ridge建立具有正則化項的線性迴歸模型。

model = linear_model.Ridge(alpha=i)
model.fit(x_train,y_train)

畫出正則化項隨偏差的變化趨勢。

可見aplha取1是比較合理的,此時Jcv(紅色曲線)接近最低值,Jtrain值也比較低。

  3.2.2 樣本分割比例

將誤差根據訓練樣本大小畫出曲線。

樣本分割比例的修改對誤差的影響不大(一般取6:2:2)。

3.2.3 迭代次數

迭代次數無需調整。

3.2.4 視覺化

將預測值與目標值重新作圖,得到:

可見效果還不錯,可以輸出提交了。

4. 總結

這是我第一次做kaggle比賽,也是從0開始,從資料清洗到建模到調整,全部按照自己的主觀想法來做,所以會比較隨意,後續也會逐漸再改進。