学科分类
目录
数据分析

数据转换

除了前面介绍的聚合操作以外,Pandas还提供了其它操作应用到分组运算中,比如,transform()和apply()方法,它们能够执行更多其他的分组运算。

前面使用agg()方法进行聚合运算时,返回的数据集的形状(shape)与被分组数据集的形状是不同的,如果希望保持与原数据集形状相同,那么可以通过transfrom()方法实现。transfrom()方法的语法格式如下:

transform(func, *args, **kwargs)

上述方法中只有一个func参数,表示操作Pandas对象的函数。transform()方法返回的结果有两种,一种是可以广播的标量值(np.mean),另一种可以是与分组大小相同的结果数组。

通过transfrom()方法操作分组时,transfrom()方法会把func函数应用各个分组中,并且将结果放在适当的位置上。

假设现在有一个5行6列的表格,从左边数前5列的数据都是数值,而最后一列的数据是字符串,具体如图1所示。

a b c d e key
0 0 1 2 3 4 A
1 1 2 3 4 5 A
2 6 7 8 9 10 B
3 10 11 12 13 14 B
4 3 4 4 5 3 B

图1 表格结构示例

按照图1中表格的key列进行分组,可以将表格划分为A、B两组,之后通过transform()方法对这两组执行求平均值的操作。

首先,创建一个与图1中表格结构相同的DataFrame对象,代码如下:

In [24]: import pandas as pd
         df = pd.DataFrame({'a': [0, 1, 6, 10, 3],
                            'b': [1, 2, 7, 11, 4],
                            'c': [2, 3, 8, 12, 4],
                            'd': [3, 4, 9, 13, 5],
                            'e': [4, 5, 10, 14, 3],
                            'key': ['A', 'A', 'B', 'B', 'B']})
         df

Out[24]:
  a  b  c  d  e  key
0  0  1  2  3  4   A
1  1  2  3  4  5   A
2  6  7  8  9 10  B
3 10 11 12 13 14  B
4  3  4  4  5  3   B

上述示例中,创建了一个5行6列的DataFrame对象df,其中,df对象的key列中的数据都是字符串。

以key列进行分组,可以将df对象拆分成A、B两组,将mean()方法应用到每个分组中,计算每个分组中每列的平均值,具体代码如下。

In [25]: data_group = df.groupby('key').transform('mean')
In [26]: data_group
Out[26]:
​      a     b  c  d  e
0 0.500000 1.500000 2.5 3.5 4.5
1 0.500000 1.500000 2.5 3.5 4.5
2 6.333333 7.333333 8.0 9.0 9.0
3 6.333333 7.333333 8.0 9.0 9.0
4 6.333333 7.333333 8.0 9.0 9.0

从输出结果可以看出,每列的数据是各分组求得的平均数。以A组为例,在A组中a列原来的数据0与1的均值为0.5(0.5为一个标量值),这个均值在A组的a列数据上进行了广播,使得所有A组a列的数据都变成了0.5。

上述示例中,原始数据的列数与最终结果的列数是不一样的。假设现在有另外一个5行4列的表格,该表格中每列的数据都是数值类型的,如图2所示。

A B C D
0 2 4 9 3
1 3 2 7 4
2 3 3 0 8
3 4 6 7 6
4 2 6 8 10

图2 表格结构示例

如果希望图2中的表格进行转换后,返回具有相同形状的结果,那么可以创建一个Series对象,该对象的长度与表格中的行数是相同的,按照这个Series对象进行分组,便可以得到一个形状相同的对象。

首先,创建与图2中表格结构相同的DataFrame对象,代码如下:

In [27]: import pandas as pd
         df = pd.DataFrame({'A': [2, 3, 3, 4, 2],
                            'B': [4, 2, 3, 6, 6],
                            'C': [9, 7, 0, 7, 8],
                            'D': [3, 4, 8, 6, 10]})
         df
Out[27]:
​    A B C D
  0 2 4 9 3
  1 3 2 7 4
  2 3 3 0 8
  3 4 6 7 6
  4 2 6 8 10

然后,创建一个列表key,key的长度需要与df对象的行数是一样的,我们把key当做分组键,将df对象按照key列表进行分组,然后同样对每个分组执行求平均值的操作,具体代码如下:

In [28]: # 以key为分组依据,对df对象进行分组
         key = ['one','one','two',' two',' two']
         df.groupby(key).transform('mean')
Out[28]:
A B C  D
0 2.5 3 8 3.5
1 2.5 3 8 3.5
2 3.0 5 5 8.0
3 3.0 5 5 8.0
4 3.0 5 5 8.0

通过比较转换前与转换后的结果,发现两次输出的结果具有相同的大小。在这里,计算出的平均值不仅在每组每列中进行了广播,而且也保证了返回的结果与原数据的形状相同。

在进行数据转换时,使用内置方法与自定义函数的方式是一样的,只需要将定义好的函数名称作为func参数传入到transform()方法中即可,这里就不再举例了。

点击此处
隐藏目录