Home Credit Default Risk EDA

这部分主要对kaggle的比赛Home Credit Default Risk做的一些探索性数据分析(EDA)

读入数据

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

application_train = pd.read_csv('application_train.csv')
application_test = pd.read_csv('application_test.csv')
bureau = pd.read_csv('bureau.csv')
bureau_balance = pd.read_csv('bureau_balance.csv')
credit_card_balance = pd.read_csv('credit_card_balance.csv')
installments_payments = pd.read_csv('installments_payments.csv')
previous_application = pd.read_csv('previous_application.csv')
POS_CASH_balance = pd.read_csv('POS_CASH_balance.csv')

print('application_train.shape:', application_train.shape)
print('application_test.shape:', application_test.shape)
print('bureau.shape:', bureau.shape)
print('bureau_balance.shape:', bureau_balance.shape)
print('credit_card_balance.shape:', credit_card_balance.shape)
print('installments_payments.shape:', installments_payments.shape)
print('POS_CASH_balance.shape:', POS_CASH_balance.shape)
application_train.shape: (307511, 122)
application_test.shape: (48744, 121)
bureau.shape: (1716428, 17)
bureau_balance.shape: (27299925, 3)
credit_card_balance.shape: (3840312, 23)
installments_payments.shape: (13605401, 8)
POS_CASH_balance.shape: (10001358, 8)

查看数据

查看缺失的数据

def missing_data(data):
    total = data.isnull().sum().sort_values(ascending=False)
    percent = (data.isnull().sum()/data.isnull().count()).sort_values(ascending=False)
    return pd.concat([total, percent], axis=1, keys=['total', 'percent'])
print('missing_data(application_train).head(10):')
print(missing_data(application_train).head(10))
missing_data(application_train).head(10):
                           total   percent
COMMONAREA_MEDI           214865  0.698723
COMMONAREA_AVG            214865  0.698723
COMMONAREA_MODE           214865  0.698723
NONLIVINGAPARTMENTS_MODE  213514  0.694330
NONLIVINGAPARTMENTS_MEDI  213514  0.694330
NONLIVINGAPARTMENTS_AVG   213514  0.694330
FONDKAPREMONT_MODE        210295  0.683862
LIVINGAPARTMENTS_MEDI     210199  0.683550
LIVINGAPARTMENTS_MODE     210199  0.683550
LIVINGAPARTMENTS_AVG      210199  0.683550
print('missing_data(application_test).head(10):')
print(missing_data(application_test).head(10))
missing_data(application_test).head(10):
                          total   percent
COMMONAREA_MEDI           33495  0.687161
COMMONAREA_AVG            33495  0.687161
COMMONAREA_MODE           33495  0.687161
NONLIVINGAPARTMENTS_MODE  33347  0.684125
NONLIVINGAPARTMENTS_MEDI  33347  0.684125
NONLIVINGAPARTMENTS_AVG   33347  0.684125
FONDKAPREMONT_MODE        32797  0.672842
LIVINGAPARTMENTS_AVG      32780  0.672493
LIVINGAPARTMENTS_MEDI     32780  0.672493
LIVINGAPARTMENTS_MODE     32780  0.672493
print('missing_data(bureau).head(10):')
print(missing_data(bureau).head(10))
missing_data(bureau).head(10):
                          total   percent
AMT_ANNUITY             1226791  0.714735
AMT_CREDIT_MAX_OVERDUE  1124488  0.655133
DAYS_ENDDATE_FACT        633653  0.369170
AMT_CREDIT_SUM_LIMIT     591780  0.344774
AMT_CREDIT_SUM_DEBT      257669  0.150119
DAYS_CREDIT_ENDDATE      105553  0.061496
AMT_CREDIT_SUM               13  0.000008
CREDIT_TYPE                   0  0.000000
AMT_CREDIT_SUM_OVERDUE        0  0.000000
CNT_CREDIT_PROLONG            0  0.000000
print('missing_data(bureau_balance).head(10):')
print(missing_data(bureau_balance).head(10))
missing_data(bureau_balance).head(10):
                total  percent
STATUS              0      0.0
MONTHS_BALANCE      0      0.0
SK_ID_BUREAU        0      0.0
print('missing_data(credit_card_balance).head(10):')
print(missing_data(credit_card_balance).head(10))
missing_data(credit_card_balance).head(10):
                             total   percent
AMT_PAYMENT_CURRENT         767988  0.199981
AMT_DRAWINGS_OTHER_CURRENT  749816  0.195249
CNT_DRAWINGS_POS_CURRENT    749816  0.195249
CNT_DRAWINGS_OTHER_CURRENT  749816  0.195249
CNT_DRAWINGS_ATM_CURRENT    749816  0.195249
AMT_DRAWINGS_ATM_CURRENT    749816  0.195249
AMT_DRAWINGS_POS_CURRENT    749816  0.195249
CNT_INSTALMENT_MATURE_CUM   305236  0.079482
AMT_INST_MIN_REGULARITY     305236  0.079482
SK_DPD_DEF                       0  0.000000
print('missing_data(installments_payments).head(10):')
print(missing_data(installments_payments).head(10))
missing_data(installments_payments).head(10):
                        total   percent
AMT_PAYMENT              2905  0.000214
DAYS_ENTRY_PAYMENT       2905  0.000214
AMT_INSTALMENT              0  0.000000
DAYS_INSTALMENT             0  0.000000
NUM_INSTALMENT_NUMBER       0  0.000000
NUM_INSTALMENT_VERSION      0  0.000000
SK_ID_CURR                  0  0.000000
SK_ID_PREV                  0  0.000000
print('missing_data(POS_CASH_balance).head(10):')
print(missing_data(POS_CASH_balance).head(10))
missing_data(POS_CASH_balance).head(10):
                       total   percent
CNT_INSTALMENT_FUTURE  26087  0.002608
CNT_INSTALMENT         26071  0.002607
SK_DPD_DEF                 0  0.000000
SK_DPD                     0  0.000000
NAME_CONTRACT_STATUS       0  0.000000
MONTHS_BALANCE             0  0.000000
SK_ID_CURR                 0  0.000000
SK_ID_PREV                 0  0.000000

检查TARGET列的分布

print(application_train['TARGET'].value_counts())
application_train['TARGET'].astype(int).plot.hist()
plt.show()

数据分析

贷款的类型

让我们看看贷款的类型,以及在另一个的图表上,TARGET目标值为1(贷款未按时偿还)的贷款的百分比(按贷款类型划分)。

def plot_stats(feature, label_rotation=False, horizontal_layout=True):
    temp = application_train[feature].value_counts()
    df1 = pd.DataFrame({feature: temp.index, 'Number of contracts': temp.values})

    cat_perc = application_train[[feature, 'TARGET']].groupby([feature], as_index=False).mean()
    cat_perc.sort_values(by='TARGET', ascending=False, inplace=True)

    if (horizontal_layout):
        fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12, 6))
    else:
        fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(12, 14))
    sns.set_color_codes("pastel")
    s = sns.barplot(ax=ax1, x=feature, y="Number of contracts", data=df1)
    if (label_rotation):
        s.set_xticklabels(s.get_xticklabels(), rotation=90)

    s = sns.barplot(ax=ax2, x=feature, y='TARGET', order=cat_perc[feature], data=cat_perc)
    if (label_rotation):
        s.set_xticklabels(s.get_xticklabels(), rotation=90)
    plt.ylabel('Percent of target with value 1 [%]', fontsize=10)
    plt.tick_params(axis='both', which='major', labelsize=10)

    plt.show()

plot_stats('NAME_CONTRACT_TYPE')

循环贷款只是贷款合同的小部分(10%左右)。与此同时,与循环贷款相比,现金贷款会有更大的几率未偿还。

客户的性别

让我们看看客户的性别,另外,在另一个图上,TARGET目标值为1(贷款未按时偿还)的贷款的百分比(按客户性别划分)

plot_stats('CODE_GENDER')

女性客户的数量几乎是男性客户数量的两倍。从违约信贷的比例来看,男性不偿还贷款的几率(约10%)高于女性(约7%)。

客户有没有车

让我们看看客户有没有自己的车,另外,在另一个图上,TARGET目标值为1(贷款未按时偿还)的贷款的百分比。

plot_stats('FLAG_OWN_CAR')

拥有汽车的客户几乎是没有汽车的客户的一半。拥有汽车的客户不太可能不偿还拥有汽车的客户的汽车。没有汽车的客户违约率稍微高点(8%左右)

客户有没有房

让我们看看客户有没有自己的房子,另外,在另一个图上,TARGET目标值为1(贷款未按时偿还)的贷款的百分比。

plot_stats('FLAG_OWN_REALTY')

拥有房产的客户是不拥有房产的两倍多。这两类人(拥有房产或不拥有房产)的违约率都在8%左右。

客户家庭状况
plot_stats('NAME_FAMILY_STATUS', True, True)

大多数客户已婚,其次是单身/未婚。
在不偿还贷款比例方面,民事婚姻不偿还比例最高(10%),寡妇最低。

儿童的数量
plot_stats('CNT_CHILDREN')

大多数贷款的客户都没有孩子。从图中我们可以看到孩子越少的客户越会去贷款。
在还款方面,无子女、1、2、3、5子女的客户平均有10%左右没有还款。对于有9、11个孩子的客户,未偿还贷款的比例为100%。

客户家庭人数
plot_stats('CNT_FAM_MEMBERS',True)

家庭成员为2人的客户最多,其次为1人(单身人士)、3人(独生子女家庭)和4人。
家庭成员分别为11人和13人的客户有100%的违约率。有10或8个成员的家庭有30%左右的违约率。拥有6名或6名以下家庭成员的违约率为10%的左右。

客户收入类型
plot_stats('NAME_INCOME_TYPE',False,False)

申请贷款的人大多是工作收入,其次是商业伙伴、养老金领取者和国家公务员。
产假的有近40%的违约率,其次是失业(约37%)。其他类型的违约率均低于10%。

客户的职业
plot_stats('OCCUPATION_TYPE',True, False)

大部分贷款由劳动者承担,其次是销售人员。IT人员的最低。前几天看了一篇推文发现学了IT的罪犯,再犯率为0%。
违约率最高的是低技能劳动者(17%以上),其次是司机、服务员/酒吧服务员、保安、劳动者和厨师。

行业类型
plot_stats('ORGANIZATION_TYPE',True, False)

违约率最高的行业是运输业:第3类(16%)、工业:第13类(13.5%)、工业:第8类(12.5%)和餐饮业(不到12%)。

客户的教育类型
plot_stats('NAME_EDUCATION_TYPE',True)

大部分客户接受中等/中等特殊教育,其次是接受高等教育的客户。只有极少数人拥有学位。
初中毕业的贷款虽然很少见,但不还贷率最高(11%)。拥有学位的人的不偿还率低于2%。

客户房屋类型
plot_stats('NAME_HOUSING_TYPE',True)

25万多名申请贷款的人将他们的住房登记为住房/公寓。

从这些类别来看,租来的公寓和跟父母一起住的高于10%的违约率。

Bureau数据集

让我们将application_train与bureau合并。

application_bureau_train = application_train.merge(bureau, left_on='SK_ID_CURR', right_on='SK_ID_CURR', how='inner')
print("The resulting dataframe `application_bureau_train` has ",application_bureau_train.shape[0]," rows and ", 
      application_bureau_train.shape[1]," columns.")
The resulting dataframe `application_bureau_train` has  1465325  rows and  138  columns.
现在让我们分析application_bureau_train数据。
def plot_b_stats(feature,label_rotation=False,horizontal_layout=True):
    temp = application_bureau_train[feature].value_counts()
    df1 = pd.DataFrame({feature: temp.index,'Number of contracts': temp.values})

    # Calculate the percentage of target=1 per category value
    cat_perc = application_bureau_train[[feature, 'TARGET']].groupby([feature],as_index=False).mean()
    cat_perc.sort_values(by='TARGET', ascending=False, inplace=True)
    
    if(horizontal_layout):
        fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12,6))
    else:
        fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(12,14))
    sns.set_color_codes("pastel")
    s = sns.barplot(ax=ax1, x = feature, y="Number of contracts",data=df1)
    if(label_rotation):
        s.set_xticklabels(s.get_xticklabels(),rotation=90)
    
    s = sns.barplot(ax=ax2, x = feature, y='TARGET', order=cat_perc[feature], data=cat_perc)
    if(label_rotation):
        s.set_xticklabels(s.get_xticklabels(),rotation=90)
    plt.ylabel('Percent of target with value 1 [%]', fontsize=10)
    plt.tick_params(axis='both', which='major', labelsize=10)

    plt.show()
信用状态

让我们看看信用状况分布。我们首先显示每个类别的信贷数量(可以是关闭的、活跃的、出售的和坏账)。

plot_b_stats('CREDIT_ACTIVE')

我们可以看出大约有900000人的状态是closed,Bad debt的状态是最少的。
但我们可以看到Bad debt的违约率是最高的,是其他状态的两倍多。

信用货币
plot_b_stats('CREDIT_CURRENCY')

从图上我们可以看出,几乎全都是currency_1贷款。
根据货币的不同,客户违约的比例是不同的。从currency_3开始,然后是currency_1和currency_2,违约的百分比分别是11%、8%和5%。currency_4的违约率约为0%。

信用类型
plot_b_stats('CREDIT_TYPE', True, True)

在 Credit Bureau登记的历史信用主要是消费信贷和信用卡。
购买设备的贷款——违约率超过20%;
小额贷款——违约率超过20%;
流动资金补充贷款——违约率超过12%。

Previous application数据集

让我们将application_train与previous_application合并。

application_prev_train = application_train.merge(previous_application, left_on='SK_ID_CURR', right_on='SK_ID_CURR', how='inner')
print("The resulting dataframe `application_prev_train` has ",application_prev_train.shape[0]," rows and ", 
      application_prev_train.shape[1]," columns.")
The resulting dataframe `application_prev_train` has  1413701  rows and  158  columns.
def plot_p_stats(feature,label_rotation=False,horizontal_layout=True):
    temp = application_prev_train[feature].value_counts()
    df1 = pd.DataFrame({feature: temp.index,'Number of contracts': temp.values})

    # Calculate the percentage of target=1 per category value
    cat_perc = application_prev_train[[feature, 'TARGET']].groupby([feature],as_index=False).mean()
    cat_perc.sort_values(by='TARGET', ascending=False, inplace=True)
    
    if(horizontal_layout):
        fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12,6))
    else:
        fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(12,14))
    sns.set_color_codes("pastel")
    s = sns.barplot(ax=ax1, x = feature, y="Number of contracts",data=df1)
    if(label_rotation):
        s.set_xticklabels(s.get_xticklabels(),rotation=90)
    
    s = sns.barplot(ax=ax2, x = feature, y='TARGET', order=cat_perc[feature], data=cat_perc)
    if(label_rotation):
        s.set_xticklabels(s.get_xticklabels(),rotation=90)
    plt.ylabel('Percent of target with value 1 [%]', fontsize=10)
    plt.tick_params(axis='both', which='major', labelsize=10)

    plt.show()
合同类型
plot_p_stats('NAME_CONTRACT_TYPE_y')

在之前的申请数据中有三种类型的合同:现金贷款、消费贷款、循环贷款。现金贷款和消费贷款几乎相同(约60万),而循环贷款约15万。
之前申请过的客户违约率因之前申请合同的类型而异,循环贷款的违约率为10%,现金贷款的违约率为9.5%,消费贷款的违约率为8%。

现金贷款的目的
plot_p_stats('NAME_CASH_LOAN_PURPOSE', True, True)

除XAP、XNA、修理、其他以外,购买二手车、建造房屋占合同数量最多。

合同状态
plot_p_stats('NAME_CONTRACT_STATUS', True, True)

大部分的合同状态是批准的,其次是取消和拒绝的。
合同状态为拒绝的违约率最高(约12%),其次是取消的(约9%),违约率最低的是批准的(不到8%)。

付款类型
plot_p_stats('NAME_PAYMENT_TYPE', True, True)

大部分的付款类型是通过银行的,其次是XNA。
除了XNA(违约率最高),其他的违约率约为8%。

结论

EDA到此为止,我们可以根据EDA创建一些新的特征、清洗数据等等。

你可能感兴趣的:(Home Credit Default Risk EDA)