在pandas/matplotlib柱状图中排序条形顺序

33 投票
3 回答
127159 浏览
提问于 2025-04-17 23:49

在pandas中,如何按照特定顺序对某一列中的“级别”进行排序,以便在柱状图中显示特定的条形顺序?

举个例子,假设有以下数据:

import pandas as pd
df = pd.DataFrame({
    'group': ['a', 'a', 'a', 'a', 'a', 'a', 'a', 
              'b', 'b', 'b', 'b', 'b', 'b', 'b'],
    'day': ['Mon', 'Tues', 'Fri', 'Thurs', 'Sat', 'Sun', 'Weds',
            'Fri', 'Sun', 'Thurs', 'Sat', 'Weds', 'Mon', 'Tues'],
    'amount': [1, 2, 4, 2, 1, 1, 2, 4, 5, 3, 4, 2, 1, 3]})
dfx = df.groupby(['group'])
dfx.plot(kind='bar', x='day')

我可以生成以下一对图表:

无序的柱状图

这些柱子的顺序是按照行的顺序来的。

那么,怎样才能重新排列数据,让柱状图中的柱子按照周一到周日的顺序排列呢?

更新:这个不太好的解决方案可以用,但它使用了一个额外的排序列,显得不太优雅:

df2 = pd.DataFrame({
    'day': ['Mon', 'Tues', 'Weds', 'Thurs', 'Fri', 'Sat', 'Sun'],
    'num': [0, 1, 2, 3, 4, 5, 6]})
df = pd.merge(df, df2, on='day')
df = df.sort_values('num')
dfx = df.groupby(['group'])
dfx.plot(kind='bar', x='day')

进一步的扩展:

有没有一种解决方案可以同时修复“错位”柱状图中的柱子顺序:

df.pivot('day', 'group', 'amount').plot(kind='bar')

在这里输入图像描述

3 个回答

5

下面我会提供代码,来扩展Dan的回答,以解决提问者问题中的“进一步概括”部分。首先,给出一个完整的例子,针对简单情况(只有一个变量),这个例子基于Dan的解决方案:

import pandas as pd

# Create dataframe 
df=pd.DataFrame({
    'group':['a','a','a','a','a','a','a','b','b','b','b','b','b','b'],
    'day':['Mon','Tues','Fri','Thurs','Sat','Sun','Weds','Fri','Sun','Thurs','Sat','Weds','Mon','Tues'],
    'amount':[1,2,4,2,1,1,2,4,5,3,4,2,1,3]
})


# Calculate the total amount for each day
df_grouped = df.groupby(['day']).sum().amount.reset_index()

# Use Dan's trick to order days names in the table created by groupby
weekdays = ['Mon', 'Tues', 'Weds', 'Thurs', 'Fri', 'Sat', 'Sun']
mapping = {day: i for i, day in enumerate(weekdays)}
key = df_grouped['day'].map(mapping)    
df_grouped = df_grouped.iloc[key.argsort()]

# Draw the bar chart
df_grouped.plot(kind='bar', x='day')

接下来,我们使用相同的排序方法来对透视表的行进行排序(而不是对通过分组生成的行进行排序)。

import pandas as pd

# Create dataframe 
df=pd.DataFrame({
    'group':['a','a','a','a','a','a','a','b','b','b','b','b','b','b'],
    'day':['Mon','Tues','Fri','Thurs','Sat','Sun','Weds','Fri','Sun','Thurs','Sat','Weds','Mon','Tues'],
    'amount':[1,2,4,2,1,1,2,4,5,3,4,2,1,3]
})

# Get the amount for each day AND EACH GROUP
df_grouped = df.groupby(['group', 'day']).sum().amount.reset_index()

# Create pivot table to get the total amount for each day and each in the proper format to plot multiple series with pandas
df_pivot = df_grouped.pivot('day','group','amount').reset_index()

# Use Dan's trick to order days names in the table created by PIVOT (not the table created by groupby, in the previous example)
weekdays = ['Mon', 'Tues', 'Weds', 'Thurs', 'Fri', 'Sat', 'Sun']
mapping = {day: i for i, day in enumerate(weekdays)}
key = df_pivot['day'].map(mapping)    
df_pivot = df_pivot.iloc[key.argsort()]

# Draw the bar chart
df_pivot.plot(kind='bar', x='day')

结果如下所示:

在这里输入图片描述

13

我知道这个回复有点晚了,但对于提到的两种情况,一个简单的解决方案是我下面贴出的内容。

把“day”(天)设置为索引,这样你就可以用 .loc 来按特定顺序选择数据。

1) 对于两个单独的图表:

df=pd.DataFrame({'group':['a','a','a','a','a','a','a','b','b','b','b','b','b','b'],
     'day':['Mon','Tues','Fri','Thurs','Sat','Sun','Weds','Fri','Sun','Thurs','Sat','Weds','Mon','Tues'],
     'amount':[1,2,4,2,1,1,2,4,5,3,4,2,1,3]})

order = ['Mon', 'Tues', 'Weds','Thurs','Fri','Sat','Sun']`
df.set_index('day').loc[order].groupby('group').plot(kind='bar')

2) 对于带有错位图的透视示例:

order = ['Mon', 'Tues', 'Weds','Thurs','Fri','Sat','Sun']
df.pivot('day','group','amount').loc[order].plot(kind='bar')

注意,透视结果中“day”已经在索引里了,所以你可以再次使用 .loc。

补充:在这些解决方案中,最好使用 .loc 而不是 .ix,因为 .ix 将会被淘汰,而且在列名和索引是数字时,使用 .ix 可能会出现奇怪的结果。

32

你需要提供一个映射,来指定如何排列星期几的名称。(如果这些名称是以正确的日期格式存储的,那就有其他方法可以做到这一点。)

更新:

构建一个键。你可以明确地写出一个字典,或者使用一些聪明的方式,比如这个字典推导式。

weekdays = ['Mon', 'Tues', 'Weds', 'Thurs', 'Fri', 'Sat', 'Sun']
mapping = {day: i for i, day in enumerate(weekdays)}
key = df['day'].map(mapping)

而排序就很简单了:

df.iloc[key.argsort()]

撰写回答