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不太熟悉,所以只能根据你要的要求自制数据写一个参考代码。核心代码我截屏见下图,完整代码也给你,不清楚的地方欢迎提问!
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循环里面自己有迭代器
可以用二分法来匹配最接近的值,给你提供一个函数参考,很简单的,速度很快
最后只匹配一个么
表1和表2 分别多大数据量