【问题标题】:groupby in pandas with custom function over a subset of rows in each grouppandas 中的 groupby 对每个组中的行子集具有自定义函数
【发布时间】:2022-11-24 20:05:31
【问题描述】:

我有以下格式的 pandas DataFrame:

输入:

                                     X    [OTHER_COLUMNS]
version     branch                      
v1          overall  2475.0         -1         .
            A        1712.5          1         .
            B         257.5          2         .
            C         392.5          2
            D         112.5          3
v2          overall  2475.0         -1
            A        2341.5          1
            B          95.0          2
            C          38.5          2
v3          overall  2475.0         -1
            A        2000.0          1
            B         475.0          2
v4          overall  2475.0         -1
            A        2341.5          1
            B         133.5          1

其中 (version, branch) 是一个 MultiIndex。

问题描述:

我想 groupby version 并将 Xbranch overall 列中的值设置为其余分支的 X 列中值的总和(具有相同的 version) ,由 N 列中的值加权。

例子:

对于versionv2Xbranchoverall列的单元格中的值应该是

(2341.5 * 1 + 95.0 * 2 + 38.5 * 2) / 2475.0 = 1.05393939394,

在伪代码中:

(A_N * A_X + B_N * B_X) / overall_N

注意:对于给定的versionNbranchoverall列中的值将始终等于N列中其他branch的值的总和。

想法和问题:

我想我必须执行以下操作:

df.loc[pd.IndexSlice[:, 'overall'], 'X'] = df.groupby('version').apply(...)

其中 df 是 DataFrame,... 将被自定义函数替换。

我正在寻求构建此类功能的帮助。

预期产出:

                          N          X
version     branch                      
v1          overall  2475.0          1.35353535354
            A        1712.5          1
            B         257.5          2
            C         392.5          2
            D         112.5          3
v2          overall  2475.0          1.05393939394
            A        2341.5          1
            B          95.0          2
            C          38.5          2
v3          overall  2475.0          1.19191919192
            A        2000.0          1
            B         475.0          2
v4          overall  2475.0          1
            A        2341.5          1
            B         133.5          1

预期输出的解释:

(1712.5 * 1 + 257.5 * 2 + 392.5 * 2 + 112.5 * 3) / 2475.0 = 1.35353535354

(2341.5 * 1 + 95.0 * 2 + 38.5 * 2) / 2475.0 = 1.05393939394

(2000.0 * 1 + 475.0 * 2) / 2475.0 = 1.19191919192

(2341.5 * 1 + 133.5 * 1) / 2475.0 = 1

创建数据框的代码:

import numpy as np
import pandas as pd
    
df = pd.DataFrame(
    data=np.array(
        [
            [2475.0, 1712.5, 257.5, 392.5, 112.5, 2475.0, 2341.5, 95.0, 38.5, 2475.0, 2000.0, 475.0, 2475.0, 2341.5, 133.5],
            [-1, 1, 2, 2, 3, -1, 1, 2, 2, -1, 1, 2, -1, 1, 1]
        ]
    ).T,
    index=pd.MultiIndex.from_tuples(
        tuples=[
            ('v1', 'overall'),
            ('v1', 'A'),
            ('v1', 'B'),
            ('v1', 'C'),
            ('v1', 'D'),
            ('v2', 'overall'),
            ('v2', 'A'),
            ('v2', 'B'),
            ('v2', 'C'),
            ('v3', 'overall'),
            ('v3', 'A'),
            ('v3', 'B'),
            ('v4', 'overall'),
            ('v4', 'A'),
            ('v4', 'B'),
        ],
        names=['version', 'branch'],
    ),
    columns=['N', 'X'],
)

print (df)
                      N    X
version branch              
v1      overall  2475.0 -1.0
        A        1712.5  1.0
        B         257.5  2.0
        C         392.5  2.0
        D         112.5  3.0
v2      overall  2475.0 -1.0
        A        2341.5  1.0
        B          95.0  2.0
        C          38.5  2.0
v3      overall  2475.0 -1.0
        A        2000.0  1.0
        B         475.0  2.0
v4      overall  2475.0 -1.0
        A        2341.5  1.0
        B         133.5  1.0

【问题讨论】:

    标签: python pandas group-by aggregate


    【解决方案1】:

    利用:

    #select overalls only
    overall = df['N'].xs('overall', level=1)
    #select all rows without overalls
    df1 = df.drop('overall', level=1)
    
    #multiple and aggregate sum, divide overalls   
    s = df1['N'].mul(df1['X']).groupby(level=0).sum().div(overall)
    
    #create MultiIndex and assign back
    df.loc[pd.IndexSlice[:, 'overall'], 'X'] = pd.concat({'overall':s}).swaplevel(0,1)
    

    print (df)
                          N         X
    version branch                   
    v1      overall  2475.0  1.353535
            A        1712.5  1.000000
            B         257.5  2.000000
            C         392.5  2.000000
            D         112.5  3.000000
    v2      overall  2475.0  1.053939
            A        2341.5  1.000000
            B          95.0  2.000000
            C          38.5  2.000000
    v3      overall  2475.0  1.191919
            A        2000.0  1.000000
            B         475.0  2.000000
    v4      overall  2475.0  1.000000
            A        2341.5  1.000000
            B         133.5  1.000000
    

    【讨论】:

    • 当我运行它时,结果与预期结果完全不同。基本上,“X”列现在全是零和一,除了一个条目 0.691919。
    • @Filip - 输入数据与Input部分中提到的不同,有问题。
    • 啊,谢谢! :)
    • @Filip - 顺便说一句,非常好的一个很好的问题,超级!!!
    猜你喜欢
    • 1970-01-01
    • 2019-06-26
    • 2019-06-08
    • 2017-08-04
    • 2017-11-05
    • 2023-01-23
    • 1970-01-01
    • 2020-10-05
    • 1970-01-01
    相关资源
    最近更新 更多