一、学习知识点概要
-
数据总体了解:
- 读取数据集并了解数据集大小,原始特征维度;
- 通过info熟悉数据类型;
- 粗略查看数据集中各特征基本统计量;
- 数据质量分析:
- 查看数据缺失值情况
- 查看唯一值特征情况
- 深入分析数据类型:
- 类别型数据
- 数值型数据
- 离散数值型数据
- 连续数值型数据
- 数据间相关关系:
- 特征和特征之间关系
- 特征和目标变量之间关系
- 用pandas_profiling生成数据报告
二、学习内容
2.1 数据总体了解
- 读取数据集并了解数据集大小,原始特征维度;
- 通过info熟悉数据类型;
- 粗略查看数据集中各特征基本统计量;
2.1.1 数据集大小
- 本次数据集下载文件格式为csv格式,读取文件可采用如下方法:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import datetime
train=pd.read_csv('C://Users//Administrator//Desktop//train.csv')
testA=pd.read_csv('C://Users//Administrator//Desktop//testA.csv')
- 查看数据集大小和原始特征维度
print(train.columns) #训练集样本属性
print("训练集样本维度:",train.shape) #训练集样本维度
print("测试集A样本维度:",testA.shape) #测试集A样本维度
输出结果如下:
Index(['id', 'loanAmnt', 'term', 'interestRate', 'installment', 'grade', 'subGrade', 'employmentTitle', 'employmentLength', 'homeOwnership', 'annualIncome', 'verificationStatus', 'issueDate', 'isDefault', 'purpose', 'postCode', 'regionCode', 'dti', 'delinquency_2years', 'ficoRangeLow', 'ficoRangeHigh', 'openAcc', 'pubRec', 'pubRecBankruptcies', 'revolBal', 'revolUtil', 'totalAcc', 'initialListStatus', 'applicationType', 'earliesCreditLine', 'title', 'policyCode', 'n0', 'n1', 'n2', 'n3', 'n4', 'n5', 'n6', 'n7', 'n8', 'n9', 'n10', 'n11', 'n12', 'n13', 'n14'], dtype='object') 训练集样本维度: (800000, 47) 测试集A样本维度: (200000, 46)
2.1.2 数据类型
train.info() #查看数据类型
输出结果如下: Data columns (total 47 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 id 800000 non-null int64 1 loanAmnt 800000 non-null float64 2 term 800000 non-null int64 3 interestRate 800000 non-null float64 4 installment 800000 non-null float64 5 grade 800000 non-null object 6 subGrade 800000 non-null object 7 employmentTitle 799999 non-null float64 8 employmentLength 753201 non-null object 9 homeOwnership 800000 non-null int64 10 annualIncome 800000 non-null float64 11 verificationStatus 800000 non-null int64 12 issueDate 800000 non-null datetime64[ns] 13 isDefault 800000 non-null int64 14 purpose 800000 non-null int64 15 postCode 799999 non-null float64 16 regionCode 800000 non-null int64 17 dti 799761 non-null float64 18 delinquency_2years 800000 non-null float64 19 ficoRangeLow 800000 non-null float64 20 ficoRangeHigh 800000 non-null float64 21 openAcc 800000 non-null float64 22 pubRec 800000 non-null float64 23 pubRecBankruptcies 799595 non-null float64 24 revolBal 800000 non-null float64 25 revolUtil 799469 non-null float64 26 totalAcc 800000 non-null float64 27 initialListStatus 800000 non-null int64 28 applicationType 800000 non-null int64 29 earliesCreditLine 800000 non-null object 30 title 799999 non-null float64 31 policyCode 800000 non-null float64 32 n0 759730 non-null float64 33 n1 759730 non-null float64 34 n2 759730 non-null float64 35 n3 759730 non-null float64 36 n4 766761 non-null float64 37 n5 759730 non-null float64 38 n6 759730 non-null float64 39 n7 759730 non-null float64 40 n8 759729 non-null float64 41 n9 759730 non-null float64 42 n10 766761 non-null float64 43 n11 730248 non-null float64 44 n12 759730 non-null float64 45 n13 759730 non-null float64 46 n14 759730 non-null float64 dtypes: datetime64[ns](1), float64(33), int64(9), object(4) memory usage: 293.0+ MB
2.1.3 基本统计量
train.describe() #查看各个特征的统计量
输出结果如下:
id loanAmnt term interestRate installment employmentTitle homeOwnership annualIncome verificationStatus isDefault ... n5 n6 n7 n8 n9 n10 n11 n12 n13 n14 count 800000.000000 800000.000000 800000.000000 800000.000000 800000.000000 799999.000000 800000.000000 8.000000e+05 800000.000000 800000.000000 ... 759730.000000 759730.000000 759730.000000 759729.000000 759730.000000 766761.000000 730248.000000 759730.000000 759730.000000 759730.000000 mean 399999.500000 14416.818875 3.482745 13.238391 437.947723 72005.351714 0.614213 7.613391e+04 1.009683 0.199513 ... 8.107937 8.575994 8.282953 14.622488 5.592345 11.643896 0.000815 0.003384 0.089366 2.178606 std 230940.252015 8716.086178 0.855832 4.765757 261.460393 106585.640204 0.675749 6.894751e+04 0.782716 0.399634 ... 4.799210 7.400536 4.561689 8.124610 3.216184 5.484104 0.030075 0.062041 0.509069 1.844377 min 0.000000 500.000000 3.000000 5.310000 15.690000 0.000000 0.000000 0.000000e+00 0.000000 0.000000 ... 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 25% 199999.750000 8000.000000 3.000000 9.750000 248.450000 427.000000 0.000000 4.560000e+04 0.000000 0.000000 ... 5.000000 4.000000 5.000000 9.000000 3.000000 8.000000 0.000000 0.000000 0.000000 1.000000 50% 399999.500000 12000.000000 3.000000 12.740000 375.135000 7755.000000 1.000000 6.500000e+04 1.000000 0.000000 ... 7.000000 7.000000 7.000000 13.000000 5.000000 11.000000 0.000000 0.000000 0.000000 2.000000 75% 599999.250000 20000.000000 3.000000 15.990000 580.710000 117663.500000 1.000000 9.000000e+04 2.000000 0.000000 ... 11.000000 11.000000 10.000000 19.000000 7.000000 14.000000 0.000000 0.000000 0.000000 3.000000 max 799999.000000 40000.000000 5.000000 30.990000 1715.420000 378351.000000 5.000000 1.099920e+07 2.000000 1.000000 ... 70.000000 132.000000 79.000000 128.000000 45.000000 82.000000 4.000000 4.000000 39.000000 30.000000 8 rows × 42 columns
2.2 数据质量分析
2.2.1 缺失值
- 查看缺失值基本代码
train.isnull() ##查看数据集中各元素是否存在缺失值,存在则返回True,不存在则返回False
train.isnull().any() ##查看各列是否存在缺失值,存在则返回True,不存在则返回False
train.isnull().any().sum() ##存在缺失值的列数
train.isnull().sum() ##各列缺失值的个数
missing = train.columns[ train.isnull().any() ].tolist() ##存在缺失值的列名
train [ missing ].isnull().sum() ##存在缺失值的列及其对应缺失值的个数
- 缺失值分析
num_miss=train.isnull().any().sum() ##存在缺失值的列数
print("训练集中有",num_miss,"列存在缺失值.")
missing = train.columns[ train.isnull().any() ].tolist() ##存在缺失值的列名
train [ missing ].isnull().sum() ##存在缺失值的各列中缺失值的个数
训练集中有 22 列存在缺失值. employmentTitle 1 employmentLength 46799 postCode 1 dti 239 pubRecBankruptcies 405 revolUtil 531 title 1 n0 40270 n1 40270 n2 40270 n3 40270 n4 33239 n5 40270 n6 40270 n7 40270 n8 40271 n9 40270 n10 33239 n11 69752 n12 40270 n13 40270 n14 40270 dtype: int64
从上面的结果我们可以看到,训练集中有22列特征存在缺失值以及这些列中存在的缺失值个数,接下来则具体分析各列特征的缺失率,对于某列特征,若其缺失率过高,则其对于目标特征的基本没有太大影响,可以考虑删除该列,但如果缺失值较小一般选择填充。下面进一步查看存在缺失值的各列中缺失率大于50%的特征。
have_null_fea_dict = (train.isnull().sum()/len(train)).to_dict()
fea_null_moreThanHalf = {}
for key,value in have_null_fea_dict.items():
if value > 0.5:
fea_null_moreThanHalf[key] = value
fea_null_moreThanHalf
输出结果如下:
{ }
由此可见,该训练集中不存在缺失率大于50%的特征,我们可以作图可视化对比各列特征的缺失率
train [ missing ].isnull().sum().sort_values(inplace=True)
train [ missing ].isnull().sum().plot.bar()
输入结果如下:
2.2.2 唯一值
one_value_fea = [col for col in train.columns if train[col].nunique() <= 1]
one_value_fea_testA = [col for col in testA.columns if testA[col].nunique() <= 1]
print("训练集中唯一值特征:",one_value_fea)
print("测试集A中唯一值特征:",one_value_fea_testA)
输出结果如下:
训练集中唯一值特征: ['policyCode'] 测试集A中唯一值特征: ['policyCode']
从输出结果可以看到,数据集中'policyCode'这一列具有一个唯一值(或全部缺失)
2.3 深入分析数据类型
特征一般分为数值型(连续型、离散性)特征和类别型特征,从2.1.2查看数据类型我们已经得到了训练集中涉及到的数据类型种类及个数:float64(33), int64(9), object(5),为进一步清晰了解哪些特征属于数值型,哪些特征属于类别型,可经过如下命令查看:
numerical_fea = list(train.select_dtypes(exclude=['object']).columns)
category_fea = list(filter(lambda x: x not in numerical_fea,list(train.columns)))
print("数值型特征:\n",numerical_fea)
print("类别型特征:\n",category_fea)
数值型特征: ['id', 'loanAmnt', 'term', 'interestRate', 'installment', 'employmentTitle', 'homeOwnership', 'annualIncome', 'verificationStatus', 'isDefault', 'purpose', 'postCode', 'regionCode', 'dti', 'delinquency_2years', 'ficoRangeLow', 'ficoRangeHigh', 'openAcc', 'pubRec', 'pubRecBankruptcies', 'revolBal', 'revolUtil', 'totalAcc', 'initialListStatus', 'applicationType', 'title', 'policyCode', 'n0', 'n1', 'n2', 'n3', 'n4', 'n5', 'n6', 'n7', 'n8', 'n9', 'n10', 'n11', 'n12', 'n13', 'n14'] 类别型特征: ['grade', 'subGrade', 'employmentLength', 'issueDate', 'earliesCreditLine']
对于数值型特征又分为离散性和连续型,若定义特征中的数值不超过10个视为离散型,则可以通过以下代码区分开来:
def get_numerical_serial_fea(data,feas):
numerical_serial_fea = []
numerical_noserial_fea = []
for fea in feas:
temp = data[fea].nunique()
if temp <= 10:
numerical_noserial_fea.append(fea)
continue
numerical_serial_fea.append(fea)
return numerical_serial_fea,numerical_noserial_fea
numerical_serial_fea,numerical_noserial_fea = get_numerical_serial_fea(train,numerical_fea)
print("连续型特征:\n",numerical_serial_fea)
print("离散型特征:\n",numerical_noserial_fea)
连续型特征: ['id', 'loanAmnt', 'interestRate', 'installment', 'employmentTitle', 'annualIncome', 'purpose', 'postCode', 'regionCode', 'dti', 'delinquency_2years', 'ficoRangeLow', 'ficoRangeHigh', 'openAcc', 'pubRec', 'pubRecBankruptcies', 'revolBal', 'revolUtil', 'totalAcc', 'title', 'n0', 'n1', 'n2', 'n3', 'n4', 'n5', 'n6', 'n7', 'n8', 'n9', 'n10', 'n13', 'n14'] 离散型特征: ['term', 'homeOwnership', 'verificationStatus', 'isDefault', 'initialListStatus', 'applicationType', 'policyCode', 'n11', 'n12']
2.3.1 类别型特征分析
通过train['列名'].value_counts()可以统计类别型特征的取值及其个数,结果如下表所示:
(上图只是通过代码得到的结果整理而成的表格,对于少量数据而言还能看得过去,但对于大量数据可行性不强,下面进行图表可视化对比更加直观)
##以类别型变量'grade'为例
plt.figure(figsize=(6, 6))
sns.barplot(train["grade"].value_counts(dropna=False)[:20],
train["grade"].value_counts(dropna=False).keys()[:20])
plt.show()
2.3.2 数值离散型特征分析
通过train['列名'].value_counts()可以统计离散型数值特征的取值及其个数,结果如下表所示:
(上图只是通过代码得到的结果整理而成的表格,对于少量数据而言还能看得过去,但对于大量数据可行性不强,下面进行图表可视化对比更加直观)
从上述结果可以作初步判断,'policyCode'存在唯一值1.0,可视为无用特征;'applicationType'、'n11'和'n12'各取值相差悬殊,后面应对其进行分析考虑是否有影响。
2.3.3 数值连续型特征分析
##得到每个连续型特征的分布直方图
f = pd.melt(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")
查看某一个数值型变量的分布,查看变量是否符合正态分布,如果不符合正太分布的变量可以log化后再观察下是否符合正态分布。
如果想统一处理一批数据变标准化 必须把这些之前已经正态化的数据提出。
正态化的原因:一些情况下正态非正态可以让模型更快的收敛,一些模型要求数据正态(eg. GMM、KNN),保证数据不要过偏态即可,过于偏态可能会影响模型预测结果。
2.4 相关性分析
2.4.1 查看各特征不同标签(isDefault)下分布情况
- 类别型(离散型)
train_loan_fr = train.loc[train['isDefault'] == 1]
train_loan_nofr = train.loc[train['isDefault'] == 0]
fig, ((ax1, ax2), (ax3, ax4),(ax5, ax6),(ax7, ax8),(ax9, ax10)) = plt.subplots(5, 2, figsize=(15, 30))
train_loan_fr.groupby('grade')['grade'].count()[:20].plot(kind='barh', ax=ax1, title='Count of grade fraud')
train_loan_nofr.groupby('grade')['grade'].count()[:20].plot(kind='barh', ax=ax2, title='Count of grade non-fraud')
train_loan_fr.groupby('subGrade')['subGrade'].count()[:20].plot(kind='barh', ax=ax3, title='Count of subGrade fraud')
train_loan_nofr.groupby('subGrade')['subGrade'].count()[:20].plot(kind='barh', ax=ax4, title='Count of subGrade non-fraud')
train_loan_fr.groupby('employmentLength')['employmentLength'].count()[:20].plot(kind='barh', ax=ax5, title='Count of employmentLength fraud')
train_loan_nofr.groupby('employmentLength')['employmentLength'].count()[:20].plot(kind='barh', ax=ax6, title='Count of employmentLength non-fraud')
train_loan_fr.groupby('issueDate')['issueDate'].count()[:20].plot(kind='barh', ax=ax7, title='Count of issueDate fraud')
train_loan_nofr.groupby('issueDate')['issueDate'].count()[:20].plot(kind='barh', ax=ax8, title='Count of issueDate non-fraud')
train_loan_fr.groupby('earliesCreditLine')['earliesCreditLine'].count()[:20].plot(kind='barh', ax=ax9, title='Count of earliesCreditLine fraud')
train_loan_nofr.groupby('earliesCreditLine')['earliesCreditLine'].count()[:20].plot(kind='barh', ax=ax10, title='Count of earliesCreditLine non-fraud')
plt.show()
- 连续型
fig, ((ax1, ax2)) = plt.subplots(1, 2, figsize=(15, 6))
train.loc[train['isDefault'] == 1]['loanAmnt'].apply(np.log).plot(kind='hist',bins=100,title='Log Loan Amt - Fraud',color='r',xlim=(-3, 10),ax= ax1)
train.loc[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)
2.4.2 时间格式处理
#转化成时间格式 issueDateDT特征表示数据日期离数据集中日期最早的日期(2007-06-01)的天数
train['issueDate'] = pd.to_datetime(train['issueDate'],format='%Y-%m-%d')
startdate = datetime.datetime.strptime('2007-06-01', '%Y-%m-%d')
train['issueDateDT'] = train['issueDate'].apply(lambda x: x-startdate).dt.days
#转化成时间格式
testA['issueDate'] = pd.to_datetime(train['issueDate'],format='%Y-%m-%d')
startdate = datetime.datetime.strptime('2007-06-01', '%Y-%m-%d')
testA['issueDateDT'] = testA['issueDate'].apply(lambda x: x-startdate).dt.days
plt.hist(train['issueDateDT'], label='train');
plt.hist(testA['issueDateDT'], label='test');
plt.legend();
plt.title('Distribution of issueDateDT dates');
从图示我们可以看到,train 和 testA的issueDate日期有重叠,所以使用基于时间的分割进行验证是不明智的。
2.5 生成数据报告
Python之pandas-profiling:pandas-profiling库的简介、安装、使用方法之详细攻略
import pandas_profiling
pfr = pandas_profiling.ProfileReport(train)
pfr.to_file("./example.html")
三、学习问题与解答
3.1 各种类型文件的读取
- csv格式:read_csv()参数详情可见文章Pandas的read_csv的参数
import pandas as pd
dataframe=pd.read_csv('文件名.csv')
- Excel文件
import pandas as pd
dataframe=pd.read_excel('文件名.xlsx')
-
SQL文件:在读取mysql数据之前要将mysql的服务启动-net start mysql
import pymysql
import pandas as pd
#连接数据库为test,用户名为root,密码是123456(根据自己的数据库信息输入)
conn=pymysql.connect(host="127.0.0.1",user="root",passwd="123456",db="test")
#查询的表为students
sql="select * from students"
data=pd.read_sql(sql,conn)
print(data)
- HTML文件:
import pandas as pd
htl=pd.read_html('地址.html')
print(htl)
3.2 正态分布的基本原理
可参考此文章:数据的正态化和标准变换
四、学习思考与总结
本次学习任务了解了探索性数据分析的基本步骤,从读取数据、初步查看数据、深入了解数据、观察特征之间的相关性以及特征与标签的相关性,而这些信息均可通过可视化图表来直观获取,探索性数据分析只是对数据进行一个大体的了解,为之后的进一步分析打下基础,是数据分析中比较重要的一个环节。