熊猫嵌套groupby产生意外结果

时间:2019-07-30 13:35:28

标签: python pandas pandas-groupby

我正在研究在熊猫DataFrame上使用嵌套groupby.apply的问题。在第一个应用中,我将添加一个列,用于第二个内部groupby.apply。合并的结果对我来说似乎是错误的。谁能向我解释为什么出现以下现象以及如何可靠地解决它?

这是一个最小的示例:

import numpy as np
import pandas as pd

T = np.array( [
        [1,1,1],
        [1,1,1],
        [1,2,2],
        [1,2,2],
        [2,1,3],
        [2,1,3],
        [2,2,4],
        [2,2,4],
])

df = pd.DataFrame(T, columns= ['a','b','c' ])

print(df)


def foo2(x):
    return x

def foo(x):

    print("*" * 80 )

    # Add column d and groupby/apply on column 'd'
    x['d'] = [1, 1, 2, 2]
    x = x.groupby('d').apply(foo2)

    print(x)

    print("*" * 80)
    return x


# Apply first groupby/apply on column 'a'
df = df.groupby('a').apply( foo)

print("*"*80)
print("*"*80)

print(df)

当我在Windows笔记本电脑上运行上述代码时,我得到了预期的结果

     a  b  c  d
a              
1 0  1  1  1  1
  1  1  1  1  1
  2  1  2  2  2
  3  1  2  2  2
2 4  2  1  3  1
  5  2  1  3  1
  6  2  2  4  2
  7  2  2  4  2

在Mac上运行相同的代码即可

     a  b  c  d
a              
1 0  1  1  1  1
  1  1  1  1  1
  2  1  2  2  2
  3  1  2  2  2
2 4  1  1  3  1
  5  1  1  3  1
  6  1  2  4  2
  7  1  2  4  2

这里的问题是,在“ a”列中,最后4个条目为1,而在Windows计算机上应为2。

编辑:

两个版本的熊猫版本:0.24.2

Windows上的Python版本:3.7.3

Mac上的Python版本:3.7.4

1 个答案:

答案 0 :(得分:1)

[Mac,Python:3.6.8]

我的想法是,嵌套DataFrame.apply的预期行为将有点难以调试。我的建议是通过仿效apply(即先映射再缩小)来实现目标:

  1. 地图:使用python的本机map方法,然后
  2. 减少:使用pandas.concat合并结果
import numpy as np
import pandas as pd

def my_apply(df, f):
    return pd.concat(map(f, df))

def foo(x):
    group, grouped = x
    grouped['d'] = [1, 1, 2, 2]
    return grouped.groupby('d').apply(lambda x: x)

T = np.array([[1,1,1]]*2 + [[1,2,2]]*2 +
             [[2,1,3]]*2 + [[2,2,4]]*2)           
df = pd.DataFrame(T, columns= ['a','b','c' ])
df = my_apply(df.groupby('a'), foo)
print(df)

结果:

   a  b  c  d
0  1  1  1  1
1  1  1  1  1
2  1  2  2  2
3  1  2  2  2
4  2  1  3  1
5  2  1  3  1
6  2  2  4  2
7  2  2  4  2

注意:

  1. 我尚未尝试解决导致Mac / Windows之间性能差异的实现/体系结构上的差异]
  2. 我已经简化了您的示例,将foo2替换为lambda,随时可以调换。
  3. 以上代码将引发以下警告A value is trying to be set on a copy of a slice from a DataFrame [...]。这是因为我们故意设置副本的值。这是预期的行为,而不是错误。不幸的是,pandas将此操作解释为错误,因为通常可能是错误的。