python中有两张表,怎么从第二张中匹配到第一张中分值最接近的值

问题遇到的现象和发生背景

PSM计算相似度分数后,需要做一步近邻匹配,目前的代码效率过低,使用500多万的实验组和对照组运行不了,是否有使用np.argmin()类似更快的方式?还请附上完整代码展示。

问题相关代码,请勿粘贴截图
df_a
         user_id    score2    flag
318221    2375034142    0.443202    0
6887114    254245646    0.451553    0
2162889    61446035    0.421192    0
3704375    1422839224    0.388748    0
1633196    806314149    0.454262    0
...    ...    ...    ...

df_b
          user_id    score    flag
7050078    3010359962    0.447330    1
426493    2595560193    0.434321    1
349725    2560657077    0.479694    1
3165806    810662170    0.451611    1
4241766    1761798847    0.328537    1
125442    167769623    0.449496    1
542170    526389776    0.244148    1
2921664    1381524450    0.395069    1
6593202    78866382    0.456352    1
5090719    61103791    0.287608    1
5187439    575019688    0.460237    1
7162326    250267620    0.426325    1
...    ...    ...    ...

df_a = df_a.reset_index(drop = True)  ##index重新排序,从而找出来需要的那列
for i in range(len(df_a)):
    a = df_a.iloc[i]['score']
    for k in range(len(df_b)):
        df_a['minus_predict'] = np.abs(df_b['score2'] - a)
        ind = df_a['minus_predict'].idxmin()  
        row = df_a.loc[ind, :]   
        df_a.loc[k, 'user_id'] = df_a.loc[ind, 'user_id']  
        df_a.loc[k, 'minus_value'] = df_a.loc[ind, 'minus_predict']
        df_a = df_a.drop(ind, axis=0)  
        k=k+1
    i = i+1
运行结果及报错内容
我的解答思路和尝试过的方法
我想要达到的结果

怎么从第二张中匹配到与第一张中分值最接近的值的user_id

你的代码时间复杂度是2500000*500=1250000000,大概就是1e9,一般计算机目前每秒运算1e8左右。并且你的两重循环可以优化一下达到2500000+500,复杂度就是250万,完全可以了。但是我对pandas不太熟悉,所以只能根据你要的要求自制数据写一个参考代码。核心代码我截屏见下图,完整代码也给你,不清楚的地方欢迎提问!

img

import numpy as np
import pandas as pd
import random
# 数据准备
# 表1数据
n = 1000000
score2 = [np.abs(random.random()) for i in range(n)]
user_id_a = [i for i in range(n)]
random.shuffle(user_id_a)
# 表二数据

m = 50
score = [np.abs(random.random()) for i in range(m)]
user_id_b = [i for i in range(m)]
random.shuffle(user_id_b)
# print(user_id)


data_a = {"user_id": user_id_a, "score2": score2}
df_a = pd.DataFrame(data_a)

data_b = {"user_id": user_id_b, "score": score}
df_b = pd.DataFrame(data_b)
# 查看数据形状
# print(df_a.shape, df_b.shape)

# 下面的是核心代码,上面的是在准备数据
# 怎么从df_b中匹配到与df_a中分值最接近的值的user_id
df_a = df_a.sort_values(by='score2')  # 根据分数排序,使得两个数据有序
df_b = df_b.sort_values(by='score')

i, j = 0, 0
# 重点就是这两个i,j。在遍历数组时候的可以接着下次结束地方继续,使得每行只访问一次,达到O(n+m)的复杂度,不然就是你的O(n*m)
n, m = len(df_a), len(df_b)
while i < n:
    score2 = df_a.loc[i].score2
    while j < m and score2 < df_b.loc[j].score:
        j += 1
    if j == m:
        print('第一张id:', df_a.loc[i].user_id, '分数:', df_a.loc[i].score2,
              '最接近第二张id:', df_b.loc[j-1].user_id, '分数:', df_b.loc[j-1].score)
    elif j > 0:
        #  score2 < df_b.loc[j-1].score 和 score2 >= df_b.loc[j].score情况

        if df_b.loc[j-1].score - score2 >= score2 - df_b.loc[j].score:
            print('第一张id:', df_a.loc[i].user_id, '分数:', df_a.loc[i].score2,
                  '最接近第二张id:', df_b.loc[j].user_id, '分数:', df_b.loc[j].score)
        else:
            print('第一张id:', df_a.loc[i].user_id, '分数:', df_a.loc[i].score2,
                  '最接近第二张id:', df_b.loc[j-1].user_id, '分数:', df_b.loc[j-1].score)
    else:
        print('第一张id:', df_a.loc[i].user_id, '分数:', df_a.loc[i].score2,
              '最接近第二张id:', df_b.loc[j].user_id, '分数:', df_b.loc[j].score)
    i += 1

首先,你的代码里面不需要 k= k+1, i = i+1。for循环里面自己有迭代器

可以用二分法来匹配最接近的值,给你提供一个函数参考,很简单的,速度很快

img

最后只匹配一个么

表1和表2 分别多大数据量