在groupby之后对Pandas分类标签进行排序

时间:2014-05-22 18:15:56

标签: python pandas data-analysis

我使用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

我已经玩了一段时间了,我能够避免这种情况的唯一方法就是在标签前加上一个前导alpha字符,例如['A) 0 - 499', 'B) 500-999', ... ]让我感到畏缩。我研究的其他事情是提供一个自定义的groupby实现,这似乎不可能(或者也是正确的)。我错过了什么?

3 个答案:

答案 0 :(得分: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])))

然后,如果你绘制排序系列,它的工作原理。

答案 1 :(得分: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>

demo with better order

答案 2 :(得分:1)

对于真正了解这部分答案的人,只需添加sorted=False参数即可保留原始排序:

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