有条件地合并pd.DataFrames

时间:2019-08-07 19:25:41

标签: python pandas dataframe

我想知道大熊猫是否有可能

  • 我要从df2创建new1new2
  • new1作为最新日期,可以从df1中找到与A列匹配的日期 和B。
  • new2作为最新日期,可以从df1中找到与A列匹配的日期 但不是B。
  • 我设法获得new1,但没有得到new2

代码:

import pandas as pd

d1 = [['1/1/19', 'xy','p1','54'], ['1/1/19', 'ft','p2','20'], ['3/15/19', 'xy','p3','60'],['2/5/19', 'xy','p4','40']]

df1 = pd.DataFrame(d1, columns = ['Name', 'A','B','C']) 

d2 =[['12/1/19', 'xy','p1','110'], ['12/10/19', 'das','p10','60'], ['12/20/19', 'fas','p50','40']]

df2 = pd.DataFrame(d2, columns = ['Name', 'A','B','C'])

d3 = [['12/1/19', 'xy','p1','110','1/1/19','3/15/19'], ['12/10/19', 'das','p10','60','0','0'], ['12/20/19', 'fas','p50','40','0','0']]

dfresult = pd.DataFrame(d3, columns = ['Name', 'A','B','C','new1','new2']) 

已更新!

2 个答案:

答案 0 :(得分:0)

您可以通过以下方式实现:

  • 基于A的标准合并
  • 删除所有与B值匹配的条目
  • 排序日期
  • 将重复项放在A上,保留最后一个日期(n.b.假定日期采用日期格式,而不是字符串!)
  • 合并回id

因此:

source = df1.copy()  # renamed
v = df2.merge(source, on='A', how='left')  # get all values where df2.A == source.A
v = v[v['B_x'] != v['B_y']]  # drop entries where B values are the same
nv = v.sort_values(by=['Name_y']).drop_duplicates(subset=['Name_x'], keep='last')
df2.merge(nv[['Name_y', 'Name_x']].rename(columns={'Name_y': 'new2', 'Name_x': 'Name'}),
          on='Name', how='left')  # keeps non-matching, consider inner

这将产生:

Out[94]: 
       Name    A    B    C     new2
0   12/1/19   xy   p1  110  3/15/19
1  12/10/19  das  p10   60      NaN
2  12/20/19  fas  p50   40      NaN

我最初的想法是做类似下面的事情。可悲的是,它并不优雅。通常,这种确定某些价值的方法之所以受到人们的欢迎,主要是因为它无法扩展且数据量很大,变得特别慢。

def find_date(row, source=df1):  # renamed df1 to source
    t = source[source['B'] != row['B']]
    t = t[t['A'] == row['A']]
    return t.sort_values(by='date', ascending=False).iloc[0]

df2['new2'] = df2.apply(find_date, axis=1)

答案 1 :(得分:0)

IIUC,您想向df2添加两列:new1new2

首先,我修改了两件事:

df1 = pd.DataFrame(d1, columns = ['Name1', 'A','B','C']) 

df2 = pd.DataFrame(d2, columns = ['Name2', 'A','B','C'])

df1.Name1 = pd.to_datetime(df1.Name1)

为了方便使用,将Name重命名为Name1Name2。然后,我将Name1设置为实际日期,因此我们可以按组获取最大日期。

然后,我们将A列上的df2与df1合并。这将为我们提供与该列匹配的行

aux = df2.merge(df1, on='A')

然后,当两个数据帧上的B列相同时,我们从中得到Name1

df2['new1'] = df2.index.map(aux[aux.B_x==aux.B_y].Name1).fillna(0)

如果它们不同,我们将为每个A组获得最长日期:

df2['new2'] = df2.A.map(aux[aux.B_x!=aux.B_y].groupby('A').Name1.max()).fillna(0)

输出:

      Name2    A    B    C                 new1                 new2
0   12/1/19   xy   p1  110  2019-01-01 00:00:00  2019-03-15 00:00:00
1  12/10/19  das  p10   60                    0                    0
2  12/20/19  fas  p50   40                    0                    0