这部分主要对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创建一些新的特征、清洗数据等等。