简单来说,我正在尝试将列 latitude
和 longitude
从 df1
添加到名为 df2
通过比较它们的 air_id
和 hpg_id
列的值:
将 latitude
和 longitude
添加到 df2
的技巧取决于如何与 df1
进行比较,这可能是 3 种情况之一:
- 当
df2.air_id
和df1.air_hd
匹配时; - 当
df2.hpg_id
和df1.hpg_hd
匹配时; - 当两者匹配时:
[df2.air_id, df2.hpg_id]
AND[df1.air_hd, df1.hpg_id]
;
考虑到这一点,预期结果应该是:
请注意 df1
中的 ignore_me
列如何被排除在生成的 DataFrame 之外。
这是设置数据帧的代码:
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
中的所有列大部分都填充了 NaN:
如何使用上述规则从 df1
复制这些特定列?
最佳答案
使用 sets 和 Numpy broadcasting 来处理东西的匹配......撒上仙尘
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)
但是空集在 bool 上下文中计算为 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
和 df1
的行。但我不需要两行 1
,所以我创建了一个适当大小的空数组,期望我将覆盖行 1
。我用 df1
a = np.zeros((len(df2), 2), int)
a[i, :] = df1[cols].values[j]
a
array([[101, 51],
[102, 52],
[103, 53]])
然后我将其包装在一个 pd.DataFrame
中并如上所示加入。
关于python - 根据两列的比较从第二个 DataFrame 添加列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49329997/