Python pandas如何获取groupby的反向结果

4

我有两个数据框,它们除了一个列之外都是相同的。我想根据第一个数据框中的平均值更改第二个数据框的列。对于后者,我必须使用groupby,但是我不知道如何得到反转。以下是一个最小化的例子,在这个特定的例子中,df_two应该和df_one一样。我的问题是如何从tmp获得df2_new-请参阅下面的代码。

import pandas as pd


def foo(df1, df2):
    # Group by A
    groupsA_one = dict(list(df1.groupby('A', as_index=False)))
    groupsA_two = dict(list(df2.groupby('A', as_index=False)))

    for key_A in groupsA_one:
        # Group by B
        groupsB_one = dict(list(groupsA_one[key_A].groupby('B', as_index=False)))
        groupsB_two = dict(list(groupsA_two[key_A].groupby('B', as_index=False)))

        for key_B in groupsB_one:
            # Group by C
            tmp = groupsB_two[key_B].groupby('C', as_index=False)['D'].mean()   # Returns DataFrame with NaN
            tmp['D'] = groupsB_one[key_B].groupby('C', as_index=False)['D'].mean()['D']
            print tmp

    df2_new = []        # ???
    return df2_new

if __name__ == '__main__':
    A1 = {'A': [1, 1, 1, 1, 2, 2, 2, 2], 'B': [1, 1, 2, 2, 1, 1, 2, 2],
          'C': [1, 2, 1, 2, 1, 2, 1, 2], 'D': [5, 5, 5, 5, 5, 5, 5, 5]}
    A2 = {'A': [1, 1, 1, 1, 2, 2, 2, 2], 'B': [1, 1, 2, 2, 1, 1, 2, 2],
          'C': [1, 2, 1, 2, 1, 2, 1, 2], 'D': [0, 0, 0, 0, 0, 0, 0, 0]}
    df_one = pd.DataFrame(A1)
    df_two = pd.DataFrame(A2)
    foo(df_one, df_two)

你是否正在寻找transform?这将返回一个数据框,其索引与lhs数据框对齐。 - EdChum
嗯,我不确定。我的做法如下:首先按'A',然后按'B'和'C'分组df1和df2。在'C'级别上,我计算df1的组的平均值,并将其赋给df2的组。因为这是一个简单的例子,所以这个平均值实际上是一个恒等式,但通常不是这样的。我希望对df2组的分配也可以在df2或df2_new中看到。pandas能做到吗? - user3176500
是的,我认为这就是你想要的,最好添加预期输出以使其更清晰。 - EdChum
期望的输出是 A2['D'] = A1['D'],因此在转换后,df_two 应该与 df_one 相同。我只是在看 .transform,但当我有几个层次的 groupby 时,我不知道如何使用它。 - user3176500
3个回答

8
我认为这对某些情况可能更简单:
groupby = dfm.groupby('variable')
for ix, row in reversed(tuple(groupby)):
    ...

0
#Do a group by on df_one on A, B, and C and find the mean
    df_group = df_one.groupby(['A','B','C']).mean()

#Change the index
    df_two.index = [df_two['A'],df_two['B'],df_two['C']]

#Transfer the value of mean from D to 
    df_two['D'] = df_group['D']

0

这是我想要的解决方案。如果您发现更优雅的解决方案,我将很高兴将其设置为正确答案。

这就是它:

import pandas as pd
import numpy as np


def foo(df):
    # Group by A
    groups_a_one = dict(list(df.groupby('A', as_index=False)))

    for key_a in groups_a_one:
        # Group by B
        groups_b_one = dict(list(groups_a_one[key_a].groupby('B', as_index=False)))

        for key_b in groups_b_one:
            # Group by C
            tmp = groups_b_one[key_b].groupby('C', as_index=False).transform(lambda x: x.fillna(x.mean()))
            df.ix[tmp.index, 'D'] = tmp['D']# assign mean values to correct lines in df

    return df

if __name__ == '__main__':
    A1 = {'A': [1, 1, 1, 1, 2, 2, 2, 2], 'B': [1, 1, 2, 2, 1, 1, 2, 2],
          'C': [1, 2, 1, 2, 1, 2, 1, 2], 'D': [5, 5, 5, 5, 5, 5, 5, 5]}
    A2 = {'A': [1, 1, 1, 1, 2, 2, 2, 2], 'B': [1, 1, 2, 2, 1, 1, 2, 2],
          'C': [1, 2, 1, 2, 1, 2, 1, 2], 'D': [np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN, np.NaN]}
    df_one = pd.DataFrame(A1)
    df_two = pd.DataFrame(A2)
    df = pd.concat([df_one, df_two], axis=0, ignore_index=True)# To get only one DataFrame

    # run the transform
    foo(df)

这是初始状态和最终状态:

# Initial
    A  B  C  D
0   1  1  1  5
1   1  1  2  5
2   1  2  1  5
3   1  2  2  5
4   2  1  1  5
5   2  1  2  5
6   2  2  1  5
7   2  2  2  5
8   1  1  1  NaN
9   1  1  2  NaN
10  1  2  1  NaN
11  1  2  2  NaN
12  2  1  1  NaN
13  2  1  2  NaN
14  2  2  1  NaN
15  2  2  2  NaN

# Final
    A  B  C  D
0   1  1  1  5
1   1  1  2  5
2   1  2  1  5
3   1  2  2  5
4   2  1  1  5
5   2  1  2  5
6   2  2  1  5
7   2  2  2  5
8   1  1  1  5
9   1  1  2  5
10  1  2  1  5
11  1  2  2  5
12  2  1  1  5
13  2  1  2  5
14  2  2  1  5
15  2  2  2  5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接