Python:使用分组选择最频繁的项
我该如何在Python中找出每个标签中出现频率最高的类别(众数)呢?
+------------------+----------+
| tag | category |
+------------------+----------+
| automotive | 8 |
| ba | 8 |
| bamboo | 8 |
| bamboo | 8 |
| bamboo | 8 |
| bamboo | 8 |
| bamboo | 8 |
| bamboo | 10 |
| bamboo | 8 |
| bamboo | 9 |
| bamboo | 8 |
| bamboo | 10 |
| bamboo | 8 |
| bamboo | 9 |
| bamboo | 8 |
| banana tree | 8 |
| banana tree | 8 |
| banana tree | 8 |
| banana tree | 8 |
| bath | 9 |
+-----------------------------+
期望的输出结果应该是这样的
tag | category
------------+-----------
ba | 8
automotive | 8
bananatree | 8
bath | 9
bamboo | 8
我借用了Stephen J. Fuhry的表格,并根据数据集的保密性,编辑了David Fuhry在MySQL SELECT most frequent by group上的输出结果。
1 个回答
19
在评论中你提到你在使用 pandas
。你可以做类似下面的操作:
>>> df
tag category
0 automotive 8
1 ba 8
2 bamboo 8
3 bamboo 8
4 bamboo 8
5 bamboo 8
6 bamboo 8
7 bamboo 10
8 bamboo 8
9 bamboo 9
10 bamboo 8
11 bamboo 10
12 bamboo 8
13 bamboo 9
14 bamboo 8
15 banana tree 8
16 banana tree 8
17 banana tree 8
18 banana tree 8
19 bath 9
先对 'category' 列进行按 'tag' 分组,然后在每个组内使用 mode
方法。不过,我们需要加个条件,因为如果观察的数量少于3,pandas
不会返回一个数字作为 mode
(在组内只有1或2个观察值的特殊情况下,我们可以直接返回这个组本身)。我们可以使用 aggregate/agg
方法配合一个 lambda 函数来实现:
>>> mode = lambda x: x.mode() if len(x) > 2 else np.array(x)
>>> df.groupby('tag')['category'].agg(mode)
tag
automotive 8
ba 8
bamboo 8
banana tree 8
bath 9
注意,当出现多个众数时,你会得到一个数组(numpy)。比如说,如果有两个关于浴室的记录(其他数据都一样):
tag|category
bath|9
bath|10
在这种情况下,输出结果会是:
>>> mode = lambda x: x.mode() if len(x) > 2 else np.array(x)
>>> df.groupby('tag')['category'].agg(mode)
tag
automotive 8
ba 8
bamboo 8
banana tree 8
bath [9, 10]
你也可以使用 value_counts
方法来代替 mode
。同样,先对 'category' 列按 'tag' 分组,然后在每个组内使用 value_counts
方法。value_counts
会按降序排列,所以你需要获取第一行的索引:
>>> df.groupby('tag')['category'].agg(lambda x: x.value_counts().index[0])
tag
automotive 8
ba 8
bamboo 8
banana tree 8
bath 9
不过,在出现多个众数的情况下,这个方法不会返回一个数组。它只会返回第一个众数。