从第二个数据框根据两列的比较添加列

2024-10-02 14:18:02 发布

您现在位置:Python中文网/ 问答频道 /正文

简单地说,我试图通过比较air_id和{}列中的值,将latitude和{}从{}添加到一个更小的名为df2的数据框中:

enter image description here

latitude和{}添加到df2的技巧取决于如何对{}进行比较,这可能是以下三种情况之一:

  • df2.air_id和{}之间存在匹配时
  • df2.hpg_id和{}之间存在匹配时
  • 当两者都匹配时:[df2.air_id, df2.hpg_id]和{}

考虑到这一点,预期结果应该是:

enter image description here

请注意df1中的ignore_me列是如何被排除在结果数据帧之外的。在

以下是设置数据帧的代码:

data = { 'air_id'     : [ 'air1',     '', 'air3', 'air4', 'air2', 'air1' ], 
         'hpg_id'     : [ 'hpg1', 'hpg2',     '', 'hpg4',     '',     '' ], 
         'latitude'   : [  101.1,  102.2,    103,    104,    102, 101.1, ],
         'longitude'  : [     51,     52,     53,     54,     52,    51, ],
         'ignore_me'  : [     91,     92,     93,     94,     95,    96 ] }

df1 = pd.DataFrame(data)
display(df1)


data2 = { 'air_id'    : [     '',  'air2', 'air3', 'air1' ], 
          'hpg_id'    : [ 'hpg1',  'hpg2',     '',     '' ]  }

df2 = pd.DataFrame(data2)
display(df2)

不幸的是,我无法将merge()用于此任务。我当前的结果是一个DataFrame,其中来自df1的所有列都填充了NaNs

enter image description here

如何使用上述规则从df1复制这些特定列?在


Tags: 数据iddataframedataairmedf1ignore
3条回答

用电视台和数字广播来处理资料的匹配。。。撒上仙尘

ids = ['air_id', 'hpg_id']
cols = ['latitude', 'longitude']

def true(s): return s.astype(bool)

s2 = df2.stack().loc[true].groupby(level=0).apply(set)
s1 = df1[ids].stack().loc[true].groupby(level=0).apply(set)

i, j = np.where((s1.values & s2.values[:, None]).astype(bool))

a = np.zeros((len(df2), 2), int)
a[i, :] = df1[cols].values[j]

df2.join(pd.DataFrame(a, df2.index, cols))

  air_id hpg_id  latitude  longitude
0          hpg1       101         51
1   air2   hpg2       102         52
2   hpg3              103         53

详细信息

s2看起来像这样

^{pr2}$

s1

0    {air1, hpg1}
1          {hpg2}
2          {hpg3}
3    {air4, hpg4}
4          {air2}
dtype: object

关键是我们想找出该行中的任何内容是否与另一个数据帧中的行中的任何其他内容匹配。现在我可以使用广播和&

s1.values & s2.values[:, None]

array([[{'hpg1'}, set(), set(), set(), set()],
       [set(), {'hpg2'}, set(), set(), {'air2'}],
       [set(), set(), {'hpg3'}, set(), set()]], dtype=object)

但是在布尔上下文中,空集的值为False,因此

(s1.values & s2.values[:, None]).astype(bool)

array([[ True, False, False, False, False],
       [False,  True, False, False,  True],
       [False, False,  True, False, False]], dtype=bool)

现在我可以使用np.where来显示这些True在哪里

i, j = np.where((s1.values & s2.values[:, None]).astype(bool))

print(i, j)

[0 1 1 2] [0 1 4 2]

它们分别是df2和{}中的行。但是我不需要两行1,所以我创建了一个大小合适的空数组,期望覆盖1行。我用df1中的lat和lon填充这些值

a = np.zeros((len(df2), 2), int)
a[i, :] = df1[cols].values[j]

a

array([[101,  51],
       [102,  52],
       [103,  53]])

然后我用pd.DataFrame将其包装起来,并按上面所示进行连接。在

这是一种没有合并的手动方式。它不是有效的,但是如果它对您的用例有足够的性能,那么它可能是可管理的。在

df1['lat_long'] = list(zip(df1['latitude'], df1['longitude']))

air = df1[df1['air_id'] != ''].set_index('air_id')['lat_long']
hpg = df1[df1['hpg_id'] != ''].set_index('hpg_id')['lat_long']

def mapper(row):
    myair, myhpg = row['air_id'], row['hpg_id']
    if (myair != '') and (myair in air):
        return air.get(myair)
    elif (myhpg != '') and (myhpg in hpg):
        return hpg.get(myhpg)
    elif (myair != '') and (myair in hpg):
        return hpg.get(myair)
    elif (myhpg != '') and (myhpg in air):
        return air.get(myhpg)
    else:
        return (None, None)

df2['lat_long'] = df2.apply(mapper, axis=1)
df2[['latitude', 'longitude']] = df2['lat_long'].apply(pd.Series)
df2 = df2.drop('lat_long', 1)

#   air_id hpg_id  latitude  longitude
# 0          hpg1       101         51
# 1   air2   hpg2       102         52
# 2   hpg3              103         53

这里有一种方法可以让你完成你想做的事情。在

首先使用merge()两次。首先在air_id上,然后在hpg_id上。对于这两种情况,当键是空字符串时,忽略小的情况。在

result = df2\
    .merge(
        df1[df1['air_id']!=''].drop(['hpg_id'], axis=1), on=['air_id'], how='left'
    )\
    .merge(
        df1[df1['hpg_id']!=''].drop(['air_id'], axis=1), on=['hpg_id'], how='left'
    )

print(result)
#  air_id hpg_id  ignore_me_x  latitude_x  longitude_x  ignore_me_y  \
#0          hpg1          NaN         NaN          NaN           91   
#1   air2   hpg2         92.0       102.0         52.0           92   
#2          hpg3          NaN         NaN          NaN           93   
#
#   latitude_y  longitude_y  
#0         101           51  
#1         102           52  
#2         103           53 

但是,这会为所需的列创建重复项。(每次调用merge时,我都会删除另一个join键,以避免这些调用出现重复的列名。)

我们可以通过采用this post上描述的方法之一来合并这些值。在

^{pr2}$

更新

在合并产生重复项的情况下,可以使用^{}。在

result = result.drop_duplicates()

相关问题 更多 >