在pandas/matplotlib柱状图中排序条形顺序
在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()]