由于各种原因,DataFrame 中会出现重复行。请看如下例子:
DataFrame 的 duplicated 方法返回的是一个布尔值 Series,这个 Series 反映的是每一行是否存在重复(与之前出现过的行相同)情况:
drop_duplicates 返回的是 DataFrame,内容是 duplicated 返回数组中为 False 的部分:
这些方法默认都是对列进行操作。我们可以指定数据的任何子集来检测是否有重复。假设我们有一个额外的列,并想基于 "k1" 列去除重复值:
duplicated 和 drop_duplicates 默认都是保留第一个观测到的值。传入参数 keep="last" 将会返回最后一个:
对于许多数据集,我们可能希望基于 DataFrame 中的数组、列或列中的数值进行一些转换。考虑下面这些收集到的关于肉类的假设数据:
假设我们想要添加一列用于表明每种食物的动物肉类型。让我们先写下一个食物和肉类的映射:
Series 的 map 方法接收一个函数或一个包含映射关系的字典型对象,但是这里我们有一个小的问题在于一些肉类大写了,而另一部分肉类没有。因此,我们需要使用 Series 的 str.lower 方法将每个值都转换为小写:
我们也可以传入一个能够完成所有工作的函数:
使用 map 是一种可以便捷执行按元素转换及其他清洗相关操作的方法。
使用 fillna 填充缺失值是通用值替换的特殊案例。我们可以使用 map 来修改一个对象中的子集的值,但是 replace 提供了更为简单灵活的实现。让我们考虑下面的 Series:
-999 可能是缺失值的标识。如果要使用 NA 来替代这些值,我们可以使用 replace 方法生成新的 Series(除非我们传入了 inplace=True):
如果我们想要一次替代多个值,我们可以传入一个列表和替代值:
要将不同的值替换为不同的值,可以传入替代值的列表:
参数也可以通过字典传递:
注意:data.replace 方法与 data.str.replace 方法是不同的,data.str.replace 是对字符串进行按元素替代的。
和 Series 中的值一样,可以通过函数或某种形式的映射对轴标签进行类似的转换,生成新的且带有不同标签的对象。我们也可以在不生成新的数据结构的情况下修改轴。下面是简单的例子:
与 Series 类似,轴索引也有一个 map 方法:
赋值给 index,修改 DataFrame:
使用 rename 方法创建数据集转换后的版本,并且不修改原有的数据集:
值得注意的是,rename 可以结合字典型对象使用,为轴标签的子集提供新的值:
rename 可以让我们从手动复制 DataFrame 并为其分配索引和列属性的繁琐工作中解放出来。如果我们想要修改原有的数据集,传入 inplace=True:
python 实现连续数据的离散化处理主要基于两个函数,pandas.cut() 和 pandas.qcut()。
我们先回忆一下,连续数据离散化方法中无监督学习方法主要有两种:
(1) 等宽法
将属性的值域从最小值到最大值分成具有相同宽度的 n 个区间,n 由数据特点决定,往往是需要有业务经验的人进行评估。
比如,属性值在 [0, 60] 区间,最小值为 0,最大值为 60,我们将其分为 3 等分,则区间被划分为 [0, 20]、[21, 40]、[41, 60],每个属性值对应属于它的那个区间。
(2) 等频法
等频法是将相同数量的记录放在每个区间,保证每个区间的数量基本一致。即将属性值分为具有相同宽度的区间,区间的个数k根据实际情况来决定。比如有60个样本,我们要将其分为k=3部分,则每部分的长度为20个样本。
这里等宽法主要使用 pandas.cut() 函数,等频法主要使用 pandas.pcut() 函数。
1、pandas.cut()——将数据均匀划分为 n 等份,每份的间距相同
pandas.cut() 是按指定分界点对连续数据进行分箱处理。
官方链接:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.cut.html
(1) 函数表达式:pandas.cut(x, bins, right: bool = True, labels=None, retbins: bool = False, precision: int = 3, include_lowest: bool = False, duplicates: str = ‘raise’)
(2) 函数表达书参数说明:
a、x:需要离散化的数组、Series、DataFrame对象
b、bins:分组的依据,可以传入 3 种形式的参数
int:传入一个整数,将 x 连续均匀分为 int 份,在两端会扩大 0.1%,用来收纳最大值和最小值。
标量序列:直接定义分割后的 bins(允许非均匀 bin 宽度的 bin 边缘),此时 bins 没有扩展,可以是不均匀分割。
IntervalIndex:定义要是用的确切的 bins,bins 的 intervalIndex 不可重叠。
c、right:right=True,是否包括区间右侧的值,默认包括,即左开右闭区间。right=False 表示左闭右开区间。
d、labels:default=None,表示分组的自定义标签,数量必须与分组的数量对应。如果值为 False,只返回整数指标面元。
e、retbins:布尔值,是否返回面元,retbins 为 True 时返回用浮点数填充的 N 维数组。
f、precision:int,deafault = 3。区间的精度,默认保留3位小数。
g、include_lowest:default = False 。类似 right,是否包含第一个区间左端点数据。
h、duplicate:default=raise or drop。如果区间重复,选择 raise 会报错,如果选择 drop,删除重复区间。
(3) 函数说明图解:
(4) 示例:
对某项研究中一组人群的年龄数据进行分组,将其放入离散的年龄框中:
使用 pandas.cut() 函数将这些年龄分为 18-25、26-35、36-60 以及 61以上 等若干个组:
pandas 返回的对象是一个特殊的 Categorical 对象。我们看到的输出描述了由 pandas.cut 计算出的箱。我们可以将它当作一个表示箱名的字符串数组;它在内部包含一个 categories(类别)数组,它指定了不同的类别名称以及 codes 属性中的 ages(年龄)数据标签:
使用 pd.value_counts(peoples) 对 pandas.cut 的结果中的箱数量进行统计:
与区间的数学符号一致,小括号表示边是开放的,中括号表示它是封闭的(包括边)。我们可以通过传递 right_False 来改变哪一边是封闭的:
我们也可以通过向 labels 选项传递一个列表或数组来传入自定义的箱名:
labels 参数为 False 时,返回结果中用不同的整数作为箱子的指示符:
如果我们传递给 cut 整数个的箱来代替显式的箱边,pandas 将根据数据中的最小值和最大值计算出等长的箱。考虑一些均匀分布的数据被切成四份的情况(precision=2 选项将十进制精度限制在两位):
2、pandas.pcut()——以相同数量的记录放进每个区间
pandas.pcut() 是按照分位数对样本进行划分的,这样划分的结果是每个区间的大小基本相同,但不一定完全相同。
官方链接:http://pandas.pydata.org/pandas-docs/stable/generated/pandas.qcut.html
(1) 函数表达式:pandas.qcut(x, q, labels=None, retbins=False, precision=3, duplicates=’raise’)
(2) 函数表达书参数说明:
a、x:要进行分组的数据,数据类型为一维数组 或 Series 对象。
b、q:整数或分位数组成的数组,即要将数据分成几组。
c、labels:可以理解为组标签,这里注意标签个数要和组数相等。
d、retbins:默认为 False,当为 False 时,返回值是 Categorical 类型(具有 value_counts() 方法),为 True 时返回值是元组。
(3) 示例:
qcut 是一个与分箱密切相关的函数,它基于样本分位数进行分箱。取决于数据的分布,使用 cut 通常不会使每个箱具有相同数据量的数据点。由于 qcut 使用样本的分位数,我们可以通过 qcut 获得等长的箱:
与 cut 类似,我们可以传入自定义的分位数(0 和 1 之间的数据,包括边):