Python Pandas,如何避免使用iterrow(如何根据另一个数据帧中的值为数据帧中的新列赋值)

Python Pandas,如何避免使用iterrow(如何根据另一个数据帧中的值为数据帧中的新列赋值),python,pandas,merge,iteration,left-join,Python,Pandas,Merge,Iteration,Left Join,我有三个不同的实体:机会,账户,活动 我需要以一种特殊的方式将它们结合起来。让我解释一下它们之间的关系: 机会N-1客户 账户1-N活动 另外,值得注意的是 Opportunity具有以下字段:{opp\u id;opp\u date;acc\u id} 活动具有以下字段:{act\u id;act\u date;acc\u id} 我想要实现的是,在Opportunity中插入Opportunity日期前X天完成的活动数量 我现在是这样做的: a_new_df = pd.DataFra

我有三个不同的实体:机会账户活动

我需要以一种特殊的方式将它们结合起来。让我解释一下它们之间的关系:

  • 机会N-1客户
  • 账户1-N活动
另外,值得注意的是

  • Opportunity具有以下字段:
    {opp\u id;opp\u date;acc\u id}
  • 活动具有以下字段:
    {act\u id;act\u date;acc\u id}
我想要实现的是,在Opportunity中插入Opportunity日期前X天完成的活动数量

我现在是这样做的:

a_new_df = pd.DataFrame(columns=['acc_id',"opp_id", "opp_date", "act_90", "act_180"])

for index, opp_row in Opportunity.iterrows():
    account = opp_row["acc_id"]
    opportunity = opp_row["opp_id"]
    opp_date = opp_row["opp_date"]
    act_90, act_180 = 0, 0
    for index, act_row in activities_step_7.iterrows():
        if acc == act_row["acc_id"]:
            days = (pd.to_datetime(opp_date) - pd.to_datetime(act_row["act_date"])).days
            if days<=90:
                act_90+=1
            elif days<=180:
                act_180+=1
    events_df = events_df.append({
        "acc_id": account,
        "opp_id":  opportunity,
        "opp_date" : dat,
        "act_90" :  act_90,
        "act_180" : act_180,    
      }, ignore_index=True)
这是我的活动表:

    opp_date    acc_id  opp_id
0   05.08.2019  acc1    opp1
1   25.03.2019  acc2    opp2
2   27.08.2019  acc1    opp3
3   02.09.2019  acc1    opp4
4   22.07.2019  acc3    opp5
    acc_id  act_date
0   acc1    25.07.2019
1   acc1    26.07.2019
2   acc1    31.07.2019 
3   acc1    28.07.2019
4   acc1    02.09.2019 
5   acc1    02.09.2019 
6   acc1    31.07.2019 
7   acc1    02.09.2019 
8   acc1    24.07.2019 
9   acc1    25.07.2019 
10  acc2    31.03.2019 
11  acc3    31.07.2019 
12  acc2    24.03.2019 
13  acc3    13.05.2019 
14  acc3    05.02.2019
15  acc3    30.05.2016 
16  acc3    30.11.2017 
17  acc3    11.04.2016 
18  acc3    19.01.2018 
19  acc3    19.01.2018 
20  acc2    24.03.2019 
21  acc1    04.08.2019
22  acc1    20.10.2019
    opp_date        acc_id  opp_id      act_90  act_180
0   05.08.2019      acc1    opp1        4       4   
1   25.03.2019      acc2    opp2        0       0   
2   27.08.2019      acc1    opp3        7       8   
3   02.09.2019      acc1    opp4        0       0   
4   22.07.2019      acc3    opp5        2       2   
则预期输出为:

    opp_date    acc_id  opp_id
0   05.08.2019  acc1    opp1
1   25.03.2019  acc2    opp2
2   27.08.2019  acc1    opp3
3   02.09.2019  acc1    opp4
4   22.07.2019  acc3    opp5
    acc_id  act_date
0   acc1    25.07.2019
1   acc1    26.07.2019
2   acc1    31.07.2019 
3   acc1    28.07.2019
4   acc1    02.09.2019 
5   acc1    02.09.2019 
6   acc1    31.07.2019 
7   acc1    02.09.2019 
8   acc1    24.07.2019 
9   acc1    25.07.2019 
10  acc2    31.03.2019 
11  acc3    31.07.2019 
12  acc2    24.03.2019 
13  acc3    13.05.2019 
14  acc3    05.02.2019
15  acc3    30.05.2016 
16  acc3    30.11.2017 
17  acc3    11.04.2016 
18  acc3    19.01.2018 
19  acc3    19.01.2018 
20  acc2    24.03.2019 
21  acc1    04.08.2019
22  acc1    20.10.2019
    opp_date        acc_id  opp_id      act_90  act_180
0   05.08.2019      acc1    opp1        4       4   
1   25.03.2019      acc2    opp2        0       0   
2   27.08.2019      acc1    opp3        7       8   
3   02.09.2019      acc1    opp4        0       0   
4   22.07.2019      acc3    opp5        2       2   

您可以使用一些内置函数来代替for循环。这个结果与您在问题中发布的“预期输出”略有不同,但我认为它符合您的描述

让我们调用第一个数据帧
df1
,然后调用第二个数据帧
df2

我们可以通过将其写为函数并应用它(而不是在行上迭代)来计算符合您条件的活动数:

def count_activities(row, act_df, days):
    return (act_df['act_date'].between(row['opp_date'] -pd.Timedelta(days=days), row['opp_date']) 
            & (act_df['acc_id']==row['acc_id'])).sum()
因为我们在上面的函数中进行计数,所以连接不是问题:

def add_count_activities_column(opp_df, act_df, days):
    return opp_df.join(opp_df.apply(lambda row: count_activities(row,act_df,days), axis=1).rename('act_{}'.format(days)))
结果是:

df3 = add_count_activities_column(df1, df2, 90)
df3 = add_count_activities_column(df3, df2, 180)
我的
df3

    opp_date    acc_id  opp_id  act_90  act_180
0   2019-05-08  acc1    opp1    4   4
1   2019-03-25  acc2    opp2    2   2
2   2019-08-27  acc1    opp3    7   8
3   2019-02-09  acc1    opp4    3   3
4   2019-07-22  acc3    opp5    2   2

p、 我会使用
opp\u id
作为索引,使用
df1。set\u index('opp\u id',inplace=True)

你能添加一些虚拟数据和它的输出吗?我相信你的代码中也有一些拼写错误(最后几行:
accout
opportunity
)。完成了,不容易,但完成了;)谢谢你给我看打字错误!在预期输出中,为什么第二行有0?acc2在该日期前一天执行了两个操作。一个操作在opportunity日期之后,而第二个操作返回0作为天,可能是因为一些近似值。这至少快了50倍,不,我不想检查确切的比率。谢谢!有没有关于如何改进标题的建议,以便其他用户可以找到这个问题?类似于“如何根据另一个数据帧中的值为数据帧中的新列赋值”这样的建议?