金融风控训练营Task02基础知识学习笔记——EDA探索性数据分析

一、学习知识点概要

  • 学习如何对数据集整体概况进行分析,包括数据集的基本情况(缺失值,异常值)
  • 学习了解变量间的相互关系、变量与预测值之间的存在关系

二、学习内容及问题与解答

1.读取文件的拓展知识:

  • pandas读取数据时相对路径载入报错时,尝试使用os.getcwd()查看当前工作目录。
  • TSV与CSV的区别:
    • 从名称上即可知道,TSV是用制表符(Tab,’\t’)作为字段值的分隔符;CSV是用半角逗号(’,’)作为字段值的分隔符;
    • Python对TSV文件的支持: Python的csv模块准确的讲应该叫做dsv模块,因为它实际上是支持范式的分隔符分隔值文件(DSV,delimiter-separated values)的。 delimiter参数值默认为半角逗号,即默认将被处理文件视为CSV。当delimiter=’\t’时,被处理文件就是TSV。
    • 读取文件的部分(适用于文件特别大的场景)
      • 通过nrows参数,来设置读取文件的前多少行,nrows是一个大于等于0的整数。
      • 分块读取
#通过nrows参数,来设置读取文件的前多少行,nrows是一个大于等于0的整数。

data_train_sample = pd.read_csv("train.csv",nrows=5)
print('data_train_sample=',data_train_sample)

结果:在这里插入图片描述

#分块读取

#设置chunksize参数,来控制每次迭代数据的大小
i = 0  # 控制输出
chunker = pd.read_csv("train.csv",chunksize=5)
for item in chunker:
    print(type(item))
    #<class 'pandas.core.frame.DataFrame'>
    print(len(item))
    i+=1
    if i >= 4:   # 由于数据量过大,限制输出4条就跳出循环
        break
    #5
    
print('chunker=',chunker)

结果:在这里插入图片描述

2.总体了解:

(省略读取文件部分)

①查看数据集的样本个数和原始特征维度

直接用.shape可以快速读取矩阵的形状
直接用.column可以快去获取矩阵的列名

print(data_test_a.shape)
print(data_test_a.columns)

print(data_train.shape)
print(data_train.columns)

结果:在这里插入图片描述

②通过info()来熟悉数据类型

print(data_train.info())

结果:
在这里插入图片描述在这里插入图片描述

③总体粗略的查看数据集各个特征的一些基本统计量

import pandas as pd
data_train = pd.read_csv('train.csv')
data_test_a = pd.read_csv('testA.csv')


print(data_train.describe())

print(data_train.head(3).append(data_train.tail(3)))

结果:
在这里插入图片描述

3.查看数据集中特征缺失值、唯一值等

①查看缺失值

print(f'There are {data_train.isnull().any().sum()} columns in train dataset with missing values.')

结果:
在这里插入图片描述

②上面得到训练集有22列特征有缺失值,进一步查看缺失特征中缺失率大于50%的特征

have_null_fea_dict = (data_train.isnull().sum()/len(data_train)).to_dict()
fea_null_moreThanHalf = {}
for key,value in have_null_fea_dict.items():
    if value > 0.5:
        fea_null_moreThanHalf[key] = value
print(fea_null_moreThanHalf)

结果:在这里插入图片描述

③具体查看缺失特征及缺失率

# nan可视化
missing = data_train.isnull().sum()/len(data_train)
missing = missing[missing > 0]
missing.sort_values(inplace=True)
missing.plot.bar()

结果:在这里插入图片描述
纵向:了解哪些列存在 “nan”, 并可以把nan的个数打印,主要的目的在于查看某一列nan存在的个数是否真的很大,如果nan存在的过多,说明这一列对label的影响几乎不起作用了,可以考虑删掉。如果缺失值很小一般可以选择填充。
横向:进行比较,如果在数据集中,某些样本数据的大部分列都是缺失的且样本足够的情况下可以考虑删除

④查看训练集测试集中特征属性只有一值的特征

one_value_fea = [col for col in data_train.columns if data_train[col].nunique() <= 1]
print(one_value_fea)
one_value_fea_test = [col for col in data_test_a.columns if data_test_a[col].nunique() <= 1]
print(one_value_fea_test)

print(f'There are {len(one_value_fea)} columns in train dataset with one unique value.')
print(f'There are {len(one_value_fea_test)} columns in test dataset with one unique value.')

结果:
在这里插入图片描述

④查看特征的数值类型、对象类型分别有哪些

  • 特征一般都是由类别型特征和数值型特征组成,而数值型特征又分为连续型和离散型。
  • 类别型特征有时具有非数值关系,有时也具有数值关系。比如‘grade’中的等级A,B,C等,是否只是单纯的分类,还是A优于其他要结合业务判断。
  • 数值型特征本是可以直接入模的,但往往风控人员要对其做分箱,转化为WOE编码进而做标准评分卡等操作。从模型效果上来看,特征分箱主要是为了降低变量的复杂性,减少变量噪音对模型的影响,提高自变量和因变量的相关度。从而使模型更加稳定。
# 数值类型
numerical_fea = list(data_train.select_dtypes(exclude=['object']).columns)
print(numerical_fea)

# 对象类型
category_fea = list(filter(lambda x: x not in numerical_fea,list(data_train.columns)))
print(category_fea)

结果:这里是引用

print(data_train.grade)

结果:
在这里插入图片描述

⑤过滤数值型类别特征,分出离散型和连续型数据

numerical_fea = list(data_train.select_dtypes(exclude=['object']).columns)
category_fea = list(filter(lambda x: x not in numerical_fea,list(data_train.columns)))

#过滤数值型类别特征
def get_numerical_serial_fea(data,feas):
    numerical_serial_fea = []
    numerical_noserial_fea = []
    for fea in feas:
        # Pandas nunique() 用于获取唯一值的统计次数。
        # 统计“fea”列中不同值的个数,不包括null值
        temp = data[fea].nunique()
        if temp <= 10:
            # 不同值的个数小于等于10,归为离散型数据
            numerical_noserial_fea.append(fea)
            continue
        # 不同值的个数大于10,归为连续型数据
        numerical_serial_fea.append(fea)
    return numerical_serial_fea,numerical_noserial_fea

numerical_serial_fea,numerical_noserial_fea = get_numerical_serial_fea(data_train,numerical_fea)


print(numerical_serial_fea)
print(numerical_noserial_fea)

结果:在这里插入图片描述

⑥查看具体的离散型数据及其重复出现的次数

value_counts函数:
value_counts(normalize=False, sort=True, ascending=False, bins=None, dropna=True)
是一种查看表格某列中有多少个不同值的快捷方法,并计算每个不同值有在该列中个数,类似Excel里面的count函数,能快速找出重复出现的值。
value_counts()并不是未带任何参数,而是所有参数都是默认的,也就是说,会默认显示数字形式,默认排序,默认降序,默认删除na

参数:

1.normalize : boolean, default False 默认false,如为true,则以百分比的形式显示

2.sort : boolean, default True 默认为true,会对结果进行排序

3.ascending : boolean, default False 默认降序排序

4.bins : integer, 格式(bins=1),意义不是执行计算,而是把它们分成半开放的数据集合,只适用于数字数据

5.dropna : boolean, default True 默认删除na值

print(data_train['term'].value_counts())#离散型变量
print("===========================================")
print(data_train['homeOwnership'].value_counts())#离散型变量
print("===========================================")
print(data_train['verificationStatus'].value_counts())#离散型变量
print("===========================================")
print(data_train['initialListStatus'].value_counts())#离散型变量
print("===========================================")
print(data_train['applicationType'].value_counts())#离散型变量  
print("===========================================")
print(data_train['policyCode'].value_counts())#离散型变量,无用,全部一个值
print("===========================================")
print(data_train['n11'].value_counts())#离散型变量,相差悬殊,用不用再分析
print("===========================================")
print(data_train['n12'].value_counts())#离散型变量,相差悬殊,用不用再分析

结果:
在这里插入图片描述
在这里插入图片描述

⑦数值连续型变量分析

numerical_fea = list(data_train.select_dtypes(exclude=['object']).columns)
category_fea = list(filter(lambda x: x not in numerical_fea,list(data_train.columns)))

#过滤数值型类别特征
def get_numerical_serial_fea(data,feas):
    numerical_serial_fea = []
    numerical_noserial_fea = []
    for fea in feas:
        # Pandas nunique() 用于获取唯一值的统计次数。
        # 统计“fea”列中不同值的个数,不包括null值
        temp = data[fea].nunique()
        if temp <= 10:
            # 不同值的个数小于等于10,归为离散型数据
            numerical_noserial_fea.append(fea)
            continue
        # 不同值的个数大于10,归为连续型数据
        numerical_serial_fea.append(fea)
    return numerical_serial_fea,numerical_noserial_fea

numerical_serial_fea,numerical_noserial_fea = get_numerical_serial_fea(data_train,numerical_fea)


#每个数字特征的分布可视化
# 这里画图估计需要10-15分钟
f = pd.melt(data_train, value_vars=numerical_serial_fea)
g = sns.FacetGrid(f, col="variable",  col_wrap=2, sharex=False, sharey=False)
g = g.map(sns.distplot, "value")

结果:
在这里插入图片描述
在这里插入图片描述
还未找到解决办法,正确结果应如下:
在这里插入图片描述
解决:

tips:

  • 查看某一个数值型变量的分布,查看变量是否符合正态分布,如果不符合正太分布的变量可以log化后再观察下是否符合正态分布。
  • 如果想统一处理一批数据变标准化 必须把这些之前已经正态化的数据提出
  • 正态化的原因:一些情况下正态非正态可以让模型更快的收敛,一些模型要求数据正态(eg. GMM、KNN),保证数据不要过偏态即可,过于偏态可能会影响模型预测结果。
#Ploting Transaction Amount Values Distribution
plt.figure(figsize=(16,12))
plt.suptitle('Transaction Values Distribution', fontsize=22)
plt.subplot(221)
sub_plot_1 = sns.distplot(data_train['loanAmnt'])
sub_plot_1.set_title("loanAmnt Distribuition", fontsize=18)
sub_plot_1.set_xlabel("")
sub_plot_1.set_ylabel("Probability", fontsize=15)

plt.subplot(222)
sub_plot_2 = sns.distplot(np.log(data_train['loanAmnt']))
sub_plot_2.set_title("loanAmnt (Log) Distribuition", fontsize=18)
sub_plot_2.set_xlabel("")
sub_plot_2.set_ylabel("Probability", fontsize=15)

结果:在这里插入图片描述
⑧非数值类别型变量分析

print(data_train['grade'].value_counts())
print("=================================")
print(data_train['subGrade'].value_counts())
print("=================================")
print(data_train['employmentLength'].value_counts())
print("=================================")
print(data_train['issueDate'].value_counts())
print("=================================")
print(data_train['earliesCreditLine'].value_counts())
print("=================================")
print(data_train['isDefault'].value_counts())

结果:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

tips:

  • 上面我们用value_counts()等函数看了特征属性的分布,但是图表是概括原始信息最便捷的方式。
  • 数无形时少直觉。
  • 同一份数据集,在不同的尺度刻画上显示出来的图形反映的规律是不一样的。python将数据转化成图表,但结论是否正确需要自己保证。

4.变量分布可视化

①单一变量分布可视化

plt.figure(figsize=(8, 8))
sns.barplot(data_train["employmentLength"].value_counts(dropna=False)[:20],
            data_train["employmentLength"].value_counts(dropna=False).keys()[:20])
plt.show()

结果:
在这里插入图片描述

②根绝y值不同可视化x某个特征的分布

  • 首先查看类别型变量在不同y值上的分布
train_loan_fr = data_train.loc[data_train['isDefault'] == 1]
train_loan_nofr = data_train.loc[data_train['isDefault'] == 0]

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 8))
train_loan_fr.groupby('grade')['grade'].count().plot(kind='barh', ax=ax1, title='Count of grade fraud')
train_loan_nofr.groupby('grade')['grade'].count().plot(kind='barh', ax=ax2, title='Count of grade non-fraud')
train_loan_fr.groupby('employmentLength')['employmentLength'].count().plot(kind='barh', ax=ax3, title='Count of employmentLength fraud')
train_loan_nofr.groupby('employmentLength')['employmentLength'].count().plot(kind='barh', ax=ax4, title='Count of employmentLength non-fraud')
plt.show()

结果:在这里插入图片描述

  • 其次查看连续型变量在不同y值上的分布
fig, ((ax1, ax2)) = plt.subplots(1, 2, figsize=(15, 6))
data_train.loc[data_train['isDefault'] == 1] \
    ['loanAmnt'].apply(np.log) \
    .plot(kind='hist',
          bins=100,
          title='Log Loan Amt - Fraud',
          color='r',
          xlim=(-3, 10),
         ax= ax1)
data_train.loc[data_train['isDefault'] == 0] \
    ['loanAmnt'].apply(np.log) \
    .plot(kind='hist',
          bins=100,
          title='Log Loan Amt - Not Fraud',
          color='b',
          xlim=(-3, 10),
         ax=ax2)

结果:在这里插入图片描述

total = len(data_train)
total_amt = data_train.groupby(['isDefault'])['loanAmnt'].sum().sum()
plt.figure(figsize=(12,5))
plt.subplot(121)##1代表行,2代表列,所以一共有2个图,1代表此时绘制第一个图。
plot_tr = sns.countplot(x='isDefault',data=data_train)#data_train‘isDefault’这个特征每种类别的数量**
plot_tr.set_title("Fraud Loan Distribution \n 0: good user | 1: bad user", fontsize=14)
plot_tr.set_xlabel("Is fraud by count", fontsize=16)
plot_tr.set_ylabel('Count', fontsize=16)
for p in plot_tr.patches:
    height = p.get_height()
    plot_tr.text(p.get_x()+p.get_width()/2.,
            height + 3,
            '{:1.2f}%'.format(height/total*100),
            ha="center", fontsize=15) 
    
percent_amt = (data_train.groupby(['isDefault'])['loanAmnt'].sum())
percent_amt = percent_amt.reset_index()
plt.subplot(122)
plot_tr_2 = sns.barplot(x='isDefault', y='loanAmnt',  dodge=True, data=percent_amt)
plot_tr_2.set_title("Total Amount in loanAmnt  \n 0: good user | 1: bad user", fontsize=14)
plot_tr_2.set_xlabel("Is fraud by percent", fontsize=16)
plot_tr_2.set_ylabel('Total Loan Amount Scalar', fontsize=16)
for p in plot_tr_2.patches:
    height = p.get_height()
    plot_tr_2.text(p.get_x()+p.get_width()/2.,
            height + 3,
            '{:1.2f}%'.format(height/total_amt * 100),
            ha="center", fontsize=15)     

结果:在这里插入图片描述

5.时间格式数据处理及查看

#转化成时间格式  issueDateDT特征表示数据日期离数据集中日期最早的日期(2007-06-01)的天数
data_train['issueDate'] = pd.to_datetime(data_train['issueDate'],format='%Y-%m-%d')
startdate = datetime.datetime.strptime('2007-06-01', '%Y-%m-%d')
data_train['issueDateDT'] = data_train['issueDate'].apply(lambda x: x-startdate).dt.days
    
#转化成时间格式
data_test_a['issueDate'] = pd.to_datetime(data_train['issueDate'],format='%Y-%m-%d')
startdate = datetime.datetime.strptime('2007-06-01', '%Y-%m-%d')
data_test_a['issueDateDT'] = data_test_a['issueDate'].apply(lambda x: x-startdate).dt.days

plt.hist(data_train['issueDateDT'], label='train');
plt.hist(data_test_a['issueDateDT'], label='test');
plt.legend();
plt.title('Distribution of issueDateDT dates');
#train 和 test issueDateDT 日期有重叠 所以使用基于时间的分割进行验证是不明智的

结果:在这里插入图片描述

6.掌握透视图可以让我们更好的了解数据

#转化成时间格式  issueDateDT特征表示数据日期离数据集中日期最早的日期(2007-06-01)的天数
data_train['issueDate'] = pd.to_datetime(data_train['issueDate'],format='%Y-%m-%d')
startdate = datetime.datetime.strptime('2007-06-01', '%Y-%m-%d')
data_train['issueDateDT'] = data_train['issueDate'].apply(lambda x: x-startdate).dt.days
    
#转化成时间格式
data_test_a['issueDate'] = pd.to_datetime(data_train['issueDate'],format='%Y-%m-%d')
startdate = datetime.datetime.strptime('2007-06-01', '%Y-%m-%d')
data_test_a['issueDateDT'] = data_test_a['issueDate'].apply(lambda x: x-startdate).dt.days

plt.hist(data_train['issueDateDT'], label='train');
plt.hist(data_test_a['issueDateDT'], label='test');
plt.legend();
plt.title('Distribution of issueDateDT dates');
#train 和 test issueDateDT 日期有重叠 所以使用基于时间的分割进行验证是不明智的


#透视图 索引可以有多个,“columns(列)”是可选的,聚合函数aggfunc最后是被应用到了变量“values”中你所列举的项目上。
pivot = pd.pivot_table(data_train, index=['grade'], columns=['issueDateDT'], values=['loanAmnt'], aggfunc=np.sum)
print(pivot)

结果:在这里插入图片描述

7.用pandas_profiling生成数据报告

import pandas_profiling
pfr = pandas_profiling.ProfileReport(data_train)
pfr.to_file("./example.html")

结果:
在这里插入图片描述
cmd中pip install pandas_profiling之后也不行,暂未解决在这里插入图片描述

三、总结与反思

数据探索性分析是我们初步了解数据,熟悉数据为特征工程做准备的阶段,甚至很多时候EDA阶段提取出来的特征可以直接当作规则来用。可见EDA的重要性,这个阶段的主要工作还是借助于各个简单的统计量来对数据整体的了解,分析各个类型变量相互之间的关系,以及用合适的图形可视化出来直观观察。
想要真正理解并做好以上操作,还需要另外补充关于python可视化的知识。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值