我正在尝试根据分配给用户的项目值来计算用户对之间的距离。但是,当两个用户没有任何交叉项目时,距离计算应该为空。我也只计算距离矩阵的下半部分(例如,UserA-UserB 等同于 UserB-UserA,所以只计算一个)。
所以我有下面这个有效的 Python 脚本,但是当我为它提供超过几百个用户时它真的开始出现问题。下面的示例脚本显示了输入结构,但我试图做数千个,而不仅仅是我在此处显示的四个。
行 s = {k:v for k,v in data.items() if k in (user1,user2)} 似乎增加了最多的开销
import math
from decimal import *
def has_matching_product(data,user1,user2):
c1=set(data[user1].keys())
c2=[k for k in data[user2].keys()]
return any([x in c1 for x in c2])
def get_euclidean_dist(data,user1,user2):
#Tried subsetting to run quicker?
s = {k:v for k,v in data.items() if k in (user1,user2)}
#Ignore users with no overlapping items
if has_matching_product(s,user1,user2):
items=set()
for k,v in s.items():
for ki in v.keys():
items.add(ki)
rs=Decimal(0)
for i in items:
p1 = s.get(user1).get(i)
p2 = s.get(user2).get(i)
v1 = p1 or 0
v2 = p2 or 0
rs+= Decimal((v1-v2)**2)
return math.sqrt(rs)
else:
return None
#User/Product/Value
raw_data = {
'U1': {
'I1':5,
'I4':2
},
'U2': {
'I1':1,
'I3':6
},
'U3': {
'I3':11
},
'U4': {
'I4':9
}
}
users = sorted(raw_data.keys())
l = len(users)
data_out = set()
#Compute lower half of a distance matrix (unique pairs only)
for u1 in range(0,l-1):
for u2 in range(1+u1,l):
dist = get_euclidean_dist(raw_data,users[u1],users[u2])
print('{x} | {y} | {d}'.format(x=users[u1],y=users[u2],d=dist)) #Sample output
正确的输出应该是这样的:
U1 | U2 | 7.483314773547883
U1 | U3 | None
U1 | U4 | 8.602325267042627
U2 | U3 | 5.0990195135927845
U2 | U4 | None
U3 | U4 | None
请您参考如下方法:
问题是您每次都在遍历整本词典,只是为了找到您想要的两个项目。从表面上看,您正在提取 user,然后花费所有时间尝试在 data 中再次找到它们。 @Peter Wood 的建议会大有帮助——首先只抓取你想要的两个 user,但这有点像不见了森林——你不需要精简你的字典首先。将它们放在一起:
import itertools
for kv1, kv2 in itertools.combinations(data.items(), 2):
## calculate distance directly here
