Kaggle:Home Credit Default Risk 数据探索及可视化(1)
最近博主在做个 kaggle 竞赛,有个 Kernel 的数据探索分析非常值得借鉴,博主也学习了一波操作,搬运过来借鉴,原链接如下:
https://www.kaggle.com/willkoehrsen/start-here-a-gentle-introduction
1 数据介绍
数据由Home Credit提供,该服务致力于向无银行账户的人群提供信贷(贷款)。预测客户是否偿还贷款或遇到困难是一项重要的业务需求,Home Credit将在Kaggle上举办此类竞赛,以了解机器学习社区可以开展哪些模式以帮助他们完成此任务。
有7种不同的数据来源:
application_train / application_test:
主要的培训和测试数据以及关于Home Credit每个贷款申请的信息。每笔贷款都有自己的行,并由功能SK_ID_CURR标识。培训申请数据附带TARGET表示0:贷款已还清或1:贷款未还清。
bureau:
有关客户之前来自其他金融机构的信贷的数据。以前的每一笔信贷都有自己的分行,但申请数据中的一笔贷款可能有多笔先前信贷。
bureau_balance:
关于主管局以前信用的月度数据。每一行都是上一个信用的一个月,并且一个先前的信用可以有多个行,每个信用额度的每个月有一个行。
previous_application:
之前在申请数据中拥有贷款的客户的Home Credit贷款申请。申请数据中的每个当前贷款都可以有多个以前的贷款。每个以前的应用程序都有一行,并由功能SK_ID_PREV标识。
POS_CASH_BALANCE:关于客户以前的销售点或现金贷款与住房贷款有关的每月数据。每一行都是前一个销售点或现金贷款的一个月,以前的一笔贷款可以有多行。
credit_card_balance:
有关之前的信用卡客户与Home Credit有关的每月数据。每行都是信用卡余额的一个月,一张信用卡可以有多行。
installments_payment:
Home Credit以前贷款的付款记录。每笔付款都有一行,每笔未付款都有一行。
下图显示了所有数据是如何相关的:
2 数据初探索
2.1 读取数据
# numpy and pandas for data manipulation
import numpy as np
import pandas as pd
# sklearn preprocessing for dealing with categorical variables
from sklearn.preprocessing import LabelEncoder
# File system manangement
import os
# Suppress warnings
import warnings
warnings.filterwarnings('ignore')
# matplotlib and seaborn for plotting
import matplotlib.pyplot as plt
import seaborn as sns
app_train = pd.read_csv('../input/application_train.csv')
app_test = pd.read_csv('../input/application_test.csv')
2.2 检查目标列的分布
app_train['TARGET'].value_counts()
app_train['TARGET'].astype(int).plot.hist();
根据这些信息,我们发现这是一个不平衡的课堂问题。 按时还款的贷款远远多于未还款的贷款。 一旦我们进入更复杂的机器学习模型,我们可以通过它们在数据中的表示来对类进行加权以反映这种不平衡。
2.3 检查缺损值
# Function to calculate missing values by column# Funct
def missing_values_table(df):
# Total missing values
mis_val = df.isnull().sum()
# Percentage of missing values
mis_val_percent = 100 * df.isnull().sum() / len(df)
# Make a table with the results
mis_val_table = pd.concat([mis_val, mis_val_percent], axis=1)
# Rename the columns
mis_val_table_ren_columns = mis_val_table.rename(
columns = {0 : 'Missing Values', 1 : '% of Total Values'})
# Sort the table by percentage of missing descending
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 some summary information
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 the dataframe with missing information
return mis_val_table_ren_columns
# Missing values statistics
missing_values = missing_values_table(app_train)
missing_values.head(20)
当需要建立我们的机器学习模型时,我们将不得不填写这些缺失值(称为插补)。 在以后的工作中,我们将使用XGBoost等模型,可以处理缺失值而不需要插补。 另一种选择是删除缺失值比例较高的列,但如果这些列对我们的模型有帮助,则不可能提前知道。 因此,我们现在将保留所有列。
2.4 查看列类型
# Number of each type of column
app_train.dtypes.value_counts()
现在我们来看看每个对象(分类)列中唯一条目的数量。
app_train.select_dtypes('object').apply(pd.Series.nunique, axis = 0)
大多数分类变量的唯一条目数量相对较少。 我们需要找到一种方法来处理这些分类变量!
2.5 编码分类变量
在我们继续前进之前,我们需要处理讨厌的分类变量。 不幸的是,机器学习模型不能处理分类变量(除了LightGBM等一些模型)。 因此,我们必须找到一种将这些变量编码(表示)为数字的方式,然后再将它们交给模型。 有两种主要的方法来执行这个过程:
- 标签编码:使用整数分配分类变量中的每个唯一类别。 没有创建新列。 一个例子如下所示:
- 单热编码:为分类变量中的每个唯一类别创建一个新列。 每个观察结果在其相应类别的列中收到1,在所有其他新列中收到0。
关于这些方法的相对优点存在一些争议,并且一些模型可以处理标签编码的分类变量而没有问题。 这是一个很好的Stack Overflow讨论。 我认为(这只是一种个人观点)对于有很多类的分类变量,单热编码是最安全的方法,因为它不会对类别强加任意值。 单热编码唯一的缺点是特征的数量(数据的维数)会随着分类变量的分类而爆炸。 为了解决这个问题,我们可以执行一个热门的编码,然后是 PCA 或其他降维方法,以减少维数(同时仍试图保留信息)。
我们将使用标签编码来处理任何仅有2个类别的分类变量,对于超过2个类别的任何分类变量使用单向编码。
2.6 标签编码和单热编码
让我们实现上面描述的策略:对于具有2个唯一类别的任何分类变量(dtype ==对象),我们将使用标签编码,对于具有多于2个唯一类别的任何分类变量,我们将使用单热编码。
对于标签编码,我们使用Scikit-Learn LabelEncoder和一个热门编码,即熊猫get_dummies(df)函数。
# Create a label encoder object
le = LabelEncoder()
le_count = 0
# Iterate through the columns
for col in app_train:
if app_train[col].dtype == 'object':
# If 2 or fewer unique categories
if len(list(app_train[col].unique())) <= 2:
# Train on the training data
le.fit(app_train[col])
# Transform both training and testing data
app_train[col] = le.transform(app_train[col])
app_test[col] = le.transform(app_test[col])
# Keep track of how many columns were label encoded
le_count += 1
print('%d columns were label encoded.' % le_count)
app_train = pd.get_dummies(app_train)
app_test = pd.get_dummies(app_test)
print('Training Features shape: ', app_train.shape)
print('Testing Features shape: ', app_test.shape)
2.7 对齐训练集和测试集
训练和测试数据中都需要具有相同的特征(列)。 一次性编码在训练数据中创建了更多列,因为有一些分类变量的类别未在测试数据中表示。 要删除训练数据中不在测试数据中的列,我们需要对齐数据框。 首先,我们从训练数据中提取目标列(因为这不在测试数据中,但我们需要保留这些信息)。 当我们进行对齐时,我们必须确保将axis = 1设置为基于列而不是在行上对齐数据框!
train_labels = app_train['TARGET']
# Align the training and testing data, keep only columns present in both dataframes
app_train, app_test = app_train.align(app_test, join = 'inner', axis = 1)
# Add the target back in
app_train['TARGET'] = train_labels
print('Training Features shape: ', app_train.shape)
print('Testing Features shape: ', app_test.shape)
3 数据分析及可视化
3.1 异常数据
在探索数据的时候需要注意的一个问题是数据中的异常情况。 这可能是由于错误的数字,测量设备的错误,或者它们可能是有效的,但极端的测量。 定量支持异常的一种方法是使用描述方法查看列的统计数据。 DAYS_BIRTH列中的数字是负数,因为它们是相对于当前贷款申请记录的。 要查看这些年份的统计数据,我们可以用-1来多项式除以一年中的天数:
(app_train['DAYS_BIRTH'] / -365).describe()
那些年龄看起来合理。 高端或低端的年龄没有异常值。 就业日期如何?
app_train['DAYS_EMPLOYED'].describe()
这看起来不正确! 最大值(除了正值)大约是1万年!
app_train['DAYS_EMPLOYED'].plot.hist(title = 'Days Employment Histogram');
plt.xlabel('Days Employment');
出于好奇,让我们对异常客户进行分类,看看他们是否倾向于比其他客户的违约率更高或更低。
anom = app_train[app_train['DAYS_EMPLOYED'] == 365243]
non_anom = app_train[app_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))
非常有趣! 事实证明,异常情况的违约率较低。
处理异常情况取决于具体情况,没有设置规则。 最安全的方法之一就是将异常设置为缺失值,然后在机器学习之前填充(使用插补)。 在这种情况下,由于所有的异常都具有完全相同的价值,我们希望用相同的价值填充它们以防所有这些贷款共享相同的东西。 异常值似乎有一些重要性,所以我们想告诉机器学习模型,如果我们确实填写了这些值。 作为一个解决方案,我们将用不是一个数字(np.nan)填充异常值,然后创建一个新的布尔列来指示值是否异常。
# Create an anomalous flag column
app_train['DAYS_EMPLOYED_ANOM'] = app_train["DAYS_EMPLOYED"] == 365243
# Replace the anomalous values with nan
app_train['DAYS_EMPLOYED'].replace({365243: np.nan}, inplace = True)
app_train['DAYS_EMPLOYED'].plot.hist(title = 'Days Employment Histogram');
plt.xlabel('Days Employment');
这个分布看起来更符合我们的预期,而且我们还创建了一个新的列,告诉模型这些值最初是异常的(因为我们将不得不用一些值填补nans,可能是中值的列)。 数据框中DAYS的其他列看起来与我们所期望的没有明显的异常值有关。
作为一个非常重要的笔记,我们对训练数据所做的任何事情,我们也必须对测试数据进行处理。 让我们确保创建新列,并在测试数据中用np.nan填充现有列。
app_test['DAYS_EMPLOYED_ANOM'] = app_test["DAYS_EMPLOYED"] == 365243
app_test["DAYS_EMPLOYED"].replace({365243: np.nan}, inplace = True)
print('There are %d anomalies in the test data out of %d entries' % (app_test["DAYS_EMPLOYED_ANOM"].sum(), len(app_test)))
3.2 相关性分析
现在我们已经处理了分类变量和异常值, 尝试和理解数据的一种方法是通过查找特征和目标之间的相关性。 我们可以使用.corr数据框方法计算每个变量和目标之间的 Pearson 相关系数。
相关系数并不是表示某个要素“相关性”的最佳方法,但它确实给了我们一个关于数据内可能关系的想法。 对相关系数绝对值的一些一般解释是:
- .00-.19 “very weak”
- .20-.39 “weak”
- .40-.59 “moderate”
- .60-.79 “strong”
- .80-1.0 “very strong”
# Find correlations with the target and sort
correlations = app_train.corr()['TARGET'].sort_values()
# Display correlations
print('Most Positive Correlations:\n', correlations.tail(15))
print('\nMost Negative Correlations:\n', correlations.head(15))
我们来看看更重要的一些相关性:DAYS_BIRTH是最正相关的。 (TARGET除外,因为变量与其本身的相关性始终为1!)查看文档,DAYS_BIRTH是负数日期内客户在贷款时间的天数(无论出于何种原因!)。 这种相关性是正向的,但是这个特征的价值实际上是负的,这意味着随着客户年龄的增长,他们不太可能违约(即目标== 0)。 这有点令人困惑,因此我们将采用该特征的绝对值,然后相关性将为负值。
3.3 年龄对还款的影响
# Find the correlation of the positive days since birth and target
app_train['DAYS_BIRTH'] = abs(app_train['DAYS_BIRTH'])
app_train['DAYS_BIRTH'].corr(app_train['TARGET'])
# Set the style of plots
plt.style.use('fivethirtyeight')
# Plot the distribution of ages in years
plt.hist(app_train['DAYS_BIRTH'] / 365, edgecolor = 'k', bins = 25)
plt.title('Age of Client'); plt.xlabel('Age (years)'); plt.ylabel('Count');
plt.figure(figsize = (10, 8))
# KDE plot of loans that were repaid on time
sns.kdeplot(app_train.loc[app_train['TARGET'] == 0, 'DAYS_BIRTH'] / 365, label = 'target == 0')
# KDE plot of loans which were not repaid on time
sns.kdeplot(app_train.loc[app_train['TARGET'] == 1, 'DAYS_BIRTH'] / 365, label = 'target == 1')
# Labeling of plot
plt.xlabel('Age (years)'); plt.ylabel('Density'); plt.title('Distribution of Ages');
为了制作这个图表,我们首先将年龄类别分为5年的垃圾箱。 然后,对于每个垃圾箱,我们计算目标的平均值,它告诉我们在每个年龄段中没有偿还的贷款的比例。
# Age information into a separate dataframe
age_data = app_train[['TARGET', 'DAYS_BIRTH']]
age_data['YEARS_BIRTH'] = age_data['DAYS_BIRTH'] / 365
# Bin the age data
age_data['YEARS_BINNED'] = pd.cut(age_data['YEARS_BIRTH'], bins = np.linspace(20, 70, num = 11))
age_data.head(10)
age_groups = age_data.groupby('YEARS_BINNED').mean()
age_groups
plt.figure(figsize = (8, 8))
# Graph the age bins and the average of the target as a bar plot
plt.bar(age_groups.index.astype(str), 100 * age_groups['TARGET'])
# Plot labeling
plt.xticks(rotation = 75); plt.xlabel('Age Group (years)'); plt.ylabel('Failure to Repay (%)')
plt.title('Failure to Repay by Age Group');
3.4 外部来源数据
我们来看看这些变量。
首先,我们可以显示“EXT_SOURCE”特征与目标和相互之间的相关性。
# Extract the EXT_SOURCE variables and show correlations
ext_data = app_train[['TARGET', 'EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3', 'DAYS_BIRTH']]
ext_data_corrs = ext_data.corr()
ext_data_corrs
# Extract the EXT_SOURCE variables and show correlations
ext_data = app_train[['TARGET', 'EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3', 'DAYS_BIRTH']]
ext_data_corrs = ext_data.corr()
ext_data_corrs
所有三个EXT_SOURCE特征与目标都有负相关,表明随着EXT_SOURCE的价值增加,客户更有可能偿还贷款。 我们还可以看到,DAYS_BIRTH与EXT_SOURCE_1正相关,表明可能是此分数中的一个因素是客户年龄。
接下来我们可以看一下这些目标值的颜色的分布。 这将让我们可视化这个变量对目标的影响。
plt.figure(figsize = (10, 12))
# iterate through the sources
for i, source in enumerate(['EXT_SOURCE_1', 'EXT_SOURCE_2', 'EXT_SOURCE_3']):
# create a new subplot for each source
plt.subplot(3, 1, i + 1)
# plot repaid loans
sns.kdeplot(app_train.loc[app_train['TARGET'] == 0, source], label = 'target == 0')
# plot loans that were not repaid
sns.kdeplot(app_train.loc[app_train['TARGET'] == 1, source], label = 'target == 1')
# Label the plots
plt.title('Distribution of %s by Target Value' % source)
plt.xlabel('%s' % source); plt.ylabel('Density');
plt.tight_layout(h_pad = 2.5)
Kaggle:Home Credit Default Risk 数据探索及可视化(1)的更多相关文章
- Kaggle:Home Credit Default Risk 特征工程构建及可视化(2)
博主在之前的博客 Kaggle:Home Credit Default Risk 数据探索及可视化(1) 中介绍了 Home Credit Default Risk 竞赛中一个优秀 kernel 关于 ...
- 利用python进行泰坦尼克生存预测——数据探索分析
最近一直断断续续的做这个泰坦尼克生存预测模型的练习,这个kaggle的竞赛题,网上有很多人都分享过,而且都很成熟,也有些写的非常详细,我主要是在牛人们的基础上,按照数据挖掘流程梳理思路,然后通过练习每 ...
- postgresql-分页重复数据探索
# postgresql-分页重复数据探索 ## 问题背景 许多开发和测试人员都可能遇到过列表的数据翻下一页的时候显示了上一页的数据,也就是翻页会有重复的数据. ### 如何处理? 这个问题出现的原因 ...
- python数据探索
数据质量分析 脏数据包括:缺失值:异常值:不一致的值:重复数据及含有特殊符号的数据: 1.缺失值处理 统计缺失率,缺失数 2.异常值处理 (1)简单统计量分析 (2)3Q原则 正态分布情况下,小概率事 ...
- 数据挖掘(二)用python实现数据探索:汇总统计和可视化
今天我们来讲一讲有关数据探索的问题.其实这个概念还蛮容易理解的,就是我们刚拿到数据之后对数据进行的一个探索的过程,旨在了解数据的属性与分布,发现数据一些明显的规律,这样的话一方面有助于我们进行数据预处 ...
- Python机器学习之数据探索可视化库yellowbrick
# 背景介绍 从学sklearn时,除了算法的坎要过,还得学习matplotlib可视化,对我的实践应用而言,可视化更重要一些,然而matplotlib的易用性和美观性确实不敢恭维.陆续使用过plot ...
- Python机器学习之数据探索可视化库yellowbrick-tutorial
背景介绍 从学sklearn时,除了算法的坎要过,还得学习matplotlib可视化,对我的实践应用而言,可视化更重要一些,然而matplotlib的易用性和美观性确实不敢恭维.陆续使用过plotly ...
- python数据挖掘之数据探索第一篇
目录 数据质量分析 当我们得到数据后,接下来就是要考虑样本数据集的数据和质量是否满足建模的要求?是否出现不想要的数据?能不能直接看出一些规律或趋势?每个因素之间的关系是什么? 通过检验数据集的 ...
- python数据探索与数据与清洗概述
数据探索的核心: 1.数据质量分析(跟数据清洗密切联系,缺失值.异常值等) 2.数据特征分析(分布.对比.周期性.相关性.常见统计量等) 数据清洗的步骤: 1.缺失值处理(通过describe与len ...
随机推荐
- WDA基础七:TABStrip
这个组件很少用. 一般用这个,是为了页面好看,还有就是布局排版的问题,因为多个页签其实占的是一块地... 新建ELEMENT TABStrip,右键tabstrip,插入页签,需要几个加几个... 加 ...
- mongodb副本集用户权限设置
mongodb副本集用户权限设置 用户权限参考文章 一:先看看MongoDB中用户的角色说明 read : 数据库的只读权限,包括: aggregate,checkShardingIndex, ...
- [hdu 6191] Query on A Tree
Query on A Tree Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Othe ...
- MYSQL--服务器的安装
MYSQL--服务器的安装 学java已经好久了,但是还是没有学会安装数据库,这次重装系统后自己学了学,昨天晚上刚刚装好,卸载了,再装一次,就想着把它笔记下来.要不又忘了.. 1.删除你的服务.在cm ...
- pip安装报错处理+PyPi源切换教程
一.pip安装出错类型 1.1 pip版本过旧导致不能安装 报错提示: You are using pip version 9.0.3, however version 10.0.1 is avail ...
- Java并发编程(五)JVM指令重排
我是不是学了一门假的java...... 引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序:在特定情况下,指令重排将会给我们的程序带来不确定的结果.. ...
- WordDenified.exportedUI
<mso:cmd app="Word" dt="1" /><mso:customUI xmlns:x1="xuzaAzWord&qu ...
- ubuntu 双硬盘挂载 windows分区自动挂载
sudo fdisk -l 查看硬盘情况 1:新建一个目录,例:old 2:mount /dev/sdb1 old 3:cd old 4:ls (就可以看到新硬盘的内容了) 取消挂载:umoun ...
- python常用
列出当前目录 import os: print os.getcwd() python load .mat variable a import scipy.io as sp tmp=sp.loadmat ...
- 分布式锁与实现(一)基于Redis实现
目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency).可用性( ...