如何在熊猫数据框的行之间应用多个条件创建目标数据框

Posted

技术标签:

【中文标题】如何在熊猫数据框的行之间应用多个条件创建目标数据框【英文标题】:How to creat a target dataframe applying multiple condition between the rows of a panda dataframe 【发布时间】:2021-12-05 22:42:36 【问题描述】:

我问下面的问题,因为我没有找到任何合适的答案,基于 data-framedifferent rows 上的 multiple condition 应用。

我有下面的data-frame 我想在其rows 上应用multiple condition 以创建一个新的data-frame

    timestamp      t_id b_id    id   b_sent   lc
0   6/1/2020 9:00   25  1       C_0  25      540
1   6/1/2020 9:00   25  1       C_1  25      540
2   6/1/2020 9:00   25  1       C_2  25      540
3   6/1/2020 9:00   25  1       C_3  28      478
4   6/1/2020 9:00   25  1       V_0  25      NA
5   6/1/2020 9:00   25  1       V_1  25      NA
6   6/1/2020 9:00   25  1       V_2  25      NA
7   6/1/2020 9:00   25  1       V_3  91      NA
8   6/1/2020 9:00   25  2       C_0  26      510
9   6/1/2020 9:00   25  2       C_1  26      510
10  6/1/2020 9:00   25  2       C_2  27      510
11  6/1/2020 9:00   25  2       C_3  32      300
12  6/1/2020 9:00   25  2       V_0  26      NA
13  6/1/2020 9:00   25  2       V_1  26      NA
14  6/1/2020 9:00   25  2       V_2  26      NA
15  6/1/2020 9:00   25  2       V_3  26      NA

16  6/1/2020 9:30   25  1       C_0  10      140
17  6/1/2020 9:30   25  1       C_1  20      340
18  6/1/2020 9:30   25  1       C_2  25      240
19  6/1/2020 9:30   25  1       C_3  30      578
20  6/1/2020 9:30   25  1       V_0  25      NA
21  6/1/2020 9:30   25  1       V_1  25      NA
22  6/1/2020 9:30   25  1       V_2  25      NA
23  6/1/2020 9:30   25  1       V_3  91      NA
24  6/1/2020 9:30   25  2       C_0  15      140
25  6/1/2020 9:30   25  2       C_1  20      340
26  6/1/2020 9:30   25  2       C_2  35      240
27  6/1/2020 9:30   25  2       C_3  40      578
28  6/1/2020 9:30   25  2       V_0  25      NA
29  6/1/2020 9:30   25  2       V_1  35      NA
30  6/1/2020 9:30   25  2       V_2  45      NA
31  6/1/2020 9:30   25  2       V_3  25      NA

输出将基于以下条件,timestamps 应该相同:

b_sent_new = b_sent(b_id==1,id=='C_0') + b_sent(b_id==2,id=='V_0')   
b_sent_new = b_sent(b_id==1,id=='C_1') + b_sent(b_id==2,id=='V_1')
b_sent_new = b_sent(b_id==1,id=='C_2') + b_sent(b_id==2,id=='V_2')
b_sent_new = b_sent(b_id==1,id=='C_3') + b_sent(b_id==2,id=='V_3')
and vice verca
b_sent_new = b_sent(b_id==2,id=='C_0') + b_sent(b_id==1,id=='V_0')   
b_sent_new = b_sent(b_id==2,id=='C_1') + b_sent(b_id==1,id=='V_1')
b_sent_new = b_sent(b_id==2,id=='C_2') + b_sent(b_id==1,id=='V_2')
b_sent_new = b_sent(b_id==2,id=='C_3') + b_sent(b_id==1,id=='V_3')

例如,b_sent_new 值将是 b_sent 值,其中 b_id=1id=C_0 加上 b_sent 值,其中 b_id=2id=V_0 在同一“时间戳”内

更准确地说,对于b_id 值1,对应C_0b_sent_new 值将是b_idC_0b_sent 值加上11b_sentb_id2

想要的输出:

    timestamp         t_id  b_id    id   b_sent   lc    b_sent_new
    0   6/1/2020 9:00   25  1       C_0  25      540    51  
    1   6/1/2020 9:00   25  1       C_1  26      540    53 
    2   6/1/2020 9:00   25  1       C_2  22      540    50  
    3   6/1/2020 9:00   25  1       C_3  28      478    47   
    4   6/1/2020 9:00   25  2       C_0  30      510    48  
    5   6/1/2020 9:00   25  2       C_1  31      510    47  
    6   6/1/2020 9:00   25  2       C_2  32      510    49  
    7   6/1/2020 9:00   25  2       C_3  33      300    51
    8   6/1/2020 9:30   25  1       C_0  10      140    35
    9   6/1/2020 9:30   25  1       C_1  20      340    55
   10   6/1/2020 9:30   25  1       C_2  25      240    70
   11   6/1/2020 9:30   25  1       C_3  30      578    55
   12   6/1/2020 9:30   25  2       C_0  15      140    40
   13   6/1/2020 9:30   25  2       C_1  20      340    45
   14   6/1/2020 9:30   25  2       C_2  35      240    60
   15   6/1/2020 9:30   25  2       C_3  40      578    131

我目前遵循的方法没有给我适当的输出:

box_1 = df[df.b_id.isin(["1"])].reset_index(drop = True)
box_2 = df[df.b_id.isin(["2"])].reset_index(drop = True)

box_1['new'] = np.where((box_1['timestamp'] == box_2['timestamp'] ) & (box_1['id']=="C_0") & (box_2['id'].shift(-4)=="V_0"), box_1['b_sent']+box_2['b_sent'].shift(-4), np.nan)
box_1['new'] = np.where((box_1['timestamp'] == box_2['timestamp'] ) & (box_1['id']=="C_1") & (box_2['id'].shift(-4)=="V_1"), box_1['b_sent']+box_2['b_sent'].shift(-4), np.nan)
box_1['new'] = np.where((box_1['timestamp'] == box_2['timestamp'] ) & (box_1['id']=="C_2") & (box_2['id'].shift(-4)=="V_2"), box_1['b_sent']+box_2['b_sent'].shift(-4), np.nan)
box_1['new'] = np.where((box_1['timestamp'] == box_2['timestamp'] ) & (box_1['id']=="C_3") & (box_2['id'].shift(-4)=="V_3"), box_1['b_sent']+box_2['b_sent'].shift(-4), np.nan)

任何帮助/建议将不胜感激。

【问题讨论】:

请多解释一下逻辑,并按原样添加最终数据帧,不要使用 cmets @sammywemmy 解释了逻辑并编辑了输出,希望这会更清楚。 【参考方案1】:

可能有更友好的方式来执行此操作,但这应该可以帮助您入门。它创建了一个更广泛的数据框,您必须对其进行修改以满足您的需求(删除列和重命名标题)。我将其保留是为了让您了解发生了什么。

基本上,我在日期 id 上使用 groupby 拆分您的数据框,并在最后将它们拼凑在一起。

另外,根据您的输入,我不认为您对 b_sent_new 的预期输出计算都是正确的。如果我在这里错了,请告诉我。

dflist = []
def calc_new(x):
    # print(x[(x['b_id']==1) & (x['id'].str.contains('C_'))].sort_values(['timestamp', 'b_id'], ascending=[True, True]).reset_index(drop=True))
    # print(x[(x['b_id']==2) & (x['id'].str.contains('V_'))].sort_values(['timestamp', 'b_id'], ascending=[True, True]).reset_index(drop=True))
    # print(x[(x['b_id']==1) & (x['id'].str.contains('V_'))].sort_values(['timestamp', 'b_id'], ascending=[True, True]).reset_index(drop=True))
    # print(x[(x['b_id']==2) & (x['id'].str.contains('C_'))].sort_values(['timestamp', 'b_id'], ascending=[True, True]).reset_index(drop=True))

    a = x[(x['b_id']==1) & (x['id'].str.contains('C_'))].sort_values(['timestamp', 'b_id'], ascending=[True, True]).reset_index(drop=True)
    b = x[(x['b_id']==2) & (x['id'].str.contains('V_'))].sort_values(['timestamp', 'b_id'], ascending=[True, True]).reset_index(drop=True)
    c = x[(x['b_id']==1) & (x['id'].str.contains('V_'))].sort_values(['timestamp', 'b_id'], ascending=[True, True]).reset_index(drop=True)
    d = x[(x['b_id']==2) & (x['id'].str.contains('C_'))].sort_values(['timestamp', 'b_id'], ascending=[True, True]).reset_index(drop=True)
    
    e = a.merge(b, left_index=True, right_index=True)
    e['b_sent_new'] = e['b_sent_x'] + e['b_sent_y']
    # print(e)
    f = d.merge(c, left_index=True, right_index=True)
    f['b_sent_new'] = f['b_sent_x'] + f['b_sent_y']
    # print(f)
    dflist.append(e)
    dflist.append(f)
    return None
    
dft = df.groupby('timestamp').apply(calc_new)
# dflist
final_df = pd.concat(dflist)
final_df

     timestamp_x  t_id_x  b_id_x id_x  b_sent_x   lc_x    timestamp_y  t_id_y  b_id_y id_y  b_sent_y  lc_y  b_sent_new
0  6/1/2020 9:00      25       1  C_0        25  540.0  6/1/2020 9:00      25       2  V_0        26   NaN          51
1  6/1/2020 9:00      25       1  C_1        25  540.0  6/1/2020 9:00      25       2  V_1        26   NaN          51
2  6/1/2020 9:00      25       1  C_2        25  540.0  6/1/2020 9:00      25       2  V_2        26   NaN          51
3  6/1/2020 9:00      25       1  C_3        28  478.0  6/1/2020 9:00      25       2  V_3        26   NaN          54
0  6/1/2020 9:00      25       2  C_0        26  510.0  6/1/2020 9:00      25       1  V_0        25   NaN          51
1  6/1/2020 9:00      25       2  C_1        26  510.0  6/1/2020 9:00      25       1  V_1        25   NaN          51
2  6/1/2020 9:00      25       2  C_2        27  510.0  6/1/2020 9:00      25       1  V_2        25   NaN          52
3  6/1/2020 9:00      25       2  C_3        32  300.0  6/1/2020 9:00      25       1  V_3        91   NaN         123
0  6/1/2020 9:30      25       1  C_0        10  140.0  6/1/2020 9:30      25       2  V_0        25   NaN          35
1  6/1/2020 9:30      25       1  C_1        20  340.0  6/1/2020 9:30      25       2  V_1        35   NaN          55
2  6/1/2020 9:30      25       1  C_2        25  240.0  6/1/2020 9:30      25       2  V_2        45   NaN          70
3  6/1/2020 9:30      25       1  C_3        30  578.0  6/1/2020 9:30      25       2  V_3        25   NaN          55
0  6/1/2020 9:30      25       2  C_0        15  140.0  6/1/2020 9:30      25       1  V_0        25   NaN          40
1  6/1/2020 9:30      25       2  C_1        20  340.0  6/1/2020 9:30      25       1  V_1        25   NaN          45
2  6/1/2020 9:30      25       2  C_2        35  240.0  6/1/2020 9:30      25       1  V_2        25   NaN          60
3  6/1/2020 9:30      25       2  C_3        40  578.0  6/1/2020 9:30      25       1  V_3        91   NaN         131

【讨论】:

谢谢! @Jonathan Leon 获取此代码!它对我来说非常完美。虽然它需要一点时间,但由于我庞大的数据集的大小,它可以忽略不计。 谢谢!很高兴它奏效了。我无法理解矢量化它,所以 apply() 就是这样。

以上是关于如何在熊猫数据框的行之间应用多个条件创建目标数据框的主要内容,如果未能解决你的问题,请参考以下文章

创建由多个数据框组成的多级熊猫数据框的最快方法是啥?

在给定“映射数据框”的情况下爆炸熊猫数据框的行

如何在遍历熊猫数据框时创建新列并插入行值

如何按列绘制数据框的多个字典?蟒蛇熊猫

根据条件保留熊猫数据框的上 n 行

熊猫数据框:在进行涉及两个数据框的算术运算时如何在多个索引级别上进行匹配