【问题标题】:How to plot stacked & normalized histograms?如何绘制堆叠和归一化直方图?
【发布时间】:2017-08-21 19:13:43
【问题描述】:

我有一个将连续值映射到离散类别的数据集。我想显示一个直方图,其中连续值为 x,类别为 y,其中条形图是堆叠和标准化的。示例:

import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt

df = pd.DataFrame({ 
        'score' : np.random.rand(1000), 
        'category' : np.random.choice(list('ABCD'), 1000) 
    },
    columns=['score', 'category'])

print df.head(10)

输出:

      score category
0  0.649371        B
1  0.042309        B
2  0.689487        A
3  0.433064        B
4  0.978859        A
5  0.789140        C
6  0.215758        D
7  0.922389        B
8  0.105364        D
9  0.010274        C

如果我尝试使用df.hist(by='category') 将其绘制为直方图,我会得到 4 个图表:

我设法得到了我想要的图表,但我必须做很多操作。

# One column per category, 1 if maps to category, 0 otherwise
df2 = pd.DataFrame({
        'score' : df.score,
        'A' : (df.category == 'A').astype(float),
        'B' : (df.category == 'B').astype(float),
        'C' : (df.category == 'C').astype(float),
        'D' : (df.category == 'D').astype(float)
    },
    columns=['score', 'A', 'B', 'C', 'D'])

# select "bins" of .1 width, and sum for each category
df3 = pd.DataFrame([df2[(df2.score >= (n/10.0)) & (df2.score < ((n+1)/10.0))].iloc[:, 1:].sum() for n in range(10)])

# Sum over series for weights
df4 = df3.sum(1)

bars = pd.DataFrame(df3.values / np.tile(df4.values, [4, 1]).transpose(), columns=list('ABCD'))

bars.plot.bar(stacked=True)

我希望有一种更直接的方法可以做到这一点,更易于阅读和理解,并且通过更少的中间步骤进行更优化。有什么解决办法吗?

【问题讨论】:

    标签: python pandas numpy matplotlib


    【解决方案1】:

    我不知道这是否真的比你已经得到的更紧凑或更易读,但这是一个建议(一个迟到的建议:))。

    import numpy as np
    import pandas as pd
    
    df = pd.DataFrame({ 
            'score' : np.random.rand(1000), 
            'category' : np.random.choice(list('ABCD'), 1000) 
        }, columns=['score', 'category'])
    
    # Set the range of the score as a category using pd.cut
    df.set_index(pd.cut(df['score'], np.linspace(0, 1, 11)), inplace=True)
    
    # Count all entries for all scores and all categories
    a = df.groupby([df.index, 'category']).size() 
    # Normalize
    b = df.groupby(df.index)['category'].count()
    df_a = a.div(b, axis=0,level=0)
    
    # Plot
    df_a.unstack().plot.bar(stacked=True)
    

    【讨论】:

      【解决方案2】:

      考虑用cut 分配箱,用几个groupby().transform 调用计算分组百分比,然后用pivot_table 聚合和重塑:

      # CREATE BIN INDICATORS
      df['plot_bins'] = pd.cut(df['score'], bins=np.arange(0,1.1,0.1), 
                               labels=np.arange(0,1,0.1)).round(1)
      
      # CALCULATE PCT OF CATEGORY OUT OF BINs
      df['pct'] = (df.groupby(['plot_bins', 'category'])['score'].transform('count')
                     .div(df.groupby(['plot_bins'])['score'].transform('count')))
      
      # PIVOT TO AGGREGATE + RESHAPE
      agg_df = (df.pivot_table(index='plot_bins', columns='category', values='pct', aggfunc='max')
                  .reset_index(drop=True))
      # PLOT
      agg_df.plot(kind='bar', stacked=True, rot=0)
      

      【讨论】:

        猜你喜欢
        • 2011-01-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-30
        • 2019-02-12
        • 2014-03-12
        • 2018-02-06
        • 1970-01-01
        相关资源
        最近更新 更多