【问题标题】:How to make Pareto Chart in python?如何在python中制作帕累托图?
【发布时间】:2019-05-03 19:05:21
【问题描述】:

Pareto 是 Excel 和 Tableu 中非常流行的图表。在 excel 中我们可以轻松绘制帕累托图,但我发现在 Python 中绘制图表并不容易。

我有一个这样的熊猫数据框:

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

df = pd.DataFrame({'country': [177.0, 7.0, 4.0, 2.0, 2.0, 1.0, 1.0, 1.0]})
df.index = ['USA', 'Canada', 'Russia', 'UK', 'Belgium', 'Mexico', 'Germany', 'Denmark']
print(df)

         country
USA        177.0
Canada       7.0
Russia       4.0
UK           2.0
Belgium      2.0
Mexico       1.0
Germany      1.0
Denmark      1.0

如何绘制帕累托图? 可能使用 pandas、seaborn、matplotlib 等?

到目前为止,我已经能够制作降序条形图。 但是仍然需要将累积总和线图放在它们之上。

我的尝试: df.sort_values(by='country',ascending=False).plot.bar()

所需情节:

【问题讨论】:

    标签: python pandas matplotlib seaborn pareto-chart


    【解决方案1】:

    这是我使用 pandas 和 plotly 的 Pareto 图版本。您可以将任何集合与未分组的数据一起使用。 让我们从这个例子的数据开始:

    import numpy as np
    
    data = np.random.choice(['USA', 'Canada', 'Russia', 'UK', 'Belgium',
                                    'Mexico', 'Germany', 'Denmark'], size=500,
                                     p=[0.43, 0.14, 0.23, 0.07, 0.04, 0.01, 0.03, 0.05])
    

    图表创建:

    import pandas as pd
    import plotly.graph_objects as go
    
    
    def pareto_chart(collection):
        collection = pd.Series(collection)
        counts = (collection.value_counts().to_frame('counts')
                  .join(collection.value_counts(normalize=True).cumsum().to_frame('ratio')))
    
        fig = go.Figure([go.Bar(x=counts.index, y=counts['counts'], yaxis='y1', name='count'),
                         go.Scatter(x=counts.index, y=counts['ratio'], yaxis='y2', name='cumulative ratio',
                                    hovertemplate='%{y:.1%}', marker={'color': '#000000'})])
    
        fig.update_layout(template='plotly_white', showlegend=False, hovermode='x', bargap=.3,
                          title={'text': 'Pareto Chart', 'x': .5}, 
                          yaxis={'title': 'count'},
                          yaxis2={'rangemode': "tozero", 'overlaying': 'y',
                                  'position': 1, 'side': 'right',
                                  'title': 'ratio',
                                  'tickvals': np.arange(0, 1.1, .2),
                                  'tickmode': 'array',
                                  'ticktext': [str(i) + '%' for i in range(0, 101, 20)]})
    
        fig.show()
    

    结果:

    【讨论】:

      【解决方案2】:

      pandas.dataframe 的排列图

      import pandas as pd
      import matplotlib.pyplot as plt
      from matplotlib.ticker import PercentFormatter
      
      
      def _plot_pareto_by(df_, group_by, column):
      
          df = df_.groupby(group_by)[column].sum().reset_index()
          df = df.sort_values(by=column,ascending=False)
      
          df["cumpercentage"] = df[column].cumsum()/df[column].sum()*100
      
      
          fig, ax = plt.subplots(figsize=(20,5))
          ax.bar(df[group_by], df[column], color="C0")
          ax2 = ax.twinx()
          ax2.plot(df[group_by], df["cumpercentage"], color="C1", marker="D", ms=7)
          ax2.yaxis.set_major_formatter(PercentFormatter())
      
          ax.tick_params(axis="y", colors="C0")
          ax2.tick_params(axis="y", colors="C1")
      
          for tick in ax.get_xticklabels():
              tick.set_rotation(45)
          plt.show()
      

      【讨论】:

        【解决方案3】:

        ImportanceOfBeingErnest 代码的更通用版本:

        def create_pareto_chart(df, by_variable, quant_variable):
            df.index = by_variable
            df["cumpercentage"] = quant_variable.cumsum()/quant_variable.sum()*100
        
            fig, ax = plt.subplots()
            ax.bar(df.index, quant_variable, color="C0")
            ax2 = ax.twinx()
            ax2.plot(df.index, df["cumpercentage"], color="C1", marker="D", ms=7)
            ax2.yaxis.set_major_formatter(PercentFormatter())
        
            ax.tick_params(axis="y", colors="C0")
            ax2.tick_params(axis="y", colors="C1")
            plt.show()
        

        而且这个也包括帕累托,它根据阈值进行分组。 例如:如果您将其设置为 70,它将把超过 70 的少数民族归为一组,称为“其他”。

        def create_pareto_chart(by_variable, quant_variable, threshold):
        
            total=quant_variable.sum()
            df = pd.DataFrame({'by_var':by_variable, 'quant_var':quant_variable})
            df["cumpercentage"] = quant_variable.cumsum()/quant_variable.sum()*100
            df = df.sort_values(by='quant_var',ascending=False)
            df_above_threshold = df[df['cumpercentage'] < threshold]
            df=df_above_threshold
            df_below_threshold = df[df['cumpercentage'] >= threshold]
            sum = total - df['quant_var'].sum()
            restbarcumsum = 100 - df_above_threshold['cumpercentage'].max()
            rest = pd.Series(['OTHERS', sum, restbarcumsum],index=['by_var','quant_var', 'cumpercentage'])
            df = df.append(rest,ignore_index=True)
            df.index = df['by_var']
            df = df.sort_values(by='cumpercentage',ascending=True)
        
            fig, ax = plt.subplots()
            ax.bar(df.index, df["quant_var"], color="C0")
            ax2 = ax.twinx()
            ax2.plot(df.index, df["cumpercentage"], color="C1", marker="D", ms=7)
            ax2.yaxis.set_major_formatter(PercentFormatter())
        
            ax.tick_params(axis="x", colors="C0", labelrotation=70)
            ax.tick_params(axis="y", colors="C0")
            ax2.tick_params(axis="y", colors="C1")
        
            plt.show()
        

        【讨论】:

        • 您使用什么版本的 matplotlib 来让 tick_params(labelrotation=70) 工作?当我运行这个命令时,我得到一个错误,labelrotation 无法识别。
        【解决方案4】:

        另一种方法是使用secondary_y 参数而不使用twinx()

        df['pareto'] = 100 *df.country.cumsum() / df.country.sum()
        fig, axes = plt.subplots()
        ax1 = df.plot(use_index=True, y='country',  kind='bar', ax=axes)
        ax2 = df.plot(use_index=True, y='pareto', marker='D', color="C1", kind='line', ax=axes, secondary_y=True)
        ax2.set_ylim([0,110])
        

        参数use_index=True 是必需的,因为在这种情况下您的index 是您的x 轴。否则你可以使用x='x_Variable'

        【讨论】:

          【解决方案5】:

          您可能希望创建一个包含百分比的新列,并将一列绘制为条形图,另一列绘制为双轴中的折线图。

          import pandas as pd
          import matplotlib.pyplot as plt
          from matplotlib.ticker import PercentFormatter
          
          df = pd.DataFrame({'country': [177.0, 7.0, 4.0, 2.0, 2.0, 1.0, 1.0, 1.0]})
          df.index = ['USA', 'Canada', 'Russia', 'UK', 'Belgium', 'Mexico', 'Germany', 'Denmark']
          df = df.sort_values(by='country',ascending=False)
          df["cumpercentage"] = df["country"].cumsum()/df["country"].sum()*100
          
          
          fig, ax = plt.subplots()
          ax.bar(df.index, df["country"], color="C0")
          ax2 = ax.twinx()
          ax2.plot(df.index, df["cumpercentage"], color="C1", marker="D", ms=7)
          ax2.yaxis.set_major_formatter(PercentFormatter())
          
          ax.tick_params(axis="y", colors="C0")
          ax2.tick_params(axis="y", colors="C1")
          plt.show()
          

          【讨论】:

          • 你知道我们如何根据百分比对其他人进行分组吗?比方说,将 98 后的其他人相加并显示为一组(条形图)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-06-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多