其他分享
首页 > 其他分享> > 【数据分析】异常值与缺失值

【数据分析】异常值与缺失值

作者:互联网

异常值与缺失值


在这里插入图片描述

1、缺失值分析与处理

1.1 造成缺失的原因

由于数据采集设备、传输线路故障等机械原因或者记录失误等认为原因,数据缺失通常难以避免,造成缺失的原因主要有以下几种

1.2 缺失的一般处理方法

1.3 数据集介绍及缺失值填充

此处使用的Lending Club贷款数据集

Lending Club 创立于2006年,主营业务是为市场提供P2P贷款的平台中介服务,公司总部位于旧金山。因此合理地对用户进行信用等级划分对贷款业务有着至关重要的意义。

1.贷款标准

2.贷款等级
贷款分为A、B、C、D、E、F、G 7 个等级,每个等级又包含了1、2、3、4、5 五个子级。
3.主要字段说明
在这里插入图片描述

## 导入数据集
import numpy as np    # Python中进行数值计算的库
import pandas as pd    # Python中进行数据处理的库
import warnings
warnings.filterwarnings('ignore') #  忽略弹出的warnings

##读取原始数据
data=pd.read_csv('./datasets/datasets/loan.csv')
data.head(10)

一共有145个特征,40万个数据
在这里插入图片描述

## 查看数据缺失情况
missingDf=data.isnull().sum().sort_values(ascending=False).reset_index()
missingDf.columns=['feature','miss_num']
missingDf['miss_percentage']=missingDf['miss_num']/data.shape[0]  #缺失值比例
missingDf.head(10)

在这里插入图片描述

print('原始数据集144列特征中:\n')
print('有%d列特征含有缺失值'%missingDf[missingDf['miss_num']>0].shape[0])
print("有%d列的特征缺失值比例在30%%以上" % missingDf[missingDf['miss_percentage'] > 0.3].shape[0])

在这里插入图片描述
下面对数据进行填充

1.2.1 处理方法1-直接删除 适合缺失值比例过大的特征

###处理方法1-直接删除 适合缺失值比例过大的特征
thr=(1-0.3)*data.shape[0] #可以根据实际情况设定不同的阈值,此处设置为30%,则非缺失值的数量大于70%
data=data.dropna(thresh=thr,axis=1)  #若某一列数据的缺失数量超过阈值就会被删除
print('去除缺失值占比大于0.3的特征之后,当前还剩%d列特征'%(data.shape[1]))

在这里插入图片描述

### 缺失特征过多的样本可以考虑直接整行删除
data['row_missing'] = data.apply(lambda x: x.isnull().sum(), axis=1).to_frame()     # 400000万条样本,计算每条样本的缺失值列数
print(data['row_missing'].value_counts())    # 观察所有样本行的缺失值情况

在这里插入图片描述

data = data[data['row_missing'] < 35]       # 删掉缺失值大于等于35列的样本,总计4241条,约占1%
data.drop(['row_missing'], axis=1, inplace=True)    # 删掉刚刚加入原始数据集的统计列
print("去除掉缺失特征大于35列的样本之后,当前还剩%d行数据" % data.shape[0])

在这里插入图片描述

1.2.2 处理方法2–固定值填充

(此处有点问题)

以emp_length这列特征为例,它代表贷款客户的工作年限,统计可知其中有21805条缺失值,原始数据集中用'n/a'表示
print("原始数据集的emp_length特征取值情况:\n", data['emp_length'].value_counts(dropna=False))
data.loc[data['emp_length']=='n/a', 'emp_length'] = 'Unknown'    # 将emp_length特征列中的缺失值替换为特殊字符'Unknown'
print("\n使用固定值填充后emp_length特征取值情况:\n", data['emp_length'].value_counts())

在这里插入图片描述

1.2.3 处理方法3-统计值填充

数值特征通常采用其他样本的均值或中位数进行填充。以dti为例,它代表贷款人每月还款占其收入的比例(去掉百分号后的值),观察其统计信息。可知该列最大值为999.000000,很明显这是一个极大的异常值,如果对该列采用均值进行填充,会受到极端值的影响,故此处选用中位数进行填充。
当然,这种简单的方法还有提升的空间,例如像dti这种特征可以结合贷款人的收入水平(annual_inc)进行先分组后填充


print("dti特征列有%d个缺失值\n" % data['dti'].isnull().sum())
print("dti特征列的统计信息:\n", data['dti'].describe())
data['dti'].fillna(data['dti'].median(), inplace=True)    # 这里采用中位数填充
print("\n填充中位数后dti特征列的统计信息:\n", data['dti'].describe())
print("\n此时dti特征列有%d个缺失值\n" % data['dti'].isnull().sum())

在这里插入图片描述

1.2.4 处理方法4–建模填充

由于数据量太大了,电脑带不动,这里只用了部分数据
pandas.DataFrame.sample 随机选取若干行

函数名及功能
DataFrame.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None)[source]

输入参数说明

参数名称参数说明举例说明
n要抽取的行数df.sample(n=3,random_state=1)
提取3行数据列表注意,使用random_state,以确保可重复性的例子。
frac抽取行的比例例如frac=0.8,就是抽取其中80%。
df.sample(frac=0.8, replace=True, random_state=1)
replace是否为有放回抽样,True:有放回抽样False:未放回抽样True:取行数据后,可以重复放回后再取,
False:取行数据后不放回,下次取其它行数据注意:
当N>总数据容量,replace设置为值时有效
weights字符索引或概率数组axis=0:为行字符索引或概率数组
axis=1:为列字符索引或概率数组
random_stateint: 随机数发生器种子或numpy.random.RandomStaterandom_state=None,取得数据不重复
random_state=1,可以取得重复数据
axis选择抽取数据的行还是列axis=0:抽取行
axis=1:抽取列
也就是说axis=1时,在列中随机抽取n列,在axis=0时,在行中随机抽取n行。
print(data.shape)
rfDf=data.sample(frac=0.2)
print(rfDf.shape)

在这里插入图片描述

### 以revol_util(信用账户的使用率)特征为例,导入sklearn的随机森林算法预测缺失值
from sklearn.ensemble import RandomForestRegressor    


# 用revol_util特征值非空的样本构建训练集,revol_util特征值缺失的样本构建测试集
rfDf_train = rfDf.loc[rfDf['revol_util'].notnull()]
rfDf_test = rfDf.loc[rfDf['revol_util'].isnull()] 

col = ['loan_amnt', 'int_rate', 'installment', 'revol_bal', 'collection_recovery_fee']    # 原始数据集中的无缺失数值特征
# 划分训练数据和标签(label)
X = rfDf_train[col]
y = rfDf_train['revol_util']
# 训练过程
rf = RandomForestRegressor(n_estimators=100,n_jobs=-1)    # 这里重在理解过程,因此仅简单选取部分参数
rf.fit(X, y)
# 预测过程
pred = rf.predict(rfDf_test[col])
 
rfDf.loc[(rfDf['revol_util'].isnull()), 'revol_util'] = pred    # 填补缺失值
print("此时的revol_util特征统计指标:\n")
print(rfDf['revol_util'].describe())  

在这里插入图片描述


2、异常值分析处理

异常值是数据集中存在的非正常的值,也成为了离群点,异常值有可能是不正确的“脏数据”,也可能是正确的异常数据,例如人的身高100m属于不正确的脏数据。

2.1 异常值的分析判别方法

2.2 异常值的处理

2.2.1 异常值处理1–简单统计分析&删除异常值

Lending Club贷款数据集中的revol_util特征为例,它表示信用账户的使用率(去掉百分号),因此容易理解这列特征的值不应超过100。观察到异常样本有1300条,占总样本的比例很小,可以将这些样本直接删除

print(data.shape)
print("revol_util特征列的异常样本数为: ", data[data['revol_util'] > 100].shape[0])
#删除掉异常值
data.drop(data[data['revol_util']>100].index,inplace=True) #根据索引删除样本值
print(data.shape)

在这里插入图片描述

2.2.2 异常值处理2–3σ原则&均值代替异常样本

以dti特征为例,它表示贷款人每月还款占其收入的比例(去掉百分号后的值),容易理解这列特征的值不应超过100,将超过100的值视为无意义的异常值。

import seaborn as sns 
import matplotlib.pyplot as plt #可视化
%matplotlib inline

ax=sns.distplot(data['dti'],kde=True,hist=False)
plt.show()

在这里插入图片描述
可以看出来存在很长的拖尾,根据实际意义我们可以知道大于100的都是异常值,把高于100的去掉后再观察下

#去掉高于100的部分在观察
norDf=data[data['dti']<=100]
ax=sns.distplot(norDf['dti'],kde=True,hist=False)
plt.show()

在这里插入图片描述
可以观察到dti的分布近似于正态分布,根据实际情况分析,大部分贷款人的dti小于40%,还款压力较小,剩下的大于40%的可能是异常值,也可能是真的存在较大的还款压力

#根据3σ原则计算异常值区间
dti_mean = norDf['dti'].mean()    # 计算均值
dti_std = norDf['dti'].std()    # 计算方差
print("大于 %f 的可以视为异常值" % (dti_mean + 3*dti_std))
print("小于 %f 的可以视为异常值" % (dti_mean - 3*dti_std))

在这里插入图片描述

data.loc[data['dti'] > 100, 'dti'] = dti_mean    # 均值替代
print("此时dti特征列还有%d个大于100的特征值" % (data[data['dti'] > 100]).shape[0])

在这里插入图片描述

2.2.3 异常值处理3–箱型图&视为缺失值

以annual_inc为例,它表示贷款人的年收入

#绘制箱线图分析
bp_list=list(data['annual_inc'])

plt.figure(figsize=(20,4))
plt.boxplot(bp_list,
            vert=False,#改变箱线图方向
            flierprops = {"marker":"o","markerfacecolor":"steelblue"}
           )
plt.show() # 展示箱型图

在这里插入图片描述

#观察annual_inc的统计值
data['annual_inc'].describe()

在这里插入图片描述

#计算箱型图的边界
q1=data['annual_inc'].describe()['25%']
q3=data['annual_inc'].describe()['75%']
iqr=q3-q1
print("箱型图上须:", q3 + 1.5*iqr)
print("箱型图下须:", q1 - 1.5*iqr)

在这里插入图片描述
可以看出大多数贷款人的年收入都在100万以下,与Lending Club的主业中小额贷款也比较相符,可以将箱型图中的大于100万的用固定值进行替代,统一定为100万

data.loc[data['annual_inc'] > 1000000.0, 'annual_inc'] = 1000000.0    # 固定值替代
print("此时annual_inc特征列还有%d个大于100万的特征值" % (data[data['annual_inc'] > 1000000.0]).shape[0]) 

在这里插入图片描述

3、优化思路

数据预处理

参考文献

https://work.datafountain.cn/forum?id=68&type=2&source=1

标签:数据分析,dti,特征,异常,print,data,缺失
来源: https://blog.csdn.net/a8689756/article/details/117329331