【问题标题】:Sorting the dataframe based on the count of one column and plot根据一列的计数对数据框进行排序并绘图
【发布时间】:2021-10-17 21:38:34
【问题描述】:

我的数据框中有两列:

winner    opening_shortname
0      White         Slav Defense
1      Black  Nimzowitsch Defense
2      White     King's Pawn Game
3      White    Queen's Pawn Game
4      White     Philidor Defense
...      ...                  ...
20053  White        Dutch Defense
20054  Black         Queen's Pawn
20055  White    Queen's Pawn Game
20056  White         Pirc Defense
20057  Black    Queen's Pawn Game

我想创建下面的图,前 10 名开局及其获胜者颜色比例 (%)。

【问题讨论】:

  • 获胜者栏目是否正确?看起来像一个索引,是这个意图吗?

标签: python pandas dataframe sorting matplotlib


【解决方案1】:
topk = 10
z = df.groupby(['opening_shortname', 'winner']).size().unstack()
ax = z.loc[z.sum(1).sort_values().tail(topk).index].plot.barh(color=['black', 'white'], edgecolor='black')
ax.xaxis.set_visible(False)

这按打开 的流行程度排序,限制在顶部 k(例如 OP 问题中的 10)。问题中提到的“比例 (%)”不明确:提供的图表清楚地显示了从顶部开口到下一个开口的总数递减,并且水平轴被移除。

无论如何,根据您提供的示例数据:

【讨论】:

  • 这样数据框没有排序
  • 简单到可以修复。另外,我不购买“比例(%)”要求,请参阅编辑。
【解决方案2】:

假设您的数据框名称为df,您可以groupby+count+unstack。然后对总和进行排序,取前 10 个进行绘图:

df2 = (df.assign(count=1)
         .groupby(['winner', 'opening_shortname'])
         .count()
         .unstack(level=0)
         .droplevel(0, axis=1)
      )

# plot part
idx = df2.sum(axis=1).sort_values().head(10).index
(df2.div(df2.sum(axis=1), axis=0) # calculate the proportion
    .fillna(0)
    .loc[idx, ['White', 'Black']]
    .plot.barh(color=['w', 'k'], edgecolor='k')
)


输出:

【讨论】:

    【解决方案3】:

    首先,您应该通过以下方式重新塑造您的数据框:

    df = df.groupby(by = ['opening_shortname', 'winner']).size().reset_index().rename(columns = {'opening_shortname': 'opening_shortname', 'winner': 'winner', 0: 'count'}).sort_values(['count', 'opening_shortname', 'winner'], ascending = False, ignore_index = True)
    

    所以你会得到一个类似(假数据)的数据框:

          opening_shortname winner  count
    0     Queen's Pawn Game  White    141
    1     Queen's Pawn Game  Black    132
    2          Queen's Pawn  White     57
    3          Queen's Pawn  Black     57
    4      King's Pawn Game  Black     57
    5         Dutch Defense  Black     53
    6      Sicilian Defense  White     51
    7      Sicilian Defense  Black     50
    8   Nimzowitsch Defense  White     46
    9   Nimzowitsch Defense  Black     45
    10     Philidor Defense  Black     44
    11         Slav Defense  White     43
    12         Pirc Defense  White     42
    13         Slav Defense  Black     39
    14         Pirc Defense  Black     38
    15     King's Pawn Game  White     38
    16        Dutch Defense  White     36
    17     Philidor Defense  White     31
    

    然后你可以绘制你的数据,例如使用seaborn.barplot:

    sns.barplot(ax = ax, data = df, x = 'count', y = 'opening_shortname', hue = 'winner', palette = ['white', 'black'], edgecolor = 'black')
    

    完整代码

    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    df = pd.read_csv(r'data/data.csv')
    
    df = df.groupby(by = ['opening_shortname', 'winner']).size().reset_index().rename(columns = {'opening_shortname': 'opening_shortname', 'winner': 'winner', 0: 'count'}).sort_values(['count', 'opening_shortname', 'winner'], ascending = False, ignore_index = True)
    
    
    fig, ax = plt.subplots()
    
    sns.barplot(ax = ax, data = df, x = 'count', y = 'opening_shortname', hue = 'winner', palette = ['white', 'black'], edgecolor = 'black')
    
    plt.show()
    


    如果你想绘制相对比例来代替count,那么你可以在上面的代码中添加一行:

    df['count'] = df['count']/df.groupby('opening_shortname')['count'].transform('sum')
    

    完整代码

    import pandas as pd
    import matplotlib.pyplot as plt
    import seaborn as sns
    
    df = pd.read_csv(r'data/data.csv')
    
    df = df.groupby(by = ['opening_shortname', 'winner']).size().reset_index().rename(columns = {'opening_shortname': 'opening_shortname', 'winner': 'winner', 0: 'count'}).sort_values(['count', 'opening_shortname', 'winner'], ascending = False, ignore_index = True)
    df['count'] = df['count']/df.groupby('opening_shortname')['count'].transform('sum')
    
    
    fig, ax = plt.subplots()
    
    sns.barplot(ax = ax, data = df, x = 'count', y = 'opening_shortname', hue = 'winner', palette = ['white', 'black'], edgecolor = 'black')
    
    plt.show()
    

    【讨论】:

    • 我意识到你和我都忘记了获得比例的要求,而不是计数;)
    • 谢谢,答案已相应更新:-)
    • 感谢您的回复,但未选择前 10 名。
    猜你喜欢
    • 2018-03-30
    • 1970-01-01
    • 1970-01-01
    • 2015-11-06
    • 2020-05-15
    • 2020-02-29
    • 1970-01-01
    • 2015-08-21
    • 2012-09-03
    相关资源
    最近更新 更多