根据两列

时间:2018-03-16 21:49:32

标签: python pandas dataframe join merge

简单来说,我试图通过比较latitude中的longitudedf1列,将df2air_id添加到名为hpg_id的较小数据框中{1}}和latitude列:

enter image description here

longitudedf2添加到df1的技巧取决于如何与df2.air_id进行比较,这可能是以下三种情况之一:

  • df1.air_hddf2.hpg_id;
  • 之间存在匹配时
  • df1.hpg_hd[df2.air_id, df2.hpg_id];
  • 之间存在匹配时
  • 如果两者之间匹配:[df1.air_hd, df1.hpg_id]ignore_me;

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

enter image description here

请注意df1中的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) 列是如何从结果DataFrame中删除的。

以下是设置DataFrames的代码:

merge()

不幸的是,我未能使用df1执行此任务。我当前的结果是一个DataFrame,其中df1的所有列都大部分都填充了 NaNs

enter image description here

如何使用上述规则从{ "query": { "match_phrase_prefix": { "text": "diesel car" } } } 复制这些特定列?

3 个答案:

答案 0 :(得分:3)

使用套装和Numpy广播处理东西的搭配......撒上仙尘

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看起来像这样

0          {hpg1}
1    {air2, hpg2}
2          {hpg3}
dtype: object

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]

分别来自df2df1的行。但是我不需要两行1所以我创建了一个适当大小的空数组,期望我会覆盖行1。我用df1

中的lats和lons填充这些值
a = np.zeros((len(df2), 2), int)
a[i, :] = df1[cols].values[j]

a

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

然后我将其包装在pd.DataFrame中并按照我们上面的说法加入。

答案 1 :(得分:2)

这是实现你想要做的事情的一种方法。

首先使用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 

但是,这会为您想要的列创建重复项。 (我在每次调用时都会删除另一个连接键以避免重复列名。)

我们可以通过调整this post中描述的方法之一来合并这些值。

cols = ['latitude', 'longitude']
colsx = list(map(lambda c: c+"_x", cols))  # list needed for python3
colsy = list(map(lambda c: c+"_y", cols))  # list needed for python3
result[cols] = pd.DataFrame(
    np.where(result[colsx].isnull() == True, result[colsy], result[colsx])
)
result = result[['air_id', 'hpg_id'] + cols]
print(result)
#  air_id hpg_id  latitude  longitude
#0          hpg1     101.0       51.0
#1   air2   hpg2     102.0       52.0
#2   air3            103.0       53.0

<强>更新

如果合并产生重复的条目,您可以使用pandas.DataFrame.drop_duplicates()

result = result.drop_duplicates()

答案 2 :(得分:1)

这是一种没有合并的手动方式。它效率不高,但如果它能够充分发挥您的用例,则可以管理。

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