【问题标题】:Pair rows in Pandas DataFrame if condition met如果满足条件,则在 Pandas DataFrame 中配对行
【发布时间】:2021-08-05 09:27:23
【问题描述】:

假设我有一个如下所示的 DataFrame:

df = pd.DataFrame({
    'group':['A', 'A', 'A', 'B', 'B', 'C'], 
    'amount':[100, -100, 50, 30, -30, 40]
})

如果我想添加另一列来检查每行的数量是否可以在组内配对(即相同数量,但 1 个正数和 1 个负数)。

例如A组中100&-100可以配对,则为True,而50找不到配对则为False(如下表)。

group amount pair
A 100 True
A -100 True
A 50 False
B 30 True
B -30 True
C 40 False

最有效的方法是什么?

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    我们可以取amount列的abs,然后根据值在DataFrame.duplicated的位置创建pair列:

    df['pair'] = df.assign(amount=df['amount'].abs()).duplicated(keep=False)
    

    *keep=False 表示两个重复的行都得到True。如果 DataFrame 的列多于这两列,右侧也可以是 subset

    df:

      group  amount   pair
    0     A     100   True
    1     A    -100   True
    2     A      50  False
    3     B      30   True
    4     B     -30   True
    5     C      40  False
    

    更新以处理重复值,但确保使用 pivot_table 仅匹配正负对:

    更新的数据框:

    df = pd.DataFrame({
        'group': ['A', 'A', 'A', 'A', 'B', 'B', 'C'],
        'amount': [100, -100, 50, 50, 30, -30, 40]
    })
    

    转为宽格式并检查配对:

    df['abs_amount'] = df['amount'].abs()
    df = df.join(
        df.pivot_table(index=['group', 'abs_amount'],
                       columns=df['amount'].gt(0),
                       values='amount',
                       aggfunc='first')
            .notnull().all(axis=1)
            .rename('pair'),
        on=['group', 'abs_amount']
    ).drop('abs_amount', axis=1)
    

    df:

      group  amount   pair
    0     A     100   True
    1     A    -100   True
    2     A      50  False
    3     A      50  False
    4     B      30   True
    5     B     -30   True
    6     C      40  False
    

    pivot_table:

    df['abs_amount'] = df['amount'].abs()
    df.pivot_table(index=['group', 'abs_amount'],
                   columns=df['amount'].gt(0),
                   values='amount',
                   aggfunc='first')
    
    amount            False   True
    group abs_amount              
    A     50            NaN   50.0  # Multiple 50s but no -50
          100        -100.0  100.0
    B     30          -30.0   30.0
    C     40            NaN   40.0
    

    确保行中的所有值:

    df.pivot_table(index=['group', 'abs_amount'],
                   columns=df['amount'].gt(0),
                   values='amount',
                   aggfunc='first').notnull().all(axis=1)
    
    group  abs_amount
    A      50            False
           100            True
    B      30             True
    C      40            False
    dtype: bool
    

    【讨论】:

    • 小改进 df.assign(pair = df['amount'].abs().duplicated(keep=False))
    • 但是如果 C 的数量是 100 呢?然后 C (idx 5) pair 将被标记为 True,即使 C 中没有匹配的值。@BENY
    • 我只是想知道一组中是否有 3 100 个
    • 嗨@HenryEcker,我发现如果说A组的数量为[100,-100,50,50],那么这种方法也会将两个50视为一对,有没有办法排除他们?
    • 已更新以确保每组仅匹配 - 和 + 对。不考虑重复。
    猜你喜欢
    • 2020-12-22
    • 1970-01-01
    • 2022-01-13
    • 2019-04-06
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-13
    相关资源
    最近更新 更多