前一部分我们对一些分类指标等一些预备知识进行了学习,接下来我们要进行的是探索性的数据分析(EDA)。
EDA是我们进行数据挖掘非常重要的一步,做的好的EDA可以让我们对数据作出更准确的分析,一方面是让我们了解整个数据集,包括缺失值,异常值,变量间的练习等,另一方面也是为我们之后的特征工程做好准备。
1.数据的总体了解,缺失值,唯一值
#导入需要的库
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import datetime
import warnings
%matplotlib inline
#导入我们的训练集和测试集
train_data = pd.read_csv('train.csv')
test_A_data = pd.read_csv('testA.csv')
#一些查看数据总体特征的方法
train_data.shape
train_data.info()
train_data.describe()
#先来查看训练集的缺失值
train_data.isnull() #data中的数据空变为False,非空为True
train_data.isnull().any() #判断每一列是空or非空
train_data.isnull().any().sum()#对无缺失值的列求和
#可以找出缺失量大于某个值的columns,p可更改,如果缺失过多可以直接删除列
have_null_fea_dict = (train_data.isnull().sum()/len(train_data)).to_dict()
p = 0.5
fea_null_morethanhalf = {}
for key,value in have_null_fea_dict.items():
if float(value) > p:
fea_null_morethanhalf[key] = value
#查看有缺失值的列和它们缺失的比重
missing = train_data.isnull().sum()/len(train_data)
missing = missing[missing > 0]
missing.sort_values(inplace = True)
missing.plot.bar()
了解哪些列存在 “nan”, 并可以把nan的个数打印,主要的目的在于 nan存在的个数是否真的很大,如果很小一般选择填充,如果使用lgb等树模型可以直接空缺,让树自己去优化,但如果nan存在的过多、可以考虑删掉.
#查看数据集中的特征是否只有一个值(唯一值)
one_value_fea = [col for col in train_data.columns if train_data[col].nunique() <= 1]
one_value_fea
#['policyCode']
2.查看数据的数值类型和对象类型
- 特征一般分为数值型和类别型。类别型有可能具有数值关系,有时不具有。
- 数值型特征可以直接入模,但一般都要进行分箱,目的是降低变量复杂性,减少变量噪音的影响,提高自变量和因变量的相关性,使模型更加稳定。
#分别提取数值型特征和类别型特征
numerical_fea = list(train_data.select_dtypes(exclude=['object']).columns)
category_fea = list(train_data.select_dtypes(include = ['object']).columns)
category_fea
# ['grade', 'subGrade', 'employmentLength', 'issueDate', 'earliesCreditLine']
#划分数值型变量中的连续变量和分类变量
#我们把数字型变量里数字类别<=10的特征当作类别型数值变量
def split_numerical_or_not(data,feas):
numerical_Series_fea = []
numerical_noSeries_fea = []
for fea in feas:
if data[fea].nunique() <= 10:
numerical_noSeries_fea.append(fea)
else:
numerical_Series_fea.append(fea)
return numerical_Series_fea,numerical_noSeries_fea
numerical_series_fea,numerical_noseries_fea = split_numerical_or_not(train_data,numerical_fea)
#分离出来之后对数值类别型特征进行一些简单的分析
for col in numerical_noseries_fea:
print(train_data[col].value_counts(),'\n')
'''
results:
3 606902
5 193098
Name: term, dtype: int64
0 395732
1 317660
2 86309
3 185
5 81
4 33
Name: homeOwnership, dtype: int64
1 309810
2 248968
0 241222
Name: verificationStatus, dtype: int64
0 640390
1 159610
Name: isDefault, dtype: int64
0 466438
1 333562
Name: initialListStatus, dtype: int64
0 784586
1 15414
Name: applicationType, dtype: int64
1.0 800000
Name: policyCode, dtype: int64 (这个数据只有一个值,没有用)
0.0 729682
1.0 540
2.0 24
4.0 1
3.0 1
Name: n11, dtype: int64 (数据相差悬殊,没什么用)
0.0 757315
1.0 2281
2.0 115
3.0 16
4.0 3
Name: n12, dtype: int64 (数据相差悬殊,没什么用)
'''
#接下来对数值型的连续型特征进行分析
#melt是将宽数据变为长数据,value_vars:需要转变的变量
f = pd.melt(train_data,value_vars=numerical_series_fea)
#FacetGrid:引入数据,布置横向画布
g = sns.FacetGrid(f,col = 'variable' , col_wrap=2 , sharex=False , sharey=False)
#map:填充数据进入
g = g.map(sns.distplot,'value')
- 查看某一个数值型变量的分布,查看变量是否符合正态分布,如果不符合正态分布的变量可以log化后再观察下是否符合正态分布。
- 如果想统一处理一批数据变标准化 必须把这些之前已经正态化的数据提出
#绘制一个交易金额的值的分布图
#设置一个画布
plt.figure(figsize=(16,12))
#设置标题
plt.suptitle('Transaction Amount Distribution',fontsize = 22)
#画出loanAmnt的概率分布子图 displot:直方图和密度图的结合
plt.subplot(221)
subplot_1 = sns.distplot(train_data['loanAmnt'])
subplot_1.set_title('Loan Amount Distribution',fontsize = 18)
subplot_1.set_xlabel('')
subplot_1.set_ylabel('probability')
#画出loanAmnt log后的子图
plt.subplot(222)
subplot_2 = sns.distplot(np.log(train_data['loanAmnt']))
subplot_2.set_title('(Log) Loan Amount Distribution',fontsize = 18)
subplot_2.set_xlabel('')
subplot_2.set_ylabel('probability')
接下来对一些非数值型的特征做一些分析
#先看看有哪些特征
category_fea
#简单看看各个特征的每个值的数量
train_data['grade'].value_counts()
train_data['subGrade'].value_counts()
train_data['employmentLength'].value_counts()
train_data['issueDate'].value_counts()
train_data['earliesCreditLine'].value_counts()
3.变量的可视化分析
#但一变量的可视化分布
#准备画布
plt.figure(figsize=(16,12))
#barplot:条形图
sns.barplot(train_data['employmentLength'].value_counts(dropna = False),
train_data['employmentLength'].value_counts(dropna = False).keys())
plt.show()
#对于不同y值的类型特征进行一些可视化分析
train_loan_fr = train_data.loc[train_data['isDefault'] == 1]
train_loan_nofr = train_data.loc[train_data['isDefault'] == 0]
#对于isdefault对等级和就业年限的可视化分析
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')
#对于不同y值的数值特征进行一些可视化分析
fig,((ax1,ax2)) = plt.subplots(1,2,figsize = (12,8))
train_data.loc[train_data['isDefault'] == 1]['loanAmnt'].apply(np.log).plot(kind = 'hist', color = 'r', bins = 100, ax = ax1, xlim = (-3,10), title = 'Count of loanAmnt fraud')
train_data.loc[train_data['isDefault'] == 0]['loanAmnt'].apply(np.log).plot(kind = 'hist', color = 'b', bins = 100, ax = ax2, xlim = (-3,10), title = 'Count of loanAmnt non-fraud')
下面这段还要再仔细看看
total = len(train_data)
total_amt = train_data.groupby(['isDefault'])['loanAmnt'].sum().sum()
plt.figure(figsize=(12,5))
plt.subplot(121)##1代表行,2代表列,所以一共有2个图,1代表此时绘制第一个图。
plot_tr = sns.countplot(x='isDefault',data=train_data)#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 = (train_data.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)
4.时间格式的数据处理
#训练集中的issuedate的格式转换,将日期转换为距离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
5.数据透视表
##透视表pivot_table 索引可以有多个,“columns(列)”是可选的,聚合函数aggfunc最后是被应用到了变量“values”中你所列举的项目上。
pivot = pd.pivot_table(train_data, index = ['grade'], columns=['issueDateDT'],values =['loanAmnt'],aggfunc=np.sum)
pivot
6.生成数据报告
import pandas_profiling
pfr = pandas_profiling.ProfileReport(data_train)
pfr.to_file("./data_report.html")