Python数据清洗 | 常用的数据清洗方法
常用的数据清洗方法
该文章首次发布于微信公众号《Python希望社》
在数据处理的通常情况下, 一般都会执行数据预处理步骤, 包括检查数据集是否存在重复性问题、是否存在问题以及是否具有完整的性和一致性, 同时还需关注是否存在不规则数据. 当发现数据中存在上述提到的问题时, 通常会采取相应的措施.
本文大纲如下: 全文共5746字。
认真阅读本文你将掌握常用的数据清洗方法和策略
常用的数据清洗方法
重复观测处理
检测
处理
缺失值处理
数据过滤/删除法dropna
数据填充 / 替换法fillna
插值法
异常值处理
异常值检测
异常值处理及其前后对比
一、重复观测处理
所谓重复观测现象是指同一观察单元在不同时间或不同条件下出现多次记录的情况;这种现象可能会影响数据分析结果的有效性;因此,在开展数据分析与模型建立前必须对数据中的重复现象进行检测;当发现有重复现象时,则应采取措施去除多余的记录
1.1处理方法
(1)检测重复观测
pandas库中包含duplicated方法,在处理数据时该方法会被用来检测是否存在重复项;该方法会生成一个布尔类型的判断结果,并针对每一行数据单独进行标记;
(2)处理重复观测
使用drop_duplicated方法移除重复值。
1.2 案例展示(电商类APP相关数据)
(1)待清洗的原始数据
原始数据
可以看出,**浅绿色 ** 突出显示数据行为重复观测示例。为此进行如下处理:
(2)重复观测处理示例
[外链图片无法存储,可能存在防盗链机制,建议您将图片保存到本地设备后再进行上传操作(文件路径为F:\Typroa\微信公众号\1-向希望\数据清洗\2.gif)]
(3)源码
import pandas as pd
# load data
data = pd.read_excel('1.xlsx')
data
#----------------------------------------------------
# 判断是否存在重复观测
print('是否存在重复观测:',any(data.duplicated()))
#----------------------------------------------------
# 处理重复观测
data.drop_duplicates(inplace=True) # inplace=True时直接删除data中重复的数据
data
#----------------------------------------------------
## 将处理后的数据 重新保存
f = pd.ExcelWriter('data_processed.xlsx') # 创建文件对象
data.to_excel(f) # 将处理后的data写入新建的excel中
f.save() # 保存文件
二、缺失值处理
在多数数据分析场景中都会遇到数据缺失的问题,在大多数情况下都会遇到这样的问题。在Pandas库中采用NaN值来表示无论是浮点型还是非浮点型数组中的缺少信息,在Python语言内置的数据类型中,默认也将会被视为处理这类问题的方法之一。
2.1 检测数据缺失
Pandas提供了功能用于判断数据框或数组中的每个元素是否存在缺失值,并将结果以布尔类型值的形式返回。
结果演示:
外部链接存储的图片无法正常访问,请确保您将图片保存后直接上传至该平台;建议您参考类似资源以获取替代方案
根据上述分析可知:在数据集中data中被检测到的第2个和第4个样本被归类为缺失值。
# 导入包库
import numpy as np
import pandas as pd
# 生成原始测试数据
data = pd.Series([10.0, None, 20,np.NaN, 30])
data
#----------------------------------------------------
print(data.isnull())
#----------------------------------------------------
print("是否存在缺失值:",any(data.isnull()))
2.2 处理数据缺失
对于缺失值通常采用过滤法、填充法和插值法。在这里我们将详细阐述每种方法的具体内容以及案例分析,并附上相关代码。
(1)数据过滤 / 删除法 (dropna)
具体来说,在数据集中若存在缺失观测的比例较低(低于等于5%),则可以直接剔除包含缺失值的数据点;而对于那些具有高度缺失比例(高于等于85%)的关键变量,则同样可以选择性地进行剔除。
数据过滤dropna方法的语法格式如下
dropna(axis = 0, how = 'any', thresh = None)
## -------- 参数注释 -----------
# (1)axis = 0 表示删除行(记录);axis = 1 表示删除列(变量)
# (2)how 参数可选值为 any 或 all, all 表示删除全有NaN的行
# (3)thresh 为整数类型,表示删除的条件,如thresh = 3,表示一行中至少有3个非NaN值时,才将其保留。
要查看关于 dropna方法的帮助,可以使用下面命令:(其他命令同理)
import pandas
help(pd.DataFrame.dropna)
案例展示:
原始数据
外链图片转存失败...
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
源码
import pandas as pd
a = pd.read_excel('3.xlsx',usecols = range(1,4)) # 提取 第2列到第4列的数据
a
#-------------------------------------
b1 = a.dropna() # 删除所有的缺失值
print(b1)
#-------------------------------------
b2 = a.dropna(axis = 1, thresh = 9) # 删除有效数据个数小于 9 的列
print(b2)
#-------------------------------------
b3 = a.drop('用户B', axis = 1) # 删除用户B的数据
print(b3)
(2)数据填充 / 替换法 (fillna)
即为以某个固定数值替代处理那些缺失的数据点,在分析过程中涉及的连续型变量可分别采用平均值或中位数值作为替代依据;而对于离散型变量,则通常选用众数作为替代数据点的代表值。
在数据存在缺失值的情况下,我们通常会使用其他数值来填充缺失项。常用的函数是 fillna,并且该函数的基本语法格式是:它接受一个参数 name(可选),用于指定需要填充的具体列名。
fillna(value = None, method = None, axis = None, inplace = False)
# 其中value值除基本类型外,还可以使用字典,这样可以实现对不同的列填充不同的值。method表示采用的填补数据的方法,默认是None。
下面通过示例说明fillna 的用法。
案例展示:
原始数据
[外链图片加载失败,请确保您直接上传文件以避免防止文件防盗链机制的问题]$F:\DataCodes\《Codes》\Codes_from_JupyterNotebook\xxw_data_processing\2222.gif
源码
import pandas as pd
a = pd.read_excel('4.xlsx')
a
#----------------------------
b1 = a.fillna(0) # 用 0 填补所有的缺失值
b2 = a.fillna(method = 'ffill') # 用前一行的值填补缺失值
b3 = a.fillna(method = 'bfill') # 用后一行的值填补,最后一行缺失值不处理
b4 = a.fillna(value = {'gender':a.gender.mode()[0],'age':a.age.mean(),'income':a.income.median()})
## 性别使用众数替换 年龄使用均值替换 收入使用中位数替换
#----------------------------
print(b1,'\n----------------------------\n',b2,'\n----------------------------\n',b3,'\n----------------------------\n',b4)
(3)插值法
Interpolation methods aim to estimate missing values based on available variables or observations. Commonly used interpolation techniques include linear interpolation, K-nearest neighbors interpolation, and Lagrange interpolation.
当遇到缺失数据时
案例演示:
由于存在防盗链机制限制以及网络访问权限的问题,[外链图片转存失败](F:\DataCodes\《 Codes》\Codes_from_JupyterNotebook\xxw_data_processing\22222.gif)无法正常加载。您可以采取以下措施:首先将目标图片文件保存到本地存储空间中;其次确保设备网络设置满足上传需求;最后重新尝试上传操作以获取成功结果。
源码
import pandas as pd
a = pd.read_excel('4.xlsx')
a
# ----------------------------------
import numpy as np
b = a.fillna(value = {'gender':a.gender.mode()[0], # 性别使用众数替换
'age':a.age.interpolate(method = 'polynomial',order = 2), # 年龄使用 二次多项式插值 替换
'income':a.income.interpolate()}) # 收入使用线性插值替换
三、异常值处理
销毁‘钓鱼网站’,关闭‘薅羊毛’用户的权限等
Anomaly(异常值)是指那些偏离常规数据点的数据观测体。这些不协调的数据点可能对数据分析模型的效果产生显著的影响。然而,并非所有发现异常值的情况都意味着问题存在;有时候识别出这些不寻常的数据特征反而是发现潜在机遇的好机会。例如,在网络环境中可以通过消除非法网站来保护系统安全,在商业领域则可以通过限制那些试图通过不当手段获取利益的用户来维护公平竞争环境
对于异常值的检测而言,在统计学领域通常用于识别异常值的方法有两种:一种基于数据分布的标准差法(Z-score method),另一种则是通过箱线图进行判别分析(Boxplot method)。在标准差法中(Z-score method),其判别公式可表示为观测值与均值之差大于等于或小于等于某个临界阈值的情况:即如果观测点与均值的距离超过或低于一定倍的标准差,则被视为异常点( outliers)。具体而言,在这种情况下(Z-score method),满足条件即为异常点( outliers);而当取n=2时( Z-score threshold of 2),则将满足该条件的所有观测视为异常点( outliers);当取n=3时( Z-score threshold of 3),则将满足该条件的所有观测视为极端异常点( extreme outliers)。
箱线图的判别准则为:\text{outlier}>Q_3+n\text{IQR} 或 \text{outlier}
在选择这两种方法时, 当数据近似服从正态分布时, 倾向于采用标准差法, 因为此时的数据分布较为对称且稳定; 如果不满足这一条件, 则倾向于采用箱线图法, 这主要是由于分位数不受极端植影响, 更适合描述偏态分布的数据特征. 当数据中存在明显离群点时, 若离群点的比例不大, 通常可以通过去除离群点的方法来处理这些异常植; 如果有明显的极端植存在, 可以考虑采用插补的方式进行处理, 例如在上端存在异常时可取低于判别上限的最大植进行替代, 在下端出现异常情况则可取高于判别下限的最小植进行替代. 此外还可以根据具体情况选择计算均植或中位数值作为替代并加以应用
3.1 案例展示:
(1)异常值检测
外部链接中的图片无法正常加载
原始数据和异常值检验结果
原始数据
直方图与核密度图
(2)异常值的处理及其前后对比
此页面中的外链图片无法正常加载或存在防盗链保护机制,请您采取以下措施:将该页面中的图片保存到本地设备后再进行直接上传操作
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| 替换前 | 289 | 48.6135 | 39.4741 | 0 | 15.6 | 39 | 68.9 | 190.2 |
| 替换后 | 289 | 48.0660 | 37.9189 | 0 | 15.6 | 39 | 68.9 | 141.7 |
源码如下:
# =============================================
# 异常值检测
# =============================================
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
a = pd.read_csv('ISSN_Y_tot.csv')
a
#---------------------------------------------
plt.plot(a.counts)
plt.show()
#---------------------------------------------
mu = a.counts.mean() # 计算黑子 个数年平均值
s = a.counts.std() # 计算黑子个数标准差
print('标准差法异常值上限检测:',any(a.counts>mu+2*s)) # 输出: True
print('标准差法异常值下限检测:',any(a.counts<mu-2*s)) # 输出: False
#---------------------------------------------
Q1 = a.counts.quantile(0.25) # 计算下四分位数
Q3 = a.counts.quantile(0.75) # 计算上四分位数
IQR = Q3 - Q1
print("箱线图法异常值上限检测:",any(a.counts> Q3 + 1.5*IQR)) # 输出: True
print("箱线图法异常值下限检测:",any(a.counts< Q1 - 1.5*IQR)) # 输出: False
#---------------------------------------------
plt.style.use('ggplot') # 设置绘图风格
a.counts.plot(kind = 'hist', bins = 30 , density = True) # 绘制直方图
a.counts.plot(kind = 'kde') # 绘制核密度曲线
plt.show()
# =============================================
# 异常值处理
# =============================================
print('异常值替换前的数据统计特征',a.counts.describe())
#---------------------------------------------
UB = Q3 + 1.5 * IQR;
st = a.counts[a.counts < UB].max()
print('判别异常值的上限临界值为:',UB)
print('用以替换异常值的数据为:',st)
#---------------------------------------------
a.loc[a.counts>UB,'counts'] = st # 替换超过判别上限异常值
print('异常值替换后的数据特征\n',a.counts.describe())
参考文献
司首奎,孙玺菁.《Python数学实验与建模》. 北京:科学出版社,2020
推文中的各种数据集以及全部源代码均可通过在后台提交"数据清洗"关键词获取
