Python:使用分组选择最频繁的项

6 投票
1 回答
12283 浏览
提问于 2025-04-18 06:44

我该如何在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

不过,在出现多个众数的情况下,这个方法不会返回一个数组。它只会返回第一个众数。

撰写回答