我经常使用 pandas 通过范围条件进行合并(连接)。
例如,如果有 2 个数据框:
A(A_id,A_value)
B(B_id、B_low、B_high、B_name)
它们很大且大小大致相同(假设每个记录 2M 条)。
我想在 A 和 B 之间进行内部连接,因此 A_value 将在 B_low 和 B_high 之间。
使用 SQL 语法:
SELECT *
FROM A,B
WHERE A_value between B_low and B_high
这将非常简单、简短且高效。
同时,在 pandas 中,唯一的方法(我发现没有使用循环)是在两个表中创建一个虚拟列,加入它(相当于交叉连接),然后过滤掉不需要的行。这听起来沉重而复杂:
A['dummy'] = 1
B['dummy'] = 1
Temp = pd.merge(A,B,on='dummy')
Result = Temp[Temp.A_value.between(Temp.B_low,Temp.B_high)]
我的另一个解决方案是通过使用 B[(x>=B.B_low) & (x<=B.B_high)]
对每个 A 值应用 B 上的搜索功能。掩码,但听起来效率也很低,可能需要索引优化。
是否有更优雅和/或更有效的方式来执行此操作?
最佳答案
设置
考虑数据帧 A
和 B
A = pd.DataFrame(dict(
A_id=range(10),
A_value=range(5, 105, 10)
))
B = pd.DataFrame(dict(
B_id=range(5),
B_low=[0, 30, 30, 46, 84],
B_high=[10, 40, 50, 54, 84]
))
A
A_id A_value
0 0 5
1 1 15
2 2 25
3 3 35
4 4 45
5 5 55
6 6 65
7 7 75
8 8 85
9 9 95
B
B_high B_id B_low
0 10 0 0
1 40 1 30
2 50 2 30
3 54 3 46
4 84 4 84
numpy
✌最简单的✌方式是使用numpy
广播。
我们寻找 A_value
大于或等于 B_low
而同时 A_value
小于或等于 的每个实例B_high
.
a = A.A_value.values
bh = B.B_high.values
bl = B.B_low.values
i, j = np.where((a[:, None] >= bl) & (a[:, None] <= bh))
pd.concat([
A.loc[i, :].reset_index(drop=True),
B.loc[j, :].reset_index(drop=True)
], axis=1)
A_id A_value B_high B_id B_low
0 0 5 10 0 0
1 3 35 40 1 30
2 3 35 50 2 30
3 4 45 50 2 30
为了解决评论并提供类似于左连接的内容,我附加了 A
中不匹配的部分。
pd.concat([
A.loc[i, :].reset_index(drop=True),
B.loc[j, :].reset_index(drop=True)
], axis=1).append(
A[~np.in1d(np.arange(len(A)), np.unique(i))],
ignore_index=True, sort=False
)
A_id A_value B_id B_low B_high
0 0 5 0.0 0.0 10.0
1 3 35 1.0 30.0 40.0
2 3 35 2.0 30.0 50.0
3 4 45 2.0 30.0 50.0
4 1 15 NaN NaN NaN
5 2 25 NaN NaN NaN
6 5 55 NaN NaN NaN
7 6 65 NaN NaN NaN
8 7 75 NaN NaN NaN
9 8 85 NaN NaN NaN
10 9 95 NaN NaN NaN
关于python - 在 Pandas 中按范围加入/合并的最佳方式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44367672/