我正在尝试编写一个Cython模块来计算成对距离,作为更大类别的局部敏感哈希的一部分。我没有为每种类型和每个距离度量编写代码,而是尝试创建一个cdef函数,该函数采用从Metric继承的各种扩展类型:
cdef class Metric:
def __init__(self):
pass
cdef class Euclidean(Metric):
cdef numeric c_evaluate(self, numeric[:] x, numeric[:] y, int dims):
....
cdef numeric[:,:] pairwise(numeric[:] x, numeric[:] y, Metric func, bint symmetric):
...
dm[i,j] = func.c_evaluate(x,y,dims)
...
要从Python访问此功能:
def py_pairwise(numeric[:,:] x, numeric[:,:] y, str func, bint symmetric = 1, **kwargs):
cdef Metric mfunc = to_Metric(func, **kwargs)
return pairwise(x, y, mfunc, symmetric)
但是我不断收到“c_distance。[Metric]对象没有属性'c_evaluate'”的错误。我想知道c_evaluate方法是否无法访问,因为类对象是通过python函数to_Metric在python代码中创建的,尽管我认为def和cdef函数应该能够在Cython模块中自由地相互调用。如果我将c_evaluate更改为cpdef方法,该方法有效,但我不确定这是否通过允许cdef对象通过python传递给cython或仅使用较慢的python方法来解决问题。任何建议(我也不在我的家用电脑上,所以我现在没有所有的代码。稍后会根据要求更新吗?)
编辑:错字不在原始函数中(可能还有其他函数):
ctypedef fused floating:
float
double
cdef class Euclidean(Metric):
cdef public floating c_evaluate(self, floating[:] x, floating[:] y, int dims):
cdef int i
cdef floating tmp, d = 0
for i in range(dims):
tmp = x[i]-y[i]
d += tmp*tmp
return sqrt(d)
#@cython.boundscheck(False)
#@cython.wraparound(False)
def py_pairwise(numeric[:,::1] x, numeric[:,::1] y,str metric, bint symmetric,**kwargs):
cdef Metric func = to_Metric(metric,**kwargs)
return pairwise(x,y,func,symmetric)
cdef numeric[:,::1] pairwise(numeric[:,::1] x,numeric[:,::1] y, Metric met, bint symmetric):#
cdef int n,m,k,i,j
n = x.shape[0]
m = y.shape[0]
dims = x.shape[1]
if numeric in floating:
mdtype = np.float
else:
mdtype = np.int
#mdtype = np.float
cdef numeric[:,::1] dm = (np.empty((n,m),dtype = mdtype)).fill(0)
if symmetric:
interval = lambda i,n,m: range(i+1,m)
else:
interval = lambda i,n,m: range(m)
for i in range(n):
for j in interval(i,n,m):
dm[i,j] = met.c_evaluate(x[i,:],y[j,:],dims)
return np.asarray(dm)
另外,to_Metric:
def to_Metric(str m, **kwargs):
if len(kwargs) == 0:
if m == 'euclidean':
met = Euclidean()
elif m in {'cos','cosine'}:
met = Cosine()
elif m in {'hamming','matching'}:
met = Hamming()
else:
raise ValueError('Unrecognized metric {}'.format('\''+m+'\''))
else:
if m in {'pnorm','p-norm'}:
met = Pnorm(kwargs['p'])
elif m == 'maximal':
met = Maximal(kwargs['m1'],kwargs['m2'],kwargs['sep'])
else:
raise ValueError('Unrecognized metric {}'.format('\''+m+'\''))
return met
答案 0 :(得分:0)
问题是c_evaluate
与类Euclidean
相关联,因此 可以与已知类型为{{1}的对象一起使用}。但是,在Euclidean
中,您将pairwise
的类型声明为met
。
因为您将Metric
函数声明为c_evaluate
,所以只能在编译时找到它。如果您希望在运行时找到cdef
,就像标准Python函数一样,您应该将其声明为c_evaluate
。
如果您需要在编译时找到该函数(这使得调用它更快),那么您应该使def
成为c_evaluate
对象的函数,或者您应该{{1}只占用Metric
个对象。