分组后对Pandas分类标签进行排序

4 投票
3 回答
2609 浏览
提问于 2025-04-18 07:19

我正在使用 pd.cut 来把一个数据集分成不同的部分,一切都很顺利。不过,我有个问题,关于 Categorical 这种对象类型,它是 pd.cut 返回的数据类型。文档上说 Categorical 对象就像是一个字符串数组,所以我看到分组时标签是按字母顺序排列的也不奇怪。

比如,下面这段代码:

df = pd.DataFrame({'value': np.random.randint(0, 10000, 100)})

labels = []
for i in range(0, 10000, 500):
    labels.append("{0} - {1}".format(i, i + 499))

df.sort(columns=['value'], inplace=True, ascending=True)
df['value_group'] = pd.cut(df.value, range(0, 10500, 500), right=False, labels=labels)

df.groupby(['value_group'])['value_group'].count().plot(kind='bar')

生成了下面这个图表:

enter image description here

(注意中间的 500-599)

在分组之前,结构是我预期的顺序:

In [94]: df['value_group']
Out [94]: 
59        0 - 499
58        0 - 499
0       500 - 999
94      500 - 999
76      500 - 999
95     1000 - 1499
17     1000 - 1499
48     1000 - 1499

我尝试了很长时间,唯一能避免这个问题的方法就是在标签前加一个字母,比如 ['A) 0 - 499', 'B) 500-999', ... ],这让我觉得很别扭。我还考虑过提供一个自定义的分组实现,但似乎不太可能(或者说也不是正确的做法)。我到底漏掉了什么呢?

3 个回答

1

如果你能看到这个答案的最后部分,只需要加上 sorted=False 这个参数,就可以保持原来的排序顺序了:

df.groupby(['value_group'], sorted=False)['value_group'].count().plot(kind='bar')
2

enter image description here你可以对你的数据进行自定义排序。假设:

group = df.groupby(['value_group'])['value_group'].count()
sortd= group.reindex_axis(sorted(group.index, key=lambda x: int(x.split("-")[0])))

然后如果你把排序后的数据画出来,就能正常显示了。

2

我也遇到过这个问题。可能最好的解决办法是增强对分类对象的原生支持,但在此之前,我通常通过最后一次排序来解决这个问题:

In [104]: z = df.groupby('value_group').size()

In [105]: z[sorted(z.index, key=lambda x: float(x.split()[0]))]
Out[105]: 
0 - 499        5
500 - 999      6
1000 - 1499    4
1500 - 1999    6
2000 - 2499    4
2500 - 2999    6
3000 - 3499    3
3500 - 3999    3
4000 - 4499    2
4500 - 4999    6
5000 - 5499    6
5500 - 5999    5
6000 - 6499    6
6500 - 6999    2
7000 - 7499    9
7500 - 7999    3
8000 - 8499    7
8500 - 8999    6
9000 - 9499    5
9500 - 9999    6
dtype: int64

In [106]: z[sorted(z.index, key=lambda x: float(x.split()[0]))].plot(kind='bar')
Out[106]: <matplotlib.axes.AxesSubplot at 0xbe87d30>

更好的排序演示

撰写回答