【问题标题】:Solution for SpecificationError: nested renamer is not supported while agg() along with groupby()SpecificationError 的解决方案:在 agg() 和 groupby() 时不支持嵌套重命名器
【发布时间】:2020-02-14 15:40:33
【问题描述】:
def stack_plot(data, xtick, col2='project_is_approved', col3='total'):
    ind = np.arange(data.shape[0])

    plt.figure(figsize=(20,5))
    p1 = plt.bar(ind, data[col3].values)
    p2 = plt.bar(ind, data[col2].values)

    plt.ylabel('Projects')
    plt.title('Number of projects aproved vs rejected')
    plt.xticks(ind, list(data[xtick].values))
    plt.legend((p1[0], p2[0]), ('total', 'accepted'))
    plt.show()

def univariate_barplots(data, col1, col2='project_is_approved', top=False):
    # Count number of zeros in dataframe python: https://stackoverflow.com/a/51540521/4084039
    temp = pd.DataFrame(project_data.groupby(col1)[col2].agg(lambda x: x.eq(1).sum())).reset_index()

    # Pandas dataframe grouby count: https://stackoverflow.com/a/19385591/4084039
    temp['total'] = pd.DataFrame(project_data.groupby(col1)[col2].agg({'total':'count'})).reset_index()['total']

    temp['Avg'] = pd.DataFrame(project_data.groupby(col1)[col2].agg({'Avg':'mean'})).reset_index()['Avg']

    temp.sort_values(by=['total'],inplace=True, ascending=False)

    if top:
        temp = temp[0:top]

    stack_plot(temp, xtick=col1, col2=col2, col3='total')
    print(temp.head(5))
    print("="*50)
    print(temp.tail(5))

univariate_barplots(project_data, 'school_state', 'project_is_approved', False)

错误:

SpecificationError                        Traceback (most recent call last)
<ipython-input-21-2cace8f16608> in <module>()
----> 1 univariate_barplots(project_data, 'school_state', 'project_is_approved', False)

<ipython-input-20-856fcc83737b> in univariate_barplots(data, col1, col2, top)
      4 
      5     # Pandas dataframe grouby count: https://stackoverflow.com/a/19385591/4084039
----> 6     temp['total'] = pd.DataFrame(project_data.groupby(col1)[col2].agg({'total':'count'})).reset_index()['total']
      7     print (temp['total'].head(2))
      8     temp['Avg'] = pd.DataFrame(project_data.groupby(col1)[col2].agg({'Avg':'mean'})).reset_index()['Avg']

~\AppData\Roaming\Python\Python36\site-packages\pandas\core\groupby\generic.py in aggregate(self, func, *args, **kwargs)
    251             # but not the class list / tuple itself.
    252             func = _maybe_mangle_lambdas(func)
--> 253             ret = self._aggregate_multiple_funcs(func)
    254             if relabeling:
    255                 ret.columns = columns

~\AppData\Roaming\Python\Python36\site-packages\pandas\core\groupby\generic.py in _aggregate_multiple_funcs(self, arg)
    292             # GH 15931
    293             if isinstance(self._selected_obj, Series):
--> 294                 raise SpecificationError("nested renamer is not supported")
    295 
    296             columns = list(arg.keys())

SpecificationError: **nested renamer is not supported**

【问题讨论】:

  • 在 StackOverflow 上不鼓励仅使用代码的答案,仅使用代码的帖子也是如此。请解释一下这个过程。
  • 如果您尝试聚合并且数据框中不存在一个或多个列,您也可能会收到此错误
  • @ConfusionMatrix 希望我早点看到 - 这是一个非常有用的指针,带有不那么直观的错误消息。谢谢!

标签: python pandas aggregate


【解决方案1】:

改变

temp['total'] = pd.DataFrame(project_data.groupby(col1)[col2].agg({'total':'count'})).reset_index()['total']

temp['Avg'] = pd.DataFrame(project_data.groupby(col1)[col2].agg({'Avg':'mean'})).reset_index()['Avg']

temp['total'] = pd.DataFrame(project_data.groupby(col1)[col2].agg(total='count')).reset_index()['total']
temp['Avg'] = pd.DataFrame(project_data.groupby(col1)[col2].agg(Avg='mean')).reset_index()['Avg']

原因:在新的 pandas 版本中,命名聚合是建议替代已弃用的“dict-of-dicts”方法来命名列特定聚合的输出(Deprecate groupby.agg() with a dictionary when renaming).

来源:https://pandas.pydata.org/pandas-docs/stable/whatsnew/v0.25.0.html

【讨论】:

  • 如何将多个函数放入聚合中?例如添加最小值和最大值
  • 将它们添加为关键字参数,例如.agg(avg="mean", total="count")
【解决方案2】:

如果聚合函数dict中指定的列在数据框中不存在,也会发生此错误:

In [190]: group = pd.DataFrame([[1, 2]], columns=['A', 'B']).groupby('A')
In [195]: group.agg({'B': 'mean'})
Out[195]: 
   B
A   
1  2

In [196]: group.agg({'B': 'mean', 'non-existing-column': 'mean'})
...
SpecificationError: nested renamer is not supported

【讨论】:

  • 这个答案指向错误的实际来源。表明有另一种指定方式的另一个答案可能是正确的,但没有找到根本原因。
【解决方案3】:

我找到了方法:而不是像这样

g2 = df.groupby(["Description","CustomerID"],as_index=False).agg({'Quantity':{"maxQ":np.max,"minQ":np.min,"meanQ":np.mean}})
g2.columns = ["Description","CustomerID","maxQ","minQ",'meanQ']

按如下操作:

g2 = df.groupby(["Description","CustomerID"],as_index=False).agg({'Quantity':{np.max,np.min,np.mean}})
g2.columns = ["Description","CustomerID","maxQ","minQ",'meanQ']

我遇到了同样的错误,这就是我解决它的方法!

【讨论】:

    【解决方案4】:

    除了使用.agg({'total':'count'})),您可以将名称作为元组列表传递给函数,例如.agg([('total', 'count')]),也可以将相同的名称用于Avg。希望它会起作用。

    【讨论】:

    • 此解决方案的好处是对生成的列进行适当命名。
    【解决方案5】:

    有时保留aggdict 以说明在聚合下应如何转换每列会很方便,这将适用于不同的列集和不同的按列分组。您可以通过使用 ** 解包 dict 来相当轻松地使用新语法来做到这一点。这是简单数据的最小工作示例。

    dfx=pd.DataFrame(columns=["A","B","C"],data=np.random.randint(0,5,size=(10,3)))
    #dfx
    #
    #   A  B  C
    #0  4  4  1
    #1  2  4  4
    #2  1  3  3
    #3  2  4  3
    #4  1  2  1
    #5  0  4  2
    #6  2  3  4
    #7  1  0  2
    #8  2  1  4
    #9  3  0  3
    

    也许当你聚合时你想要第一个"A",最后一个"B",平均值"C",有时你的管道有一个"D"(但这次不是)你也想要平均值。

    aggdict = {"A":lambda x: x.iloc[0], "B": lambda x: x.iloc[-1], "C" : "mean" , "D":lambda x: "mean"}
    

    你可以像过去一样构建一个简单的dict,然后用**过滤相关键来解压它:

    gb_col="C"
    gbc = dfx.groupby(gb_col).agg(**{k:(k,v) for k,v in aggdict.items() if k in dfx.columns and k != gb_col})
    #       A  B
    #C      
    #1  4  2
    #2  0  0
    #3  1  4
    #4  2  3
    

    然后您可以使用相同的语法进行切片和切块:

    mygb = lambda gb_col: dfx.groupby(gb_col).agg(**{k:(k,v) for k,v in aggdict.items() if k in dfx.columns and k != gb_col})
    allgb = [mygb(c) for c in dfx.columns]
    

    【讨论】:

      【解决方案6】:

      如果你改变你会得到同样的错误

      temp['total'] = pd.DataFrame(project_data.groupby(col1)[col2].agg({'total':'count'})).reset_index()['total']
      

      temp['total'] = project_data.groupby(col1)[col2].agg(total=('total','count')).reset_index()['total']
      

      【讨论】:

        【解决方案7】:

        我遇到了与@akshay jindal 类似的问题,但我按照@artikay Khanna 的建议检查了文档,问题解决了,一些功能已经调整,旧的已弃用。这是每次执行时提供的代码警告。

        /usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:1: FutureWarning: using a dict on a Series for aggregation
        is deprecated and will be removed in a future version. Use                 named aggregation instead.
        
            >>> grouper.agg(name_1=func_1, name_2=func_2)
        
          """Entry point for launching an IPython kernel.
        

        因此,我会建议尝试

        grouper.agg(name_1=func_1, name_2=func_2)
        

        希望这会有所帮助

        【讨论】:

          【解决方案8】:

          不是一个非常优雅的解决方案,但这个解决方案有效。由于不推荐使用您正在做的方式重命名列。但是有解决办法。创建一个临时变量 'approved' ,将 col2 存储在其中。因为当您应用 agg function 时,原始列值将随着列名而变化。您可以保留列名,但这些列中的值会发生变化。因此,为了保留原始数据框并拥有两个具有所需名称的新列,您可以使用以下代码。

          approved = temp[col2]
          temp = pd.DataFrame(project_data.groupby(col1)[col2].agg([('Avg','mean'),('total','count')]).reset_index())
          temp[col2] = approved
          

          P.S : 好像是 AAIC 的任务,我也在做同样的工作:)

          【讨论】:

            【解决方案9】:

            我已经尝试了所有解决方案,结果是名称错误。如果您的列名包含一些内置关键字,例如“in”、“is”等,则会引发错误。就我而言,我的列名为“Points in Polygon”,我通过将列重命名为“Points”解决了这个问题

            【讨论】:

              【解决方案10】:

              @Rishi 的解决方案对我有用。我的数据框中列的原始名称是net_value_budgeted_rate,它本质上是销售的美元价值。我将其更改为 dollars 并且有效。

              【讨论】:

                【解决方案11】:
                Info = pd.DataFrame(df.groupby("school_state").agg(Approved=("project_is_approved",lambda x: x.eq(1).sum()),Total=("project_is_approved","count"),Avg=("project_is_approved","mean"))).reset_index().sort_values(by=["Total"],ascending=False).head()
                

                您可以将其分解为单独的命令以获得更好的可读性。

                【讨论】:

                  猜你喜欢
                  • 2021-08-26
                  • 2021-02-07
                  • 2020-11-24
                  • 2021-05-12
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多