是否在pandas.DataFrame中的两列之间分组函数?

是否在pandas.DataFrame中的两列之间分组函数?,pandas,grouping,correlation,Pandas,Grouping,Correlation,我有一个dataframe,它有多个数字数据列和一个“group”列。我想得到每个组的两列上各种函数的输出 示例数据和功能: df = pandas.DataFrame({"Dummy":[1,2]*6, "X":[1,3,7]*4, "Y":[2,3,4]*4, "group":["A","B"]*6}) def RMSE(X): return(np.sqrt(np.sum((X.iloc[:,0] - X.iloc[:,1])**2)))

我有一个dataframe,它有多个数字数据列和一个“group”列。我想得到每个组的两列上各种函数的输出

示例数据和功能:

df = pandas.DataFrame({"Dummy":[1,2]*6, "X":[1,3,7]*4, 
                       "Y":[2,3,4]*4, "group":["A","B"]*6})

def RMSE(X):
  return(np.sqrt(np.sum((X.iloc[:,0] - X.iloc[:,1])**2)))
我想做一些像

group_correlations = df[["X", "Y"]].groupby('group').apply(RMSE)
但如果我这样做,“group”列就不在数据帧中。如果我反过来做,像这样:

group_correlations = df.groupby('group')[["X", "Y"]].apply(RMSE)
然后,列选择不起作用:

df.groupby('group')[['X', 'Y']].head(1)

         Dummy  X  Y group
group                     
A     0      1  1  2     A
B     1      2  3  3     B
虚拟列仍然包括在内,因此函数将根据错误的数据计算RMSE

有什么办法可以做我想做的事吗?我知道我可以在不同的组上执行for循环,并手动选择子列,但如果有,我更喜欢按熊猫的方式执行。

这看起来像个bug(或者没有实现在groupby中捕获多个列?),解决方法是直接传入groupby列:

In [11]: df[['X', 'Y']].groupby(df['group']).apply(RMSE)
Out[11]:
group
A        4.472136
B        4.472136
dtype: float64
要知道这是一样的:

In [12]: df.groupby('group')[['X', 'Y']].apply(RMSE)  # wrong
Out[12]:
group
A        8.944272
B        7.348469
dtype: float64

In [13]: df.iloc[:, 1:].groupby('group')[['X', 'Y']].apply(RMSE)  # correct: ignore dummy col
Out[13]:
group
A        4.472136
B        4.472136
dtype: float64
更稳健的实施: 为了完全避免这种情况,您可以将RMSE更改为按名称选择列:

In [21]: def RMSE2(X, left_col, right_col):
             return(np.sqrt(np.sum((X[left_col] - X[right_col])**2)))

In [22]: df.groupby('group').apply(RMSE2, 'X', 'Y')  # equivalent to passing lambda x: RMSE2(x, 'X', 'Y'))
Out[22]:
group
A        4.472136
B        4.472136
dtype: float64

感谢@NOTT101指出了避免lambda的sweet apply语法。

谢谢,第一个解决方案很好,但后两个解决方案并不可移植(到不同的列集)。由于这可能是一个bug(),我认为您的第一个解决方案可能是目前最好的解决方案。@将列名传递到RMSE2也可以工作/使其更易于移植是不是RMSE函数适用于
.apply(RMSE)
(即使没有分组)?我发誓它在一分钟前对我有效,但现在似乎不是…@101你必须使用axis=1,即
df.apply(RMSE2,1)
。谢谢你,安迪。Apply实际上正确地传递了值,因此不需要lambda。我编辑了答案以使用更简单的语法,并避免使用lambda。