如何为Scipy的cdist(或pdist)自定义函数传递额外参数?
解决Scipy cdist自定义度量函数传递额外参数的问题
这问题我之前也踩过坑!Scipy的cdist对自定义度量函数的签名有严格要求——只能接受两个输入参数(即待比较的两个向量u和v),所以你直接带k=7传进去肯定会报错。下面给你几个比全局变量优雅得多的解决方案:
方法1:用Lambda函数做参数适配
最简单的方式就是用lambda把额外参数k绑定进去,给cdist提供它需要的双参数接口:
import numpy as np from scipy.spatial.distance import cdist def cust_metric(u, v, k): dist = np.cumsum(np.gcd(u, v) * k) return dist # 调用时用lambda封装k参数 arr1 = np.array([[1,2],[3,4]]) arr2 = np.array([[5,6],[7,8]]) d_ar = cdist(arr1, arr2, metric=lambda u, v: cust_metric(u, v, k=7))
lambda在这里就像一个“适配器”,帮你把三参数的自定义函数转换成cdist能识别的双参数函数。
方法2:用functools.partial做偏函数绑定
如果觉得lambda不够直观,Python标准库的functools.partial是专门用来固定函数部分参数的工具,可读性更强:
import numpy as np from scipy.spatial.distance import cdist from functools import partial def cust_metric(u, v, k): dist = np.cumsum(np.gcd(u, v) * k) return dist # 预先绑定k参数,生成一个只需要u和v的新函数 custom_metric_with_k = partial(cust_metric, k=7) d_ar = cdist(arr1, arr2, metric=custom_metric_with_k)
这种方式特别适合自定义函数有多个额外参数的场景,代码逻辑会更清晰。
方法3:用类封装状态(适合复杂场景)
如果你的度量逻辑以后需要扩展,比如要传递多个参数或者维护一些状态,用类的__call__方法来实现会更灵活:
import numpy as np from scipy.spatial.distance import cdist class CustMetric: def __init__(self, k): self.k = k # 把k作为类的属性保存 def __call__(self, u, v): # 调用实例时就像调用函数一样,自动传入u和v dist = np.cumsum(np.gcd(u, v) * self.k) return dist # 实例化时传入k参数 metric_obj = CustMetric(k=7) d_ar = cdist(arr1, arr2, metric=metric_obj)
类的方式可以很好地封装所有需要的参数,避免全局变量带来的命名污染和维护问题。
这三种方法都能完美解决你的问题,推荐根据场景选择:简单需求用lambda,参数多的时候用partial,复杂逻辑用类封装。
内容的提问来源于stack exchange,提问作者Sam m
相关产品推荐
相关产品推荐

