Python大数据分析6:数据的分组和聚合运算

在我们处理各种数据的时候,常常需要进行必要的数据汇总分析,比如我们想看看目前男女学生各有多少人

这里就使用了其实三个重要过程:一个是分组,比如我们按照性别进行了组别的划分,我们不妨称之为拆分;

第二个是统计分析,比如计算个数、总和、平均数、最大值、最小值等,这种运算我们常常称之为聚合运算,我们也可以称之为应用,即对每个组应用特定的聚合运算方法来计算结果;

第三是显示结果,这个过程可以根据用户的喜好采取多种方式来显示同样的数据结果,我们称之为合并。

我们就以刚才这个男女学生人数的例子来看看。

groups = frame.groupby(frame[‘gender’])

print(groups.count())

这里的第一行表示得到一个分组变量,groupby就是根据什么分组的意思,正好对应第一个过程,其中的参数表示我们要按照性别列来分组。可以想象,因为性别列这里只有两个值,此时的frame数据变成了两组,

第二行表示统计分析,count表示统计个数,这里有几组就分别在几组中应用该聚合函数,分别算出各自的结果。

有时可以省略groupby里面的frame,显得更为简单些。但是在一些复杂操作时,这种省略会导致更多的歧义可能。

默认的呈现方式看的出来意义不大,我们没有必要显示所有列的聚合结果,因此,可以在第三步过程中选择所需的列。于是我们再改进下,选择下所需的显示列:

print(groups[‘gender’].count())

这里其实选择一个列都可以,毕竟是个数:

print(groups[‘ID’].count())

不过,既然我们只需一列就够了,那为何还要对所有列进行统计呢?每个列都算一算个数显然没有意义。因此更为高效的写法应该是:

groups = frame[‘gender’].groupby(frame[‘gender’])

print(groups.count())

此时的结果很清楚。

当然有时为了书写方便,我们也可以合并起来一起写:

print(frame[‘gender’].groupby(frame[‘gender’]).count())

大家只要知道了其执行过程,那么意思很好理解。

关于显示问题,我们可以再次优化下。

这里有一个细节,如果希望在显示结果中显示聚合运算后的统计列名称,可以尝试在前面选择frame列使用列表参数,也就是使用两个方括号,未来可以据此实现对多个字段的选择。

groups = frame[[‘gender’]].groupby(frame[‘gender’])

print(groups.count())

此时还可以改动这个统计列的名称,比如使用rename:

print(groups.count().rename(columns={‘gender’: ‘genderCount’}))

可能也有学生会说,这种过程不可以更简单的实现吗?

print(frame[‘gender’].value_counts())

不错,对于这个例子,确实这个函数更简单,但是要想实现更为灵活和复杂的统计效果,还得要自己使用分组和聚合函数来组合。

我们再试一下,计算下不同年龄的人数:

print(frame[‘age’].groupby(frame[‘age’]).count())

我们可以按照排序依据排列结果,默认是按照升序来排列:

print(frame[‘age’].groupby(frame[‘age’]).count().sort_index())

我们也可以按照计算后的值,比如这里为个数来排序,并且为降序排列:

print(frame[‘age’].groupby(frame[‘age’]).count().sort_values(ascending=False))

看得出来,一般倒序输出意义更大些。

我们也可以按照多个列来分组:

比如我们按照性别和年龄一起分组,分别统计各自的人数:

print(frame[[‘ID’]].groupby([frame[‘gender’], frame[‘age’]]).count())

甚至可以继续对结果进行排序

print(frame[[‘ID’]].groupby([frame[‘gender’], frame[‘age’]]).count().

      sort_values(by=[‘gender’, ‘age’], ascending=[False, True]))

此时由于有多个列,因此可以通过sort_values的by属性增加多个列,还可以通过ascending属性分别指定每个列是按照升序还是降序。

当然,除了求个数以外,pandas分组的聚合函数还有很多,比如求平均值等。

我们来对不同年龄的学生计算他们的平均身高:

print(frame[[‘height’]].groupby(frame[‘age’]).mean())

当然也可以组合条件分组,比如按照性别、年龄分组后统计各个组的平均身高:

print(frame[[‘height’]].groupby([frame[‘gender’], frame[‘age’]]).mean())

下面我们说一些高级的应用。Pandas的强大之处在于我们还可以自己来扩展分组条件和统计函数,并实现分组统计效果。其中,主要利用apply函数来应用这些不同的函数来扩展功能:

比如我们想按照姓名的长度来分组,并统计各组的人数:

print(frame[‘name’].groupby(frame[‘name’].apply(len)).count())

再比如统计不同身高范围的人数,我们只区分小数点后一位,这个可以使用round函数,传递1表示1位小数:

print(frame[‘name’].groupby(frame[‘height’].apply(round, args=[1])).count())

甚至还可以通过自己定义的函数扩展功能,如计算最大值和最小值之间的距离:

def peak_to_peak(arr):

    return arr.max() – arr.min()

可以想象,这个arr参数应该是个具有多个值的序列变量。

此时,就可以利用apply函数来分组调用:

print(frame[‘height’].groupby(frame[‘gender’]).apply(peak_to_peak))

其实这种自定义函数甚至可以写得更为简单,更为Pythonic(Python风格化),比如使用匿名函数来合二为一:

print(frame[‘height’].groupby(frame[‘gender’]).apply(lambda arr: arr.max() – arr.min()))

发表评论

邮箱地址不会被公开。 必填项已用*标注