【问题标题】:Pandas - find and iterate rows with matching values in multiple columns and multiply value in another columnPandas - 在多列中查找和迭代具有匹配值的行并在另一列中相乘
【发布时间】:2019-01-20 06:50:42
【问题描述】:

这个问题比我的previous one更进一步:

我编辑了表格以减少混乱

首先假设我们下面有一个数据框:

data = pd.DataFrame({'id':['1','2','3','4','5','6','7','8','9','10'], 
                 'A':['foo', 'bar', 'foo', 'bar','foo', 'bar', 'foo', 'foo','foo','bar'],  
                 'C':['10','10','10','50','50','50','50','8','10','20'], 
                 'D':['10','9','8','7','6','5','4','3','2','1']})

如下:

      A  C   D  id
0   foo 10  10  1
1   bar 10  9   2
2   foo 10  8   3
3   bar 50  7   4
4   foo 50  6   5
5   bar 50  5   6
6   foo 50  4   7
7   foo 8   3   8
8   foo 10  2   9
9   bar 20  1   10

我想做的是找到匹配的行,然后做一些计算。

for any two ids(idx, idy) in data.iterrows():
       if idx.A == idy.A and idx.C = idy.C:
       result = idx.D * idy.D

然后生成一个包含三列['id']['A']['result'] 的新数据框。

@Jon Clements♦ 在下面用非常简洁的代码回答了我之前的问题:

   df.merge(
        df.groupby(['A', 'C']).D.agg(['prod', 'count'])
        [lambda r: r['count'] > 1],
        left_on=['A', 'C'],
        right_index=True
    )

新目标:

现在我想知道是否有一种方法可以在 row_a 与 row_b 匹配后不再对其进行迭代。换句话说,我将这两个匹配的行视为一对。一旦 row_a 和 row_b 成为一对,进一步的循环将忽略 row_a(直到 row_b 匹配到另一行才忽略 row_b)。

groupby().agg('prod', 'count')函数为例,我希望生成的所有结果中的'count'都是2(不仅仅是带有['count'] == 2的过滤器)。我不认为使用groupby() 会起作用所以我认为像for-loop 这样的机制可以解决这个问题吗?还是有更好的方法?

所以现在的预期结果是(因为 id1 和 id3 已经成为一对所以它不会聚合到 id9,并且对于其余的迭代 id3 将不会与 id1 匹配。所以对于下表,第一行的结果是 80但不是 160,第二行也不是):

     id   A   result   
0    1   foo   80   
1    3   foo   16
2    4   bar   35
3    5   foo   24

我的英语不是很好,所以我不确定我是否清楚地解释了我的问题。有什么不清楚的可以问我。

感谢您的帮助。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    有点冗长的解决方案,远没有 Jon Clements 为您解决第一个问题的原始解决方案那么优雅。但我想出了一个不需要 for 循环的解决方案。

    # sort values by A,C,id
    df = df.sort_values(['A','C','id'])
    # find where A and C are equal when shifted down by 1
    s=(df[['A','C']] == df[['A','C']].shift()).T.apply(lambda x: x.A and x.C)
    
    # create a new series where we take the value of D of whe A and C are equal
    # and multiply it with the next value - since it's sorted it should be next A,C match
    new_d = (df.iloc[df[s].index].reset_index().D * df.iloc[df[s].index+1].reset_index().D)
    new_d.index = df.iloc[df[s].index].index
    new_d.name = 'results'
    
    print(new_d)
    Output >
    0    80
    3    35
    4    24
    2    16
    Name: results, dtype: int64
    

    采用上述方法,我们只需在df 中创建一个新列并将其分配给new_d

    # create a new column in df and assign it to new_d
    df['results'] = new_d
    
    df.dropna()[['id','A','results']].sort_values('id')
    

    输出:

        id  A   results
    0   1   foo 80.0
    2   3   foo 16.0
    3   4   bar 35.0
    4   5   foo 24.0
    

    【讨论】:

      猜你喜欢
      • 2019-01-19
      • 2020-07-28
      • 2020-10-03
      • 2016-06-04
      • 1970-01-01
      • 2021-10-13
      • 1970-01-01
      • 2021-08-02
      • 2020-11-12
      相关资源
      最近更新 更多