数据清洗是机器学习项目中最为琐碎而又繁重的工作之一,下面总结一些经常用到的数据清洗方法与Python实现,以探索能否用更加自动化的手段来简化数据清洗工作。
1.缺失值处理
2.格式内容清洗
3.重复值处理
4.不一致数据处理
5.错误数据处理
6.离群点处理
7.高杠杆点处理
8.强影响点处理
缺失值是最常见的数据问题之一,按缺失比例,我们大致可以将数据的缺失分为两种情况:
1)严重缺失
这种情况首先尝试从其他渠道获取缺失的数据;
或尝试从其他数据中间接获取缺失的数据;
如果实在无法获取,只好删除该条数据;
2)少量缺失
当缺失数据不重要且数据量较大,删除该数据没有太大影响时,可以直接删除;
否则应当采取填充的方式处理缺失值,填充方法有以下几种:
a.人工填充:当数据量较小时,可以人工根据业务经验填充缺失值
b.全局变量填充:将缺失的数据值用常量或“unknown”等标记填写,但需要注意的是当用“unknown”时,算法会把“unknown”也当做一种数据特征,除非在业务中数据的缺失代表某种实际意义,否则很少采用这种填充方式
c.使用中心度量填充:如均值或中位数,对于正态分布的数据可以采用均值填充,偏态数据可以用中位数填充,可以采用全量数据的中心度量值,也可以采用与缺失值同一类别等下的中心度量值填充
d.邻近值填充:如时序中用缺失值前面(或后面)一个节点的数据填充。
e.机器学习方法估计缺失值:如用回归、贝叶斯、决策树等算法来预测缺失值
####检查数据集的缺失率
def missing_ratio(df):
"""
输入dataframe数据集,返回数据集各列的缺失比例,字典形式
:return:
"""
dict_columns = {} #定义列名和缺失比例字典
colunm_name = [i for i in df.columns][:-1] #不算最后一列标签列
for i in colunm_name: # 遍历所有的列; 循环次数为列的次数
missing_rate = (df.shape[0] - df[i].count()) * 1.0 / len(df.index) # 计算缺失率
dict_columns[i]=missing_rate
return dict_columns
####删除方式处理缺失值
def delete_missing(df,missing_ratio,thresh_loss_rate):
"""
删除缺失率超过阈值的列(特征列,不包括标签列),然后判断标签列是否有缺失值,有的化整行删除
:param df:原数据集
:param missing_ratio:missing_ratio函数的输出,字典,数据集各列的缺失比例
:param thresh_loss_rate:缺失率阈值,float
:return: 做删除操作后的dataframe
"""
for key in missing_ratio:
if missing_ratio[key] > thresh_loss_rate:
df.drop(['key'], axis=1)
colunm_name = [i for i in df.columns][-1]
index_missing = [int(i) for i in
df[colunm_name].index[np.where(np.isnan(df[colunm_name]))[0]].tolist()]
for i in index_missing:
df.drop(index = i, axis=0,inplace=True )
return df
####用常量填充缺失值
def constant_fill(fill_dict,df):
"""
用常量填充缺失值,可以用一个常量填充所有缺失值,也可以用多个常量分别填充多列缺失值
:param fill_dict: 可以是常数,当是常数时将填充所有缺失值;可以是字典,key是列名,值是填充内容,这种模型下将对缺失值列按字典分别填充
:param df:被填充的数据集
:return: 填充后的数据集
"""
df.fillna(fill_dict,inplace=True )
return df
####用均值(数值型)和众数(字符型)填充缺失值
def average_mode_fill(df):
"""
判断各字段数据类型,如果是数值型,求列均值,并用均值填充缺失值,如果非数值型,求列众数,用众数填充缺失值
:param df:
:return:
"""
from pandas.api.types import is_numeric_dtype
for key in df.columns.tolist():
if is_numeric_dtype(df[key]): #如果列为数值型
average_item = df[key].mean() #求列均值
df.fillna({key,average_item}, inplace=True) #用均值填充缺失
else:
mode_item = df[key].mode() .tolist()[0] # 求列均值
df.fillna({key:mode_item}, inplace=True) # 用均值填充缺失
return df
####前向插补或后向插补
def nerghbor_fill(df,type ="ffill"):
"""
前向,后向插补法,用缺失值的前一个值或后一个值插补
:param df: 待插补的数据集
:param type:
:return: 当type= ffill是后向插补,type= bfill是前向插补
"""
if type == "forth":
df.fillna(method = "ffill", inplace=True)
elif type == "bfill":
df.fillna(method = "bfill", inplace=True)
return df
(机器学习插补法代码待补充)
当数据是由多人录入,或来自于异构数据源等情况时,往往存在数据格式或内容不统一的情况;这种不一致通常体现在:
a.字段格式不统一:如时间或日期格式的存储形式不一致;字符型、数值型、浮点型数据混合或滥用;全半角不一致等。
b.字段内容不统一:如有的值有空格有的没有空格,有的名称类的字段存在一个实体多种叫法的现象等。
c.内容与字段定义不符:姓名写了性别,身份证号写了手机号等等
并不是所有数据都能对重复数据采用直接删除的方法解决;实际情况中,常常存在两个重复数据,因为空格,小数点位数,叫法不同等原因,导致我们没办法直接发现他们重复,因此在做重复值删除之前,要先对数据的格式内容进行统一化。
即同一数据集中的同一实体的属性存在相互矛盾的数据值,这一点要结合业务实际考虑,如同一件商品出现两种价格,这可能跟商品的规格、服务项目、促销等因素有关;也可能是数据的量纲不同;或标准不同等原因导致的;当然也有可能 是单纯的数据错误。当不一致数据是复杂业务逻辑的产物,并且对模型是必要的时候,可以保留矛盾数据。当数据矛盾是单纯的数据错误应删除数据;当数据矛盾由数据量纲、等级等信息差原因导致时,应制定统一标准,对数据进行规范。
错误数据指逻辑上不成立的数据,如年龄为200岁,身高为300cm等,可以直接删除该条数据,或采用缺失值填补的办法进行填充。
离群点通常指残差非常大的点,模型预测的y值与真实的y值相差非常大。对离群点,我们一般会选择删除方法,删除离群点还有利于提高数据集对于正态分布假设的拟合度。
检查离群点方法有:用QQ图检测,落在置信区间外的点通常被认为是离群点;或标准化残差的绝对值大于2的点可能是离群点,也有资料说是大于3,可视情况而定;
(离群点检查代码待补充)
高杠杆值点指的是x值比较异常,通常与响应变量值y没有关系。判断高杠杆值点的方法,是计算点的帽子统计量,若该点的帽子统计量大于帽子统计量的均值的2或3倍,通常被认为是高杠杆值点。
(高杠杆点检查代码待补充)
强影响点是对模型有较大影响的点,如果删除该点能改变拟合回归方程。高杠杆值点,若是离群点,则是强影响点。当然强影响点也不局限于此,强影响点是指对统计推断有影响的点,一般用cook距离进行判断,若cook距离的值大于4/(n-k-1),则表明是强影响点。Cook距离直接总结了去除某一个数据点之后,其他样本拟合值的变化,相当于综合了残差和杠杆值的信息。
(强影响点检查代码待补充)
参考文献
关于数据清洗的步骤及方法的理解https://blog.csdn.net/wyqwilliam/article/details/84801095