数据清洗是数据分析过程中至关重要的一步,它确保数据的准确性、一致性和完整性。这不仅有助于提高分析结果的可靠性和有效性,还能为算法建模决策提供高质量的数据基础。在进行数据分析和建模的过程中,大量的时间花在数据准备上:加载、清理、转换和重新排列,这样的工作占用了工程师 80% 以上的时间。所以掌握常用的数据清洗方法,将帮助我们能更高效、更高质量完成数据清洗工作。
我们将从易到难来讲述数据清洗系列三篇章,本文为第一篇章:处理缺失值和重复值,我们将理论和实践结合,层层递进一步一步掌握缺失值和重复值的处理方法。
一、处理缺失值
缺失数据会在很多数据分析应用中出现,当清洗数据用于分析时,对缺失数据本身进行分析以确定数据收集问题或数据丢失导致的数据偏差通常很重要。
1、缺失值表示
对于数值型数据,pandas 使用浮点值 NaN(Not a Number)来表示缺失值,包括 numpy 中的 nan 值和 Python 内建的 None 值。
import pandas as pd
import numpy as npseries_data = pd.Series([1, np.nan, None, 4])
series_data# ----输出----
0 1.0
1 NaN
2 NaN
3 4.0
dtype: float64
2、过滤缺失值
Series 中使用 dropna 来过滤缺失值,它会返回 Series 中所有的非空数据及其索引值
import pandas as pd
import numpy as npseries_data = pd.Series([1, np.nan, None, 4])
series_data.dropna()# ----输出----
0 1.0
3 4.0
dtype: float64
Series 中使用 dropna 删除缺失值时,默认情况下会删除包含缺失值的行
import pandas as pd
import numpy as npseries_data = pd.Series([1, np.nan, None, 4])
series_data.dropna()# ----输出----
0 1.0
3 4.0
dtype: float64
DataFrame 中使用 dropna 删除缺失值时,默认情况下会删除包含缺失值的行
import pandas as pd
import numpy as npframe_data = pd.DataFrame([[1,2,3],[4,np.nan,np.nan],[7,8,np.nan],[np.nan,np.nan,np.nan]])
cleaned_data = frame_data.dropna()
frame_data# ----输出----0 1 2
0 1.0 2.0 3.0
1 4.0 NaN NaN
2 7.0 8.0 NaN
3 NaN NaN NaNcleaned_data# ----输出----0 1 2
0 1.0 2.0 3.0
如果想要删除所有值都为缺失值的行,则需要传入how='all'
frame_data.dropna(how='all')# ----输出----0 1 2
0 1.0 2.0 3.0
1 4.0 NaN NaN
2 7.0 8.0 NaN
你可以通过设置 thresh 参数来保留存在一定数量非缺失值的行,即如果设置 thresh=1,则表示如果每行如果存在大等于1个非缺失值,则保留该行,否则删除该行
frame_data.dropna(thresh=1)# ----输出----0 1 2
0 1.0 2.0 3.0
1 4.0 NaN NaN
2 7.0 8.0 NaN
如果要以列为维度删除缺失值的列,则传入参数 axis=1
frame_data.dropna(axis=1)
3、补全缺失值
在大多数情况下,我们需要对缺失值进行填充,这时我们可以使用 pandas 提供的 fillna 方法来实现我们的需求。使用 fillna 方法时,我们通过传递一个常数来填充缺失值
import pandas as pd
import numpy as np
frame_data = pd.DataFrame([[1,2,3],[4,np.nan,np.nan],[7,8,np.nan],[np.nan,np.nan,np.nan]])
frame_data.fillna(0)# ----输出----0 1 2
0 1.0 2.0 3.0
1 4.0 0.0 0.0
2 7.0 8.0 0.0
3 0.0 0.0 0.0
如果我们需要为不同列设定不同的填充值,则可以通过传入字典的形式,其中字典的属性表示哪一列,字典的属性值表示那一列填充的值
frame_data.fillna({0:0, 1:1, 2:2})# ----输出----0 1 2
0 1.0 2.0 3.0
1 4.0 1.0 2.0
2 7.0 8.0 2.0
3 0.0 1.0 2.0
fillna 默认时返回一个新的填充后的对象,不修改原先的对象,但是我们也可以修改已经存在的对象
frame_data.fillna(0, inplace=True)
frame_data# ----输出----0 1 2
0 1.0 2.0 3.0
1 4.0 0.0 0.0
2 7.0 8.0 0.0
3 0.0 0.0 0.0
我们可以使用 ffill 方法实现前向填充,即将每个缺失值替换为该列上方最近的非缺失值,使用 bfill 方法实现后向填充,即将每个缺失值替换为该列下方最近的非缺失值
frame_data.ffill()# ----输出----0 1 2
0 1.0 2.0 3.0
1 4.0 2.0 3.0
2 7.0 8.0 3.0
3 7.0 8.0 3.0
并且可以使用 limit 限制限制连续填充的次数
frame_data.ffill(limit=1)# ----输出----0 1 2
0 1.0 2.0 3.0
1 4.0 2.0 3.0
2 7.0 8.0 NaN
3 7.0 8.0 NaN
当然我们在实际清洗数据过程中,需要使用 fillna 填充的数据在很多场景下并不是一个固定的参数,而是行或者列的平均值或者中位数,这点跟上面分享的内容是不冲突的,只是将常数或者对应的计算值即可
frame_data.fillna(frame_data.mean())# ----输出----0 1 2
0 1.0 2.0 3.0
1 4.0 5.0 3.0
2 7.0 8.0 3.0
3 4.0 5.0 3.0
但是值得我们注意的是,我们如果要让数据建模的效果好,选择合适的数据补全策略至关重要,除了上面提到的常数、平均值和中位数外,我们还可以利用统计方法(内差/回归)或机器学习(预测)进行缺失值的补全,至于选取哪种方式更好,不同场景的选择方案不同,大家可以通过实验测算每种补全方法得到的结果表现来择优选择最适用相应场景的方法。
二、处理重复值
1、识别重复值
数据中经常会出现重复值,有时候我们需要判断数据中是否存在重复值,然后进行对应分析,再决定要对重复的数据进行哪些处理。我们可以使用 duplicated() 方法来判断 Series 或 DataFrame 中是否存在重复值,其中输出结果为 True 的则表示是重复的值
import pandas as pdframe_data = pd.DataFrame({'name': ['tom','paz','leo','tom','leo'],'age': [11, 10, 10, 11, 12]})
frame_data.duplicated()# ----输出----
0 False
1 False
2 False
3 True
4 False
dtype: bool
当然,我们可以指定数据的任何列来检测是否有重复,例如我们指定 name 列判断其存在重复值的情况
frame_data.duplicated(['name'])# ----输出----
0 False
1 False
2 False
3 True
4 True
dtype: bool
2、删除重复值
当我们需要对数据中的重复值进行处理时,我们可以使用 drop_duplicates 删除每列值都相同的行,Series 和 DataFrame 都有这个方法,以下我们以 DataFrame 来做示例
import pandas as pdframe_data = pd.DataFrame({'name': ['tom','paz','leo','tom','leo'],'age': [11, 10, 10, 11, 12]})
frame_data.drop_duplicates()# ----输出----name age
0 tom 11
1 paz 10
2 leo 10
4 leo 12
可以指定数据的任何列来检测是否有重复,例如我们指定 name 列去除重复值
import pandas as pdframe_data = pd.DataFrame({'name': ['tom','paz','leo','tom','leo'],'age': [11, 10, 10, 11, 12]})
frame_data.drop_duplicates(['name'])# ----输出----name age
0 tom 11
1 paz 10
2 leo 10
drop_duplicates 默认都是保留第一个观测到的值,我们可以传入参数 keep='last' ,将会返回最后一个
import pandas as pdframe_data = pd.DataFrame({'name': ['tom','paz','leo','tom','leo'],'age': [11, 10, 10, 11, 12]})
frame_data.drop_duplicates(keep='last')# ----输出----name age
1 paz 10
2 leo 10
3 tom 11
4 leo 12
本文,我们详细介绍了在数据清洗中我们可以如何识别、处理数据的缺失值和重复值,希望对阅读本文的读者有一定的学习提升和借鉴启发,不足之处也欢迎留言指出。
如果你喜欢本文,欢迎点赞,并且关注我们的微信公众号:Python数据挖掘分析,我们会持续更新数据挖掘分析领域的好文章,让大家在数据挖掘分析领域持续精进提升,成为更好的自己!
同时可以扫描以下二维码,加入 Python数据挖掘分析 群,在群内与众多业界大牛互动,了解行业发展前沿~