欧几里得距离错误:不支持的操作数类型
我正在尝试使用 scipy.spatial.distance
来实现 欧几里得距离
,之前我都是这样写的。
from math import sqrt
critics = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
'The Night Listener': 3.0},
'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 3.5},
'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
'The Night Listener': 4.5, 'Superman Returns': 4.0,
'You, Me and Dupree': 2.5},
'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 2.0},
'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}}
def sim_distance(preference, person1, person2):
si = {}
for item in preference[person1]:
if item in preference[person2]:
si[item] = 1
if len(si) == 0: return 0
sum_of_scores = sum([pow(preference[person1][item] - preference[person2][item], 2)
for item in preference[person1] if item in preference[person2]])
return 1 / (1 + sum_of_scores)
a = sim_distance(critics, 'Lisa Rose','Mick LaSalle')
print(a) #0.333
现在的实现运行得很好,但当我尝试使用 scipy
模块时,我不太明白应该提供什么样的输入。这是我尝试过的。
from scipy.spatial.distance import euclidean
a = euclidean(critics['Lisa Rose'], critics['Mick LaSalle'])
print(a)
错误追踪
Traceback (most recent call last):
File "C:/Users/Ajay/PycharmProjects/SO/new.py", line 22, in <module>
a = euclidean(critics['Lisa Rose'], critics['Mick LaSalle'])
File "C:\Python33\lib\site-packages\scipy\spatial\distance.py", line 224, in euclidean
dist = norm(u - v)
TypeError: unsupported operand type(s) for -: 'dict' and 'dict'
在查看 euclidean
的实现时,似乎输入应该以 元组
的形式给出,但我不太明白该如何处理这个。
def euclidean(u, v):
"""
Computes the Euclidean distance between two 1-D arrays.
The Euclidean distance between 1-D arrays `u` and `v`, is defined as
.. math::
{||u-v||}_2
Parameters
----------
u : (N,) array_like
Input array.
v : (N,) array_like
Input array.
Returns
-------
euclidean : double
The Euclidean distance between vectors `u` and `v`.
"""
u = _validate_vector(u)
v = _validate_vector(v)
dist = norm(u - v)
return dist
请给我一些指点。
2 个回答
我做了一个不错的API,虽然代码写得不太好:
http://vectordict.readthedocs.org/en/latest/vector.html#metrics
重要提示:我不建议你使用这段代码(我正在重新写一份更好的),你可以看看它是怎么工作的,也许会对这个API有些尊重,但不要用这段代码。
通过重写加减乘除的操作,你可能会对如何用字典(dict)来做“数学”感兴趣,以及这怎么实现,能让生活变得更简单。
这里是L2范数的实现:sqrt( self.dot(self) )
https://github.com/jul/ADictAdd_iction/blob/master/vector_dict/VectorDict.py#L972
我提倡使用与线性代数定义一致的API,这样你读起来会更容易理解。
from vector_dict.VectorDict import cos
from vector_dict.VectorDict import convert_tree, VectorDict
crit = {'Lisa Rose': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.5,
'Just My Luck': 3.0, 'Superman Returns': 3.5, 'You, Me and Dupree': 2.5,
'The Night Listener': 3.0},
'Gene Seymour': {'Lady in the Water': 3.0, 'Snakes on a Plane': 3.5,
'Just My Luck': 1.5, 'Superman Returns': 5.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 3.5},
'Michael Phillips': {'Lady in the Water': 2.5, 'Snakes on a Plane': 3.0,
'Superman Returns': 3.5, 'The Night Listener': 4.0},
'Claudia Puig': {'Snakes on a Plane': 3.5, 'Just My Luck': 3.0,
'The Night Listener': 4.5, 'Superman Returns': 4.0,
'You, Me and Dupree': 2.5},
'Mick LaSalle': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'Just My Luck': 2.0, 'Superman Returns': 3.0, 'The Night Listener': 3.0,
'You, Me and Dupree': 2.0},
'Jack Matthews': {'Lady in the Water': 3.0, 'Snakes on a Plane': 4.0,
'The Night Listener': 3.0, 'Superman Returns': 5.0, 'You, Me and Dupree': 3.5},
'Toby': {'Snakes on a Plane': 4.5, 'You, Me and Dupree': 1.0, 'Superman Returns': 4.0}}
dd = convert_tree(crit)
print "cos"
print cos(dd['Gene Seymour'], dd['Toby'])
# 0.770024275094
print "L2 distance"
print dd['Gene Seymour'].norm()
# 8.35164654425
print "jaccard similarities"
print dd['Gene Seymour'].jaccard( dd['Toby'])
# 0.579335793358
顺便说一下,我猜如果你在做范数计算,那是为了比较,所以我推测你想做相似度测量。
欧几里得距离是用来衡量两个向量之间的差异的一种方法,可以理解为计算两个向量之间的“直线距离”。在代码中,这个计算可以表示为 dist = norm(u - v)
,这里的 euclidean
函数就是用来计算这种距离的。
不过,你提到的 critics['Lisa Rose']
和 critics['Mick LaSalle']
是字典类型,而字典之间是不能直接进行减法运算的。此外,norm
这个函数是专门用来处理数组类型的数据。
所以,如果你真的想在你的情况下使用 scipy.spatial.distance.euclidean
,你需要为你的 critics
创建一个类,并在这个类里重写减法运算符,也就是定义一个叫 __sub__
的方法,这个方法需要返回一个数组类型的数据。