文章目录
数据清洗
前导
数据清洗是一项复杂且繁琐
的工作,同时也是整个数据分析过程中最为重要
的环节。
数据清洗的目的在于
提高数据质量
,将脏数据
清洗干净,使原数据具有完整性、唯一性、权威性、合法性、一致性等特点。
脏数据
在这里指的是对数据分析没有实际意义
、格式非法
、不在指定范围
内的数据。
空值和缺失值的处理
空值一般表示数据未知
、不适用
或将在以后添加数据。缺失值是指数据集中某个或某些属性的值是不完整
的。
一般空值使用
None
表示,缺失值使用NaN
表示。
Pandas中提供了一些用于
检查
或处理空值
和缺失值
的函数或方法。
- 使用
isnull()
和notnull()
函数可以判断数据集中是否存在空值和缺失值。 - 对于缺失数据可以使用
dropna()
和fillna()
方法对缺失值进行删除和填充
isnull()函数的语法格式如下:
pandas.isnull(obj)
- 上述函数中
只有一个参数obj
,表示检查空值
的对象。 isnull()
函数会返回一个布尔类型的值,如果返回的结果为True
,则说明有空值或缺失值,否则为False
。(NaN
或None
映射到True
值,其它内容映射到False
)
notnull()
与isnull()
函数的功能是一样的,都可以判断数据中是否存在空值或缺失值,不同之处在于,前者发现数据中有空值或缺失值时返回False
,后者返回的是True
。
series_obj = Series([1, None, NaN])
# 检查是否不为空值或缺失值
pd.notnull(series_obj)
0 | True |
---|---|
1 | False |
2 | False |
dropna()
方法的作用是删除含有空值或缺失值的行或列。
dropna(axis=0, how='any', thresh=None, subset=None, inplace=False)
axis
:确定过滤行或列。how
:确定过滤的标准。thresh
:表示有效数据量的最小要求。若传入了2,则是要求该行或该列至少有两个非NaN
值时将其保留
删除空值或缺失值前后的效果如下图所示:
填充缺失值和空值的方式有很多种,比如人工填写、热卡填充等,Pandas中的
fillna()
方法可以实现填充空值或缺失值。
fillna(value=None, method=None, axis=None, inplace=False,limit=None, downcast=None, **kwargs)
value
:用于填充的数值。method
:表示填充方式,默认值为None
。limit
: 可以连续填充的最大数量,默认None
。
method
参数不能与value
参数同时使用。
有一张表格里存在缺失值,如果使用常量66.0来替换缺失值,那么填充前后的效果如下图所示。
通过fillna()方法填充常量的示例如下:
# 使用66.0替换缺失值
df_obj.fillna('66.0')
如果希望A列缺失的数据使用数字“4.0”进行填充,B列缺失的数据使用数字“5.0”来填充,那么填充前后的效果如下图所示。
通过fillna()方法对指定列进行填充的示例如下:
# 指定列填充数据
df_obj.fillna({'A': 4.0, 'B': 5.0})
如果希望A~D列中按从前往后的顺序填充缺失的数据,那么填充前后的效果如下图所示。
通过
fillna()
方法采用前向填充的方式替换空值或缺失值,示例如下:
# 使用前向填充的方式替换空值或缺失值
df.fillna(method='ffill')
重复值的处理
当数据中出现了重复值,在大多数情况下需要进行删除。
Pandas提供了两个函数专门用来处理数据中的重复值,分别为
duplicated()
和drop_duplicates()
方法。
duplicated()
方法用于标记是否有重复值。drop_duplicates()
方法用于删除重复值。- 它们的判断标准是一样的,即只要两条数据中所有条目的值完全相等,就判断为重复值。
duplicated()
方法的语法格式如下:
duplicated(subset=None, keep='first')
subset
:用于识别重复的列标签或列标签序列,默认识别所有的列标签。keep
:删除重复项并保留第一次出现的项,取值可以为first
、last
或False
。
duplicated()
方法用于标记Pandas对象的数据是否重复,重复则标记为True
,不重复则标记为False
,所以该方法返回一个由布尔值组成的Series对象,它的行索引保持不变,数据则变为标记的布尔值。
对于
duplicated()
方法,这里有如下两点要进行强调:
- 只有数据表中两个条目间所有列的内容都相等时,
duplicated()
方法才会判断为重复值。 duplicated()
方法支持从前向后(first
)和从后向前(last
)两种重复值查找模式,默认是从前向后查找判断重复值的。换句话说,就是将后出现的相同条目判断为重复值。
drop_duplicates()
方法的语法格式如下:
drop_duplicates(subset=None, keep='first', inplace=False)
上述方法中,inplace
参数接收一个布尔类型的值,表示是否替换原来的数据,默认为False
。
异常值的处理
异常值是指样本中的个别值,其数值明显偏离它所属样本的其余观测值,这些数值是不合理的或错误的。
要想确认一组数据中是否有异常值,则常用的检测方法有3σ原则(拉依达准则)和箱形图。
- 3σ原则是基于正态分布的数据检测,而箱形图没有什么严格的要求,可以检测任意一组数据,
思考:
什么是3σ原则?
答:
3σ原则,又称为拉依达原则,它是指假设一组检测数据只含有随机误差,对其进行计算处理得到标准偏差,按一定概率确定一个区间,凡是超过这个区间的误差都是粗大误差,在此误差的范围内的数据应予以剔除。
在正态分布概率公式中,σ表示标准差,μ表示平均数,f(x)表示正态分数函数,具体如下:
正态分布函数如下图所示。
根据正态分布函数图可知,3σ原则在各个区间所占的概率如下所示:
- 数值分布在(μ-σ,μ+σ)中的概率为
0.682
。 - 数值分布在(μ-2σ,μ+2σ)中的概率为
0.954
。 - 数值分布在(μ-3σ,μ+3σ)中的概率为
0.997
。
数值几乎全部集中在
(μ-3σ,μ+3σ)
区间内,超出这个范围的可能性仅占不到0.3%。所以,凡是误差超过这个区间的就属于异常值,应予以剔除。
箱形图是一种用作显示一组数据分散情况的统计图。在箱形图中,异常值通常被定义为小于
QL – 1.5QR
或大于QU + 1.5IQR
的值。
- QL称为下四分位数,表示全部观察中
四分之一的数据
取值比它小; - QU称为上四分位数,表示全部观察值中有
四分之一的数据
取值比它大; - IQR称为四分位数间距,是上四分位数QU与下四分位数QL之差,其间包含了全部观察值的一半。
离散点表示的是异常值,上界表示
除异常值以外数据中最大值
;下界表示除异常值以外数据中最小值
。
为了能够从箱形图中查看异常值,Pandas中提供了一个
boxplot()
方法,专门用来绘制箱形图。
从输出的箱形图中可以看出,D列的数据中有一个离散点,说明箱形图成功检测出了异常值。
检测出异常值后,通常会采用如下四种方式处理这些异常值:
- 直接将含有异常值的记录
删除
。 - 用具体的值来进行
替换
,可用前后两个观测值的平均值修正该异常值。 - 不处理,直接在具有异常值的数据集上进行统计分析。
- 视为缺失值,利用缺失值的处理方法修正该异常值。
如果希望对异常值进行修改,则可以使用
replace()
方法进行替换,该方法不仅可以对单个数据进行替换,也可以多个数据执行批量替换操作。
replace(to_replace = None,value = None,inplace = False,limit = None,regex = False,method ='pad' )
to_replace
:表示查找被替换值的方式。
value
:用来替换任何匹配to_replace
的值,默认值None
。
更改数据类型
在处理数据时,可能会遇到数据类型不一致的问题。例如,通过爬虫采集到的数据都是整型的数据,在使用数据时希望保留两位小数点,这时就需要将数据的类型转换成浮点型。
创建Pandas数据对象时,如果没有明确地指出数据的类型,则可以根据传入的数据推断出来,并且通过
dtypes
属性进行查看。
df = pd.DataFrame({'A':['5', '6', '7'], 'B':['3', '2', '1']})
# 查看数据的类型
df.dtypes
# A object
# B object
# dtype: object
还可以在创建Pandas对象时明确地指定数据的类型,即在使用构造方法中的
dtype
参数指定数据的类型。
df = pd.DataFrame({'A': ['5', '6', '7'],
'B': ['3', '2', '1']},dtype='int')
df.dtypes
# A int32
# B int32
# dtype: object
通过
astype()
方法可以强制转换数据的类型。
astype(dtype,copy = True,errors ='raise',** kwargs )
dtype
:表示数据的类型。
errors
:错误采取的处理方式,可以取值为raise
或ignore
。其中,raise
表示允许引发异常,ignore
表示抑制异常,默认为raise
。
astype()
方法存在着一些局限性,只要待转换的数据中存在非数字以外的字符,在使用astype()
方法进行类型转换时就会出现错误,而to_numeric()
函数的出现正好解决了这个问题。
to_numeric()
函数可以将传入的参数转换为数值类型。
pandas.to_numeric(arg, errors='raise', downcast=None)
arg
:表示要转换的数据,可以是list
、tuple
、Series
。errors
:表示错误采取的处理方式。
数据合并
轴向堆叠数据
concat()函数可以沿着一条轴将多个对象进行堆叠,其使用方式类似数据库中的数据表合并。
concat(objs,axis=0,join=‘outer’,join_axes=None,ignore_index=False,keys=None,levels=None,names=None, ...)
axis
:表示连接的轴向,可以为0
或1
,默认为0
。join
:表示连接的方式,inner
表示内连接,outer
表示外连接,默认使用外连接。ignore_index
:如果设置为True
,清除现有索引并重置索引值。names
:结果分层索引中的层级的名称。
根据轴方向的不同,可以将堆叠分成横向堆叠与纵向堆叠,默认采用的是纵向堆叠方式。
在堆叠数据时,默认采用的是外连接(
join
参数设为outer
)的方式进行合并,当然也可以通过join=inner
设置为内连接的方式。
当使用
concat()
函数合并时,若是将axis
参数的值设为1
,且join
参数的值设为outer
,代表着使用横向堆叠与外连接的方式进行合并。
当使用
concat()
函数合并时,若是将axis
参数的值设为0
,且join
参数的值设为inner
,则代表着使用纵向堆叠与内连接的方式进行合并。
主键合并数据
主键合并类似于关系型数据库的连接方式,它是指根据一个或多个键将不同的
DatFrame
对象连接起来,大多数是将两个DatFrame
对象中重叠的列作为合并的键。
Pandas中提供了用于主键合并的
merge()
函数。
pandas.merge(left, right, how='inner', on=None, left_on=None,
right_on=None, left_index=False, right_index=False, sort=False,
suffixes=('_x', '_y'), copy=True, indicator=False, validate=None)
left
:参与合并的左侧DataFrame
对象。right
:参与合并的右侧DataFrame
对象。how
:表示连接方式,默认为inner
。
how
参数可以取下列值:
left
:使用左侧的DataFrame的键,类似SQL的左外连接。right
:使用右侧的DataFrame的键,类似SQL的右外连接。outer
:使用两个DataFrame所有的键,类似SQL的全连接。inner
:使用两个DataFrame键的交集,类似SQL的内连接。
在使用
merge()
函数进行合并时,默认会使用重叠的列索引做为合并键,并采用内连接方式合并数据,即取行索引重叠的部分。
除此之外,
merge()
函数还支持对含有多个重叠列的DataFrame对象进行合并。
使用外连接的方式将
left
与righ
t进行合并时,列中相同的数据会重叠,没有数据的位置使用NaN
进行填充。
左连接是以左表为基准进行连接,所以
left
表中的数据会全部显示,right
表中只会显示与重叠数据行索引值相同的数据,合并后表中缺失的数据会使用NaN
进行填充。
右连接与左连接的规则正好相反,右连接是以右表为基准,右表中的数据全部显示,而左表中显示与重叠数据行索引值相同的数据,合并后缺失的数据使用NaN填充合并。
假设两张表中的行索引与列索引均没有重叠的部分,但依旧可以使用
merge
函数来合并,只需要将参数left_index
与right_index
的值设置为True
即可。
根据行索引合并数据
join()
方法能够通过索引或指定列来连接多个DataFrame对象。
join(other,on = None,how ='left',lsuffix ='',rsuffix ='',sort = False )
on
:名称,用于连接列名。how
:可以从{‘‘left’’ ,‘‘right’’, ‘‘outer’’,‘‘inner’’}中任选一个,默认使用左连接的方式。sort
:根据连接键对合并的数据进行排序,默认为False
。
合并重叠数据
当DataFrame对象中出现了缺失数据,而我们希望使用其他DataFrame对象中的数据填充缺失数据,则可以通过
combine_first()
方法为缺失数据填充。
combine_first(other)
- 上述方法中只有一个参数
other
,该参数用于接收填充缺失值的DataFrame对象。
假设现在有
left表
与right表
,其中left表
中存在3个缺失的数据,而right表中的数据是完整的,并且right表与left表有相同的索引名,此时我们可以使用right表中的数据来填充left表的缺失数据,得到一个新的result表
数据重塑
重塑层次化索引
Pandas中重塑层次化索引的操作主要是
stack()
方法和unstack()
方法,前者是将数据的列“旋转”为行,后者是将数据的行“旋转”为列。
stack()
方法可以将数据的列索引转换为行索引。
DataFrame.stack(level=-1, dropna=True)
level
:表示操作内层索引。若设为0
,表示操作外层索引,默认为-1
。dropna
:表示是否将旋转后的缺失值删除,若设为True
,则表示自动过滤缺失值,设置为False
则相反。
现在有一个DataFrame类对象df,如果希望将它重塑为一个具有两层索引结构的对象
result
,也就是说将列索引转换成内层行索引,则重塑前后的效果如下图所示。
unstack()
方法可以将数据的行索引转换为列索引。
DataFrame.unstack(level=-1, fill_value=None)
level
:默认为-1
,表示操作内层索引,0
表示操作外层索引。fill_value
:若产生了缺失值,则可以设置这个参数用来替换NaN
。
轴向旋转
某件商品的价格在非活动期间为50元,而在活动期间商品的价格为30元,这就造成同一件商品在不同时间对应不同的价格。
同一款商品的在活动前后的价格无法很直观地看出来。
我们可以将商品的名称作为列索引,出售日期作为行索引,价格作为表格中的数据,此时每一行展示了同一日期不同手机品牌的价格。
通过表格可以直观地看出活动前后的价格浮动
在Pandas中
pivot()
方法提供了这样的功能,它会根据给定的行或列索引重新组织一个DataFrame对象。
pivot(index=None, columns=None, values=None)
index
:用于创建新DataFrame对象的行索引。columns
:用于创建新DataFrame对象的列索引。values
:用于填充新DataFrame对象中的值。
数据转换
重命名轴索引
Pandas中提供了一个
rename()
方法来重命名个别列索引或行索引的标签或名称。
rename(mapper = None,index = Nonecolumns = None,axis = None,copy = True,inplace = False,level = None)
index,columns
:表示对行索引名或列索引名的转换。inplace
:默认为False
,表示是否返回新的Pandas对象。
例如,将df对象的每个列索引名称重命名为a、b、c。
离散化连续数据
例如,将df对象的每个列索引名称重命名为a、b、c。
有时候我们会碰到这样的需求,例如,将有关年龄的数据进行离散化(分桶)或拆分为“面元”,直白来说,就是将年龄分成几个区间。
Pandas 的
cut ()
函数能够实现离散化操作。
pandas.cut(x,bins,right = True,labels = None,retbins = False,precision = 3,include_lowest = False,duplicates ='raise' )
x
:表示要分箱的数组,必须是一维的。bins
:接收int和序列类型的数据。right
:是否包含右端点,决定区间的开闭,默认为True
。
cut()
函数会返回一个Categorical对象,我们可以将其看作一组表示面元名称的字符串,它包含了分组的数量以及不同分类的名称。
Categories对象中的区间范围跟数学符号中的“区间”一样,都是用圆括号表示开区间,用方括号则表示闭区间。
如果希望设置左闭右开区间,则可以在调用
cut()
函数时传入right=False
进行修改。
pd.cut(ages, bins=bins, right=False)
哑变量处理类别型数据
哑变量又称虚拟变量、名义变量,从名称上看就知道,它是人为虚设的变量,用来反映某个变量的不同类别。使用哑变量处理类别转换,事实上就是将分类变量转换为哑变量矩阵或指标矩阵,矩阵的值通常用
“0”或“1”
表示。假设变量“职业”的取值分别为司机、学生、导游、工人、教师共5种选项,如果使用哑变量表示,则可以用下图表示。
在Pandas中,可以使用
get_dummies()
函数对类别特征进行哑变量处理,
pandas.get_dummies(data, prefix=None, prefix_sep='_', dummy_na=False,columns=None, sparse=False, drop_first=False, dtype=None)
data
:表示哑变量处理的数据。prefix
:表示列名的前缀,默认为None
。prefix_sep
:用于附加前缀作为分隔符使用,默认为“_”。
本章小结
- 本章进一步介绍了Pandas的数据预处理,包括数据清洗、数据合并、数据重塑和数据转换,并结合预处理部分地区信息的案例,讲解了如何利用Pandas预处理数据。
- 数据预处理是数据分析中必不可少的环节,希望大家要多加练习,并能够在实际场景中选择合理的方式对数据进行预处理操作。