Kaggle—Home Credit Default Risk

我們將初步了解一下在Kaggle上舉辦的Home Credit Default Risk機(jī)器學(xué)習(xí)競(jìng)賽。這項(xiàng)比賽的目的是利用歷史貸款申請(qǐng)數(shù)據(jù)來(lái)預(yù)測(cè)申請(qǐng)人是否有能力償還貸款。這是一個(gè)標(biāo)準(zhǔn)的二分類(lèi)任務(wù)。

數(shù)據(jù)介紹

這些數(shù)據(jù)由Home Credit提供漏麦,這是一項(xiàng)專(zhuān)門(mén)為無(wú)銀行賬戶(hù)人群提供信貸額度(貸款)的服務(wù)耸袜。預(yù)測(cè)客戶(hù)是否會(huì)償還貸款或遇到困難是一項(xiàng)關(guān)鍵的業(yè)務(wù)需求,Home Credit在Kaggle上舉辦了這場(chǎng)比賽攀隔,看看機(jī)器學(xué)習(xí)社區(qū)可以開(kāi)發(fā)什么樣的模型來(lái)幫助他們完成這項(xiàng)任務(wù)。
有7種不同的數(shù)據(jù)來(lái)源:

  • application_train/application_test:train數(shù)據(jù)和test數(shù)據(jù)栖榨,包含關(guān)于每個(gè)家庭信貸貸款申請(qǐng)的信息昆汹。每個(gè)貸款都有自己的行,并由特性SK_ID_CURR標(biāo)識(shí)婴栽。application_train中的TARGET列:0:貸款已償還满粗;1:貸款未償還。
  • bureau:客戶(hù)以前從其他金融機(jī)構(gòu)取得的信用數(shù)據(jù)愚争。每個(gè)先前的貸款在bureau中都有自己的行映皆,但是申請(qǐng)數(shù)據(jù)中的一個(gè)貸款可以有多個(gè)先前的貸款挤聘。
  • bureau_balance:關(guān)于之前在bureau的信用記錄的每月數(shù)據(jù)。每一行是前一個(gè)信用記錄的一個(gè)月捅彻,一個(gè)前一個(gè)信用記錄可以有多個(gè)行组去,每個(gè)月的信用記錄長(zhǎng)度對(duì)應(yīng)一個(gè)行。
  • bureau_balance:關(guān)于之前在bureau的信用記錄的每月數(shù)據(jù)步淹。每一行是前一個(gè)信用記錄的一個(gè)月从隆,一個(gè)前一個(gè)信用記錄可以有多個(gè)行,每個(gè)月的信用記錄長(zhǎng)度對(duì)應(yīng)一個(gè)行缭裆。
  • POS_CASH_BALANCE:關(guān)于客戶(hù)以前的銷(xiāo)售點(diǎn)或家庭信貸的現(xiàn)金貸款的每月數(shù)據(jù)键闺。每一行是前一個(gè)銷(xiāo)售點(diǎn)或現(xiàn)金貸款的一個(gè)月,而前一個(gè)貸款可以有許多行澈驼。
  • credit_card_balance:關(guān)于以前的信用卡客戶(hù)使用家庭信用卡的每月數(shù)據(jù)艾杏。每一行是信用卡余額的一個(gè)月,一張信用卡可以有很多行盅藻。
  • installments_payment: 以前在國(guó)內(nèi)貸款的付款歷史购桑。每一次付款都有一行,每一次未付款也有一行氏淑。

這張圖顯示了所有的數(shù)據(jù)是如何關(guān)聯(lián)的:

庫(kù)

導(dǎo)入我們接下來(lái)需要用到的庫(kù)

import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelEncoder
import warnings
warnings.filterwarnings('ignore')
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import MinMaxScaler, Imputer
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier

讀入數(shù)據(jù)

app_train = pd.read_csv('application_train.csv')
app_test = pd.read_csv('application_test.csv')
print(app_train.shape)
print(app_test.shape)
# print(app_train.head(10))  # 查看前10行數(shù)據(jù)

輸出:

(307511, 122)
(48744, 121)

可以看出訓(xùn)練集有307511個(gè)觀(guān)察值(每個(gè)單獨(dú)的貸款)和122個(gè)特征(變量)勃蜘。
測(cè)試集要小得多,并且缺少TARGET列假残。

檢查T(mén)ARGET列的分布

TARGET是我們要預(yù)測(cè)的:0表示貸款按時(shí)償還缭贡,1表示貸款未按時(shí)償還。我們先檢查每一類(lèi)貸款的數(shù)量辉懒。

print(app_train['TARGET'].value_counts())
0    282686
1     24825
Name: TARGET, dtype: int64
app_train['TARGET'].astype(int).plot.hist()
plt.show()

這是一個(gè)類(lèi)別不平衡的問(wèn)題阳惹,我們可以很明顯的看出按時(shí)償還貸款的遠(yuǎn)遠(yuǎn)比未按時(shí)償還貸款的多。
解決方法

檢查缺失值

接下來(lái)眶俩,我們可以查看每一列中缺失值的數(shù)量和百分比莹汤。

# 按列計(jì)算缺失值
def missing_values_table(df):
    # 總?cè)笔е?    mis_val = df.isnull().sum()
    # 缺失值百分比
    mis_val_parent = 100*df.isnull().sum()/len(df)
    # 用結(jié)果做一個(gè)表格
    mis_val_table = pd.concat([mis_val, mis_val_parent], axis=1)
    # 重命名列
    mis_val_table_ren_columns = mis_val_table.rename(
        columns={0: 'Missing Values', 1: '% of Total Values'}
    )
    # 按丟失降序排列的百分比對(duì)表進(jìn)行排序
    mis_val_table_ren_columns = mis_val_table_ren_columns[mis_val_table_ren_columns.iloc[:, 1] != 0].sort_values(
        '% of Total Values', ascending=False).round(1)
    print('Your selected dataframe has ' + str(df.shape[1]) + ' columns.\n'
          'There are ' + str(mis_val_table_ren_columns.shape[0]) + ' columns that have missing values.')
    return mis_val_table_ren_columns

# 缺失值統(tǒng)計(jì)
miss_values = missing_values_table(app_train)
print(miss_values.head(11)) 
Your selected dataframe has 122 columns.
There are 67 columns that have missing values.
                          Missing Values  % of Total Values
COMMONAREA_MEDI                   214865               69.9
COMMONAREA_AVG                    214865               69.9
COMMONAREA_MODE                   214865               69.9
NONLIVINGAPARTMENTS_MEDI          213514               69.4
NONLIVINGAPARTMENTS_MODE          213514               69.4
NONLIVINGAPARTMENTS_AVG           213514               69.4
FONDKAPREMONT_MODE                210295               68.4
LIVINGAPARTMENTS_MODE             210199               68.4
LIVINGAPARTMENTS_MEDI             210199               68.4
LIVINGAPARTMENTS_AVG              210199               68.4
FLOORSMIN_MODE                    208642               67.8

當(dāng)構(gòu)建機(jī)器學(xué)習(xí)模型時(shí),我們必須填充這些缺失的值颠印。又或者我們使用XGBoost之類(lèi)的模型纲岭,這些模型可以處理缺失的值。另一種選擇是刪除具有高丟失值百分比的列线罕。我們現(xiàn)在保留所有的列止潮。

列類(lèi)型

查看每種數(shù)據(jù)類(lèi)型的列數(shù)

# 每種類(lèi)型列的數(shù)目
print(app_train.dtypes.value_counts())
float64    65
int64      41
object     16
dtype: int64

我們可以看出有16列是object類(lèi)型的,我們要把這些轉(zhuǎn)為機(jī)器學(xué)習(xí)可以處理的數(shù)值型钞楼。

# 每個(gè)object列中,不重復(fù)值的數(shù)目
print(app_train.select_dtypes('object').apply(pd.Series.nunique, axis=0))
NAME_CONTRACT_TYPE             2
CODE_GENDER                    3
FLAG_OWN_CAR                   2
FLAG_OWN_REALTY                2
NAME_TYPE_SUITE                7
NAME_INCOME_TYPE               8
NAME_EDUCATION_TYPE            5
NAME_FAMILY_STATUS             6
NAME_HOUSING_TYPE              6
OCCUPATION_TYPE               18
WEEKDAY_APPR_PROCESS_START     7
ORGANIZATION_TYPE             58
FONDKAPREMONT_MODE             4
HOUSETYPE_MODE                 3
WALLSMATERIAL_MODE             7
EMERGENCYSTATE_MODE            2
dtype: int64

標(biāo)簽編碼(Label Encoding)和獨(dú)熱編碼(One-Hot Encoding)

標(biāo)簽編碼:它給類(lèi)別一個(gè)任意的順序喇闸。分配給每個(gè)類(lèi)別的值是隨機(jī)的,不反映類(lèi)別的任何固有方面。所以我們?cè)谥挥袃蓚€(gè)類(lèi)別的時(shí)候使用標(biāo)簽編碼燃乍。例如上面的‘NAME_CONTRACT_TYPE’等唆樊,我們就可以使用標(biāo)簽編碼。
獨(dú)熱編碼:為分類(lèi)變量中的每個(gè)類(lèi)別創(chuàng)建一個(gè)新列橘沥。當(dāng)類(lèi)別>2的時(shí)候窗轩,我們將使用獨(dú)熱編碼夯秃。例如上面的‘CODE_GENDER’等座咆。當(dāng)然獨(dú)熱編碼的缺點(diǎn)也很明顯,就是特征可能會(huì)暴增仓洼,但我們可以使用PCA或其他降維方法來(lái)減少維數(shù)介陶。

# 創(chuàng)建一個(gè)LabelEncoder對(duì)象
le = LabelEncoder()
le_count = 0
# 標(biāo)簽編碼
for col in app_train:
    if app_train[col].dtype == 'object':
        if len(app_train[col].unique()) <= 2:
            le.fit(app_train[col])
            app_train[col] = le.transform(app_train[col])
            app_test[col] = le.transform(app_test[col])
            le_count += 1
print('%d columns were label encoded.' % le_count)
3 columns were label encoded.
train = pd.get_dummies(app_train)
test = pd.get_dummies(app_test)
print('Training Features shape: ', train.shape)
print('Testing Features shape: ', test.shape)
Training Features shape:  (307511, 243)
Testing Features shape:  (48744, 239)

調(diào)整訓(xùn)練集和測(cè)試集

在訓(xùn)練集和測(cè)試集中需要有相同的特征(列)。獨(dú)熱編碼在訓(xùn)練集中創(chuàng)建了更多的列色建,因?yàn)橛?xùn)練集中有TARGET列哺呜,而測(cè)試集中沒(méi)有。

train_labels = train['TARGET']
app_train, app_test = train.align(test, join = 'inner', axis = 1)
app_train['TARGET'] = train_labels
print('Training Features shape: ', app_train.shape)
print('Testing Features shape: ', app_test.shape)
Training Features shape:  (307511, 240)
Testing Features shape:  (48744, 239)

EDA

檢查異常值

print((train['DAYS_BIRTH'] / -365).describe())
count    307511.000000
mean         43.936973
std          11.956133
min          20.517808
25%          34.008219
50%          43.150685
75%          53.923288
max          69.120548
Name: DAYS_BIRTH, dtype: float64

看上去很正常沒(méi)有異常值

print(train['DAYS_EMPLOYED'].describe())
count    307511.000000
mean      63815.045904
std      141275.766519
min      -17912.000000
25%       -2760.000000
50%       -1213.000000
75%        -289.000000
max      365243.000000
Name: DAYS_EMPLOYED, dtype: float64

最大值為365243天箕戳,也就是1000年某残,這明顯不對(duì),是異常值陵吸。
出于好奇玻墅,讓我們對(duì)異常客戶(hù)進(jìn)行分析壮虫,看看他們的違約率比其他客戶(hù)高還是低澳厢。

anom = train[train['DAYS_EMPLOYED'] == 365243]
non_anom = train[train['DAYS_EMPLOYED'] != 365243]
print('The non-anomalies default on %0.2f%% of loans' % (100 * non_anom['TARGET'].mean()))
print('The anomalies default on %0.2f%% of loans' % (100 * anom['TARGET'].mean()))
print('There are %d anomalous days of employment' % len(anom))
The non-anomalies default on 8.66% of loans
The anomalies default on 5.40% of loans
There are 55374 anomalous days of employment

事實(shí)證明,這些異城羲疲現(xiàn)象的違約率較低剩拢。
處理異常取決于具體情況,沒(méi)有固定的規(guī)則饶唤。最安全的方法之一就是將異常設(shè)置為一個(gè)缺失的值徐伐,然后在使用算法之前填充它們。在這種情況下募狂,由于所有的異常值都是相同的呵晨,所以我們希望用相同的值來(lái)填充它們,以防所有這些貸款都有一個(gè)共同點(diǎn)熬尺。異常值似乎有一定的重要性摸屠。作為一種解決方案,我們將用非數(shù)字(np.nan)填充異常值粱哼,然后創(chuàng)建一個(gè)新的布爾列季二,指示該值是否異常。

# 創(chuàng)建一個(gè)異常標(biāo)志列
train['DAYS_EMPLOYED_ANOM'] = train['DAYS_EMPLOYED'] == 365243
# 用nan代替異常值
train['DAYS_EMPLOYED'].replace({365243: np.nan}, inplace=True)
test['DAYS_EMPLOYED_ANOM'] = test['DAYS_EMPLOYED'] == 365243
test['DAYS_EMPLOYED'].replace({365243: np.nan}, inplace=True)
print('There are %d anomalies in the test data out of %d entries' % (test["DAYS_EMPLOYED_ANOM"].sum(), len(test)))
There are 9274 anomalies in the test data out of 48744 entries

相關(guān)性

現(xiàn)在我們已經(jīng)處理了分類(lèi)變量和異常值,讓我們繼續(xù)EDA胯舷。一種嘗試和理解數(shù)據(jù)的方法是尋找特征和目標(biāo)之間的關(guān)聯(lián)刻蚯。我們可以使用.corr方法計(jì)算每個(gè)變量與目標(biāo)之間的Pearson相關(guān)系數(shù)。
相關(guān)系數(shù)并不是表示特征“相關(guān)性”的最佳方法桑嘶,但它確實(shí)讓我們了解了數(shù)據(jù)中可能存在的關(guān)系炊汹。對(duì)相關(guān)系數(shù)絕對(duì)值的一般解釋是:

  • .00-.19 “very weak”
  • .20-.39 “weak”
  • .40-.59 “moderate”
  • .60-.79 “strong”
  • .80-1.0 “very strong”
# 查看與TARGET的相關(guān)系數(shù)并排序
correlations = train.corr()['TARGET'].sort_values()
# 顯示相關(guān)系數(shù)
print('Most Positive Correlations:\n', correlations.tail(15))
print('\nMost Negative Correlations:\n', correlations.head(15))
Most Positive Correlations:
OCCUPATION_TYPE_Laborers                             0.043019
FLAG_DOCUMENT_3                                      0.044346
REG_CITY_NOT_LIVE_CITY                               0.044395
FLAG_EMP_PHONE                                       0.045982
NAME_EDUCATION_TYPE_Secondary / secondary special    0.049824
REG_CITY_NOT_WORK_CITY                               0.050994
DAYS_ID_PUBLISH                                      0.051457
CODE_GENDER_M                                        0.054713
DAYS_LAST_PHONE_CHANGE                               0.055218
NAME_INCOME_TYPE_Working                             0.057481
REGION_RATING_CLIENT                                 0.058899
REGION_RATING_CLIENT_W_CITY                          0.060893
DAYS_EMPLOYED                                        0.074958
DAYS_BIRTH                                           0.078239
TARGET                                               1.000000
Name: TARGET, dtype: float64

Most Negative Correlations:
EXT_SOURCE_3                           -0.178919
EXT_SOURCE_2                           -0.160472
EXT_SOURCE_1                           -0.155317
NAME_EDUCATION_TYPE_Higher education   -0.056593
CODE_GENDER_F                          -0.054704
NAME_INCOME_TYPE_Pensioner             -0.046209
DAYS_EMPLOYED_ANOM                     -0.045987
ORGANIZATION_TYPE_XNA                  -0.045987
FLOORSMAX_AVG                          -0.044003
FLOORSMAX_MEDI                         -0.043768
FLOORSMAX_MODE                         -0.043226
EMERGENCYSTATE_MODE_No                 -0.042201
HOUSETYPE_MODE_block of flats          -0.040594
AMT_GOODS_PRICE                        -0.039645
REGION_POPULATION_RELATIVE             -0.037227
Name: TARGET, dtype: float64

年齡對(duì)還款的影響

# 找出DAYS_BIRTH和TARGET之間的相關(guān)系數(shù)
app_train['DAYS_BIRTH'] = abs(app_train['DAYS_BIRTH'])
print(app_train['DAYS_BIRTH'].corr(app_train['TARGET']))
-0.07823930830982694

隨著客戶(hù)年齡的增長(zhǎng),與目標(biāo)存在負(fù)線(xiàn)性關(guān)系逃顶,這意味著隨著客戶(hù)年齡的增長(zhǎng)讨便,他們往往會(huì)更經(jīng)常地按時(shí)償還貸款。

plt.figure(figsize=(10, 8))
# KDE圖中按時(shí)償還的貸款
sns.kdeplot(app_train.loc[app_train['TARGET'] == 0, 'DAYS_BIRTH'] / -365, label = 'target == 0')
# KDE圖中未按時(shí)償還的貸款
sns.kdeplot(app_train.loc[app_train['TARGET'] == 1, 'DAYS_BIRTH'] / -365, label = 'target == 1')
plt.xlabel('Age (years)')
plt.ylabel('Density')
plt.title('Distribution of Ages')
plt.show()

target == 1曲線(xiàn)向范圍的較年輕端傾斜以政。雖然這不是一個(gè)顯著的相關(guān)性(-0.07相關(guān)系數(shù))霸褒,但這個(gè)變量很可能在機(jī)器學(xué)習(xí)模型中有用,因?yàn)樗_實(shí)會(huì)影響目標(biāo)盈蛮。

外部來(lái)源

與目標(biāo)負(fù)相關(guān)性最強(qiáng)的三個(gè)變量是EXT_SOURCE_1废菱、EXT_SOURCE_2和EXT_SOURCE_3。根據(jù)文檔抖誉,這些特征表示“來(lái)自外部數(shù)據(jù)源的標(biāo)準(zhǔn)化得分”殊轴。
首先,我們可以顯示EXT_SOURCE特性與目標(biāo)以及彼此之間的關(guān)聯(lián)袒炉。

# 提取EXT_SOURCE變量并顯示相關(guān)性
ext_data = app_train[['TARGET', 'EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3', 'DAYS_BIRTH']]
ext_data_corrs = ext_data.corr()
print(ext_data_corrs)
                TARGET  EXT_SOURCE_1  EXT_SOURCE_2  EXT_SOURCE_3  DAYS_BIRTH
TARGET        1.000000     -0.155317     -0.160472     -0.178919    0.078239
EXT_SOURCE_1 -0.155317      1.000000      0.213982      0.186846   -0.600610
EXT_SOURCE_2 -0.160472      0.213982      1.000000      0.109167   -0.091996
EXT_SOURCE_3 -0.178919      0.186846      0.109167      1.000000   -0.205478
DAYS_BIRTH    0.078239     -0.600610     -0.091996     -0.205478    1.000000

這三個(gè)EXT_SOURCE特性都與目標(biāo)負(fù)相關(guān)旁理,這表明隨著EXT_SOURCE值的增加,客戶(hù)端更有可能償還貸款梳杏。我們還可以看到DAYS_BIRTH與EXT_SOURCE_1呈正相關(guān)韧拒,這表明這個(gè)評(píng)分中的一個(gè)因素可能是客戶(hù)端年齡。

特征工程

多項(xiàng)式特征

關(guān)于多項(xiàng)式特征可以看這篇文章

# 為多項(xiàng)式特征創(chuàng)建一個(gè)新的dataframe
poly_features = app_train[['EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3', 'DAYS_BIRTH', 'TARGET']]
poly_features_test = app_test[['EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3', 'DAYS_BIRTH']]

imputer = Imputer(strategy='median')

poly_target = poly_features['TARGET']
poly_features = poly_features.drop(columns=['TARGET'])
poly_features = imputer.fit_transform(poly_features)
poly_features_test = imputer.transform(poly_features_test)
poly_transformer = PolynomialFeatures(degree=3)

poly_transformer.fit(poly_features)

poly_features = poly_transformer.transform(poly_features)
poly_features_test = poly_transformer.transform(poly_features_test)
print('Polynomial Features shape: ', poly_features.shape)

print(poly_transformer.get_feature_names(input_features=['EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3', 'DAYS_BIRTH'])
      [:15])
Polynomial Features shape:  (307511, 35)
['1',
 'EXT_SOURCE_1',
 'EXT_SOURCE_2',
 'EXT_SOURCE_3',
 'DAYS_BIRTH',
 'EXT_SOURCE_1^2',
 'EXT_SOURCE_1 EXT_SOURCE_2',
 'EXT_SOURCE_1 EXT_SOURCE_3',
 'EXT_SOURCE_1 DAYS_BIRTH',
 'EXT_SOURCE_2^2',
 'EXT_SOURCE_2 EXT_SOURCE_3',
 'EXT_SOURCE_2 DAYS_BIRTH',
 'EXT_SOURCE_3^2',
 'EXT_SOURCE_3 DAYS_BIRTH',
 'DAYS_BIRTH^2']

共有35個(gè)特征十性,每個(gè)特征的冪次可達(dá)3次叛溢,并有交互項(xiàng)。現(xiàn)在劲适,我們可以看到這些新特征與目標(biāo)的相關(guān)系數(shù)楷掉。

poly_features = pd.DataFrame(poly_features,
                             columns = poly_transformer.get_feature_names(['EXT_SOURCE_1', 'EXT_SOURCE_2',
                                                                           'EXT_SOURCE_3', 'DAYS_BIRTH']))

poly_features['TARGET'] = poly_target

# 找出與target的相關(guān)性
poly_corrs = poly_features.corr()['TARGET'].sort_values()

# 顯示最消極和最積極的一面
print(poly_corrs.head(10))
print(poly_corrs.tail(5))
EXT_SOURCE_2 EXT_SOURCE_3                -0.193939
EXT_SOURCE_1 EXT_SOURCE_2 EXT_SOURCE_3   -0.189605
EXT_SOURCE_2^2 EXT_SOURCE_3              -0.176428
EXT_SOURCE_2 EXT_SOURCE_3^2              -0.172282
EXT_SOURCE_1 EXT_SOURCE_2                -0.166625
EXT_SOURCE_1 EXT_SOURCE_3                -0.164065
EXT_SOURCE_2                             -0.160295
EXT_SOURCE_1 EXT_SOURCE_2^2              -0.156867
EXT_SOURCE_3                             -0.155892
EXT_SOURCE_1 EXT_SOURCE_3^2              -0.150822
Name: TARGET, dtype: float64
EXT_SOURCE_1 EXT_SOURCE_2 DAYS_BIRTH    0.155891
EXT_SOURCE_2 DAYS_BIRTH                 0.156873
EXT_SOURCE_2 EXT_SOURCE_3 DAYS_BIRTH    0.181283
TARGET                                  1.000000
1                                            NaN

幾個(gè)新變量與目標(biāo)的相關(guān)性(就絕對(duì)值而言)比原來(lái)的特征更大。當(dāng)我們構(gòu)建機(jī)器學(xué)習(xí)模型時(shí)霞势,我們可以嘗試使用或不使用這些特性來(lái)確定它們是否真的有助于模型的學(xué)習(xí)烹植。
我們將把這些特性添加到訓(xùn)練集和測(cè)試集中,然后評(píng)估具有和不具有這些特性的模型愕贡。在機(jī)器學(xué)習(xí)中草雕,很多時(shí)候,知道一種方法是否有效的唯一方法就是嘗試它!

poly_features_test = pd.DataFrame(poly_features_test,
                                  columns = poly_transformer.get_feature_names(['EXT_SOURCE_1', 'EXT_SOURCE_2',
                                                                                'EXT_SOURCE_3', 'DAYS_BIRTH']))

poly_features['SK_ID_CURR'] = app_train['SK_ID_CURR']
app_train_poly = app_train.merge(poly_features, on = 'SK_ID_CURR', how = 'left')

poly_features_test['SK_ID_CURR'] = app_test['SK_ID_CURR']
app_test_poly = app_test.merge(poly_features_test, on = 'SK_ID_CURR', how = 'left')

app_train_poly, app_test_poly = app_train_poly.align(app_test_poly, join = 'inner', axis = 1)

print('Training data with polynomial features shape: ', app_train_poly.shape)
print('Testing data with polynomial features shape:  ', app_test_poly.shape)
Training data with polynomial features shape:  (307511, 274)
Testing data with polynomial features shape:   (48744, 274)

領(lǐng)域知識(shí)特征

我們可以創(chuàng)建幾個(gè)特性固以,試圖捕捉我們認(rèn)為對(duì)于判斷客戶(hù)是否會(huì)拖欠貸款可能很重要的信息墩虹。

  • CREDIT_INCOME_PERCENT: 信貸金額占客戶(hù)收入的百分比
  • ANNUITY_INCOME_PERCENT: 貸款年金占客戶(hù)收入的百分比
  • CREDIT_TERM: 以月為單位支付的期限(因?yàn)槟杲鹗敲吭碌狡诘慕痤~)
  • DAYS_EMPLOYED_PERCENT: 就職天數(shù)占客戶(hù)年齡的百分比
app_train_domain = app_train.copy()
app_test_domain = app_test.copy()

app_train_domain['CREDIT_INCOME_PERCENT'] = app_train_domain['AMT_CREDIT'] / app_train_domain['AMT_INCOME_TOTAL']
app_train_domain['ANNUITY_INCOME_PERCENT'] = app_train_domain['AMT_ANNUITY'] / app_train_domain['AMT_INCOME_TOTAL']
app_train_domain['CREDIT_TERM'] = app_train_domain['AMT_ANNUITY'] / app_train_domain['AMT_CREDIT']
app_train_domain['DAYS_EMPLOYED_PERCENT'] = app_train_domain['DAYS_EMPLOYED'] / app_train_domain['DAYS_BIRTH']

app_test_domain['CREDIT_INCOME_PERCENT'] = app_test_domain['AMT_CREDIT'] / app_test_domain['AMT_INCOME_TOTAL']
app_test_domain['ANNUITY_INCOME_PERCENT'] = app_test_domain['AMT_ANNUITY'] / app_test_domain['AMT_INCOME_TOTAL']
app_test_domain['CREDIT_TERM'] = app_test_domain['AMT_ANNUITY'] / app_test_domain['AMT_CREDIT']
app_test_domain['DAYS_EMPLOYED_PERCENT'] = app_test_domain['DAYS_EMPLOYED'] / app_test_domain['DAYS_BIRTH']

模型

Logistic Regression

# 邏輯回歸
# 從訓(xùn)練集中刪除TARGET列
if 'TARGET' in app_train:
    train = app_train.drop(columns = ['TARGET'])
else:
    train = app_train.copy()

features = list(train.columns)

test = app_test.copy()

# 缺失值的中值估計(jì)
imputer = Imputer(strategy='median')

# 將每個(gè)特性縮放到0-1
scaler = MinMaxScaler(feature_range=(0, 1))

imputer.fit(train)

train = imputer.transform(train)
test = imputer.transform(app_test)

scaler.fit(train)
train = scaler.transform(train)
test = scaler.transform(test)

print('Training data shape: ', train.shape)
print('Testing data shape: ', test.shape)
Training data shape:  (307511, 278)
Testing data shape:  (48744, 278)

現(xiàn)在這個(gè)模型已經(jīng)經(jīng)過(guò)訓(xùn)練嘱巾,我們可以用它來(lái)做預(yù)測(cè)。我們想預(yù)測(cè)不償還貸款的概率诫钓,所以我們使用predict.proba()

log_reg = LogisticRegression(C = 0.0001)
log_reg.fit(train, train_labels)
log_reg_pred = log_reg.predict_proba(test)[:, 1]

submit = app_test[['SK_ID_CURR']]
submit['TARGET'] = log_reg_pred
# 將提交文件保存到csv文件中
submit.to_csv('log_reg_baseline.csv', index=False)

提交后旬昭,分?jǐn)?shù)為0.671

Random Forest

# 隨機(jī)森林
random_forest = RandomForestClassifier(n_estimators = 100, random_state = 50, verbose = 1, n_jobs = -1)
random_forest.fit(train, train_labels)
predictions = random_forest.predict_proba(test)[:, 1]

submit = app_test[['SK_ID_CURR']]
submit['TARGET'] = predictions
submit.to_csv('random_forest_baseline.csv', index = False)

提交后,分?jǐn)?shù)為0.678

總結(jié)

我們首先了解數(shù)據(jù)菌湃。然后问拘,我們執(zhí)行了一個(gè)相當(dāng)簡(jiǎn)單的EDA,試圖識(shí)別可能有助于建模的關(guān)系惧所、趨勢(shì)或異常骤坐。在此過(guò)程中,我們執(zhí)行了必要的預(yù)處理步驟纯路,比如對(duì)分類(lèi)變量進(jìn)行編碼或油、輸入缺失的值以及將特性縮放到一個(gè)范圍寞忿。然后驰唬,我們從現(xiàn)有的數(shù)據(jù)構(gòu)建新特性。最后腔彰,我們跑了兩個(gè)模型叫编。
參考文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市霹抛,隨后出現(xiàn)的幾起案子搓逾,更是在濱河造成了極大的恐慌,老刑警劉巖杯拐,帶你破解...
    沈念sama閱讀 212,816評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件霞篡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡端逼,警方通過(guò)查閱死者的電腦和手機(jī)朗兵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)顶滩,“玉大人余掖,你說(shuō)我怎么就攤上這事〗嘎常” “怎么了盐欺?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,300評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)仅醇。 經(jīng)常有香客問(wèn)我冗美,道長(zhǎng),這世上最難降的妖魔是什么析二? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,780評(píng)論 1 285
  • 正文 為了忘掉前任粉洼,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘漆改。我一直安慰自己心铃,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,890評(píng)論 6 385
  • 文/花漫 我一把揭開(kāi)白布挫剑。 她就那樣靜靜地躺著去扣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪樊破。 梳的紋絲不亂的頭發(fā)上愉棱,一...
    開(kāi)封第一講書(shū)人閱讀 50,084評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音哲戚,去河邊找鬼奔滑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛顺少,可吹牛的內(nèi)容都是我干的朋其。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼脆炎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼梅猿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起秒裕,我...
    開(kāi)封第一講書(shū)人閱讀 37,912評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤袱蚓,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后几蜻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體喇潘,經(jīng)...
    沈念sama閱讀 44,355評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,666評(píng)論 2 327
  • 正文 我和宋清朗相戀三年梭稚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颖低。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,809評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡哨毁,死狀恐怖枫甲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情扼褪,我是刑警寧澤想幻,帶...
    沈念sama閱讀 34,504評(píng)論 4 334
  • 正文 年R本政府宣布,位于F島的核電站话浇,受9級(jí)特大地震影響脏毯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜幔崖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,150評(píng)論 3 317
  • 文/蒙蒙 一食店、第九天 我趴在偏房一處隱蔽的房頂上張望渣淤。 院中可真熱鬧,春花似錦吉嫩、人聲如沸价认。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,882評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)用踩。三九已至,卻和暖如春忙迁,著一層夾襖步出監(jiān)牢的瞬間脐彩,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,121評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工姊扔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惠奸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,628評(píng)論 2 362
  • 正文 我出身青樓恰梢,卻偏偏與公主長(zhǎng)得像佛南,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子删豺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,724評(píng)論 2 351