Pandas - 在两列中查找具有匹配值的行并在另一列中相乘

Posted

技术标签:

【中文标题】Pandas - 在两列中查找具有匹配值的行并在另一列中相乘【英文标题】:Pandas - find rows with matching values in two columns and multiply value in another column 【发布时间】:2019-01-19 08:31:47 【问题描述】:

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

import pandas as pd
data = pd.DataFrame('id':['1','2','3','4','5','6','7','8'], 
                     'A':['foo', 'bar', 'foo', 'bar','foo', 'bar', 'foo', 'foo'],  
                     'C':['10','10','10','30','50','60','50','8'], 
                     'D':['9','8','7','6','5','4','3','2'])
print(data)

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

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

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'] 的新数据框。

所以几行预期的结果是:

     id   A   result   
0    1   foo   63   
1    3   foo   63   
2    5   foo   15
3    7   foo   15

我试过了,但结果要么是错误的逻辑,要么是错误的代码/数据格式。 有人可以帮帮我吗?

【问题讨论】:

我的回答有用吗? 【参考方案1】:

您可以使用自连接技术:

data[['id', 'C', 'D']] = data[['id', 'C', 'D']].apply(pd.to_numeric)
joint = pd.merge(data, data, on=('A', 'C'))
joint = joint.loc[join['id_x'] != join['id_y']]
joint['result'] = joint['D_x'] * joint['D_y']
result = joint[['id_x', 'A', 'result']]
result.columns = ['id', 'A', 'result']

结果

   id    A  result
1   1  foo      63
2   3  foo      63
7   5  foo      15
8   7  foo      15

【讨论】:

更好更快joint['result'] = joint['D_x'] * joint['D_y'] 而不是joint['result'] = joint.apply(lambda x: x['D_x'] * x['D_y'], axis=1) 也可以这样做:joint = pd.merge(data, data, on=('A', 'C'))[lambda r: r.id_x != r.id_y] 但它可能更慢... 我得到 'function' 对象不可下标且无法运行 先生,当我尝试处理大型数据集时,您的回答会导致内存错误。你有什么解决办法吗? @Lev Zakharov【参考方案2】:

一种方法是按A + C分组,取产品并计数,过滤掉组中只有一个项目的那些,然后在A + C上内部合并回您的原始框架,例如:

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

给你:

     A   C  D  id  prod  count
0  foo  10  9   1    63      2
2  foo  10  7   3    63      2
4  foo  50  5   5    15      2
6  foo  50  3   7    15      2

然后根据需要删除/重命名列。

【讨论】:

我很困惑。 OP 是否要求过滤组中行数的特定行?我将问题编辑为few rows of the output would be,在他解释他想要什么时,他没有说他没有添加只会返回计数为2的那些行的逻辑部分。 嗯好吧。我按照他的逻辑走。 您好,先生,我有一个与此相关的new question。你介意花点时间检查一下吗?谢谢!【参考方案3】:
import pandas as pd
data = pd.DataFrame('id':['1','2','3','4','5','6','7','8'], 
                     'A':['foo', 'bar', 'foo', 'bar','foo', 'bar', 'foo', 'foo'],  
                     'C':['10','10','10','30','50','60','50','8'], 
                     'D':['9','8','7','6','5','4','3','2'])

先将相关列转换为数值

data[['C', 'D', 'id']] = data[['C', 'D', 'id']].apply(pd.to_numeric)

创建空的 DataFrame 以追加到

finalDataFrame = pd.DataFrame()

groupby两列,然后在组内找到列D的乘积并追加。

group = data.groupby(['A', 'C'])
for x, y in group:


    product = (y[["D"]].product(axis=0).values[0])


    for row in y.index:
        y.at[row, 'D'] = product

    finalDataFrame = finalDataFrame.append(y, ignore_index=True)

output = finalDataFrame[['id', 'A', 'D']]
output = output.rename(columns = 'D': 'result')
print(output)

给你

   id    A  result
0   2  bar       8
1   4  bar       6
2   6  bar       4
3   8  foo       2
4   1  foo      63
5   3  foo      63
6   5  foo      15
7   7  foo      15

【讨论】:

以上是关于Pandas - 在两列中查找具有匹配值的行并在另一列中相乘的主要内容,如果未能解决你的问题,请参考以下文章

Pandas:在多列中查找具有匹配值的行的 Pythonic 方法(分层条件)

pandas:删除两列中具有相同索引的行中的重复值

从数据框中删除重复项,基于两列 A,B,在另一列 C 中保持具有最大值的行

SQL - 选择两列中具有相同值的行

遍历 pandas 数据框中的行并匹配列表中的元组并创建一个新的 df 列

Pandas GroupBy 并选择特定列中具有最小值的行