Python 标签传播-如何避免被零除?

Python 标签传播-如何避免被零除?,python,numpy,machine-learning,scikit-learn,Python,Numpy,Machine Learning,Scikit Learn,在使用时,我经常遇到此警告(我认为这应该是一个错误,因为它完全无法传播): /usr/local/lib/python3.5/dist-packages/sklearn/semi_-supervised/label_-propagation.py:279:RuntimeWarning:true_divide中遇到无效值 self.label_分布u/=normalizer 因此,在对RBF核进行了几次尝试之后,我发现参数gammar有影响 编辑: 问题来自: 我不明白label_distribu

在使用时,我经常遇到此警告(我认为这应该是一个错误,因为它完全无法传播):

/usr/local/lib/python3.5/dist-packages/sklearn/semi_-supervised/label_-propagation.py:279:RuntimeWarning:true_divide中遇到无效值 self.label_分布u/=normalizer

因此,在对RBF核进行了几次尝试之后,我发现参数
gammar
有影响

编辑: 问题来自:

我不明白label_distributions_uu怎么可能全为零,尤其是当它的定义是:

self.label_distributions_ = safe_sparse_dot(
graph_matrix, self.label_distributions_)
Gamma对graph_矩阵有影响(因为graph_矩阵是调用核函数的_build_graph()的结果)。好啊但仍然如此。有点不对劲

旧帖子(编辑前) 我提醒您如何计算传播的图权重:W=exp(-gamma*D),D数据集所有点之间的成对距离矩阵

问题是:
np.exp(x)
如果x非常小,则返回0.0 假设我们有两个点,
i
j
,使得
dist(i,j)=10

>>> np.exp(np.asarray(-10*40, dtype=float)) # gamma = 40 => OKAY
1.9151695967140057e-174
>>> np.exp(np.asarray(-10*120, dtype=float)) # gamma = 120 => NOT OKAY
0.0
实际上,我不是手动设置gamma,而是使用(第2.4节)中描述的方法

那么,如何避免被零除以获得适当的传播呢? 我能想到的唯一方法是规范化每个维度的数据集,但我们会丢失数据集的一些几何/拓扑属性(例如,2x10矩形变成1x1正方形)


可复制示例: 在这个例子中,最糟糕的是:即使gamma=20,它也会失败

In [11]: from sklearn.semi_supervised.label_propagation import LabelPropagation

In [12]: import numpy as np

In [13]: X = np.array([[0, 0], [0, 10]])

In [14]: Y = [0, -1]

In [15]: LabelPropagation(kernel='rbf', tol=0.01, gamma=20).fit(X, Y)
/usr/local/lib/python3.5/dist-packages/sklearn/semi_supervised/label_propagation.py:279: RuntimeWarning: invalid value encountered in true_divide
  self.label_distributions_ /= normalizer
/usr/local/lib/python3.5/dist-packages/sklearn/semi_supervised/label_propagation.py:290: ConvergenceWarning: max_iter=1000 was reached without convergence.
  category=ConvergenceWarning
Out[15]: 
LabelPropagation(alpha=None, gamma=20, kernel='rbf', max_iter=1000, n_jobs=1,
         n_neighbors=7, tol=0.01)

In [16]: LabelPropagation(kernel='rbf', tol=0.01, gamma=2).fit(X, Y)
Out[16]: 
LabelPropagation(alpha=None, gamma=2, kernel='rbf', max_iter=1000, n_jobs=1,
         n_neighbors=7, tol=0.01)

In [17]: 

基本上你在做一个
softmax
功能,对吗

防止
softmax
溢出/下溢的一般方法是(从)

这将
e_x
限制在0和1之间,并确保
e_x
的一个值始终为
1
(即元素
np.argmax(x)
)。这可以防止溢出和下溢(当
np.exp(x.max())
大于或小于
float64
可以处理的值时)

在这种情况下,由于您无法更改算法,因此我将接受输入
D
,并使
D_=D-D.min()
,因为这在数字上应该与上面的相同,因为
W.max()
应该是
-gamma*D.min()
(因为您只是在翻转符号)。执行有关
D的算法

编辑:

正如下面@PaulBrodersen所建议的,您可以基于
sklearn
实现构建一个“安全”的rbf内核:

然后在传播中使用它

LabelPropagation(kernel = rbf_kernel_safe, tol = 0.01, gamma = 20).fit(X, Y)
不幸的是,我只有
v0.18
,它不接受
LabelPropagation
的用户定义内核函数,所以我无法测试它

EDIT2:

检查源代码以了解为什么有如此大的
gamma
值,我想知道您是否使用了
gamma=D.min()/3
,这是不正确的。定义是
sigma=D.min()/3
,而
w
sigma
的定义是

w = exp(-d**2/sigma**2)  # Equation (1)

这将使正确的
gamma
1/sigma**2
9/D.min()**2

可能使用阈值对RBF内核进行编码,以避免返回0。但是如果我这样做,D=15处的点的影响将小于D=100处的2点。(类似于1e-99对2*1e-99)通常我会说降低伽马值,但这不会有帮助,因为你用algo找到它。人们倾向于使用gamme=1/n_特性。20对伽马来说真是太大了。我不确定你在做唇形繁殖时会不会碰到它。使用Gamma1/n_功能显然不适用于像卫星这样的数据集,如
sklearn.datasets.make_卫星(1000,noise=0.06)
我认为大于10的值非常大,但这当然取决于你的数据。至于
np.exp(x)
对于非常小的x为零,请尝试以下操作:
np.exp(np.asarray(-10*120,dtype=np.float128))
为什么不更改实现?您可以从
LabelPropagation
继承,并覆盖
\u get\u kernel
以使用自定义的
rbf\u kernel
,其中在sklearn实现中添加一行
K-=K.max()
。免责声明:我还没有测试过这些。谢谢你的编辑,我正在考虑做我自己的内核。别担心,我使用了gamma=9/D.min()**2,如果D.min()<1,那么这个值就大了。老实说,那篇论文中对gamma
的启发似乎更像是一种对给定数据集有效的方法
gamma>>1
很快就会得到一个二进制
label\u分布
矩阵(只有1和0),如果任何一行被驱动到所有0(因为一个点远离其他点)正如您所描述的,您的方法将失败。今天我有时间尝试,修改后的内核允许我使用比经典rbf内核更大的gamma。谢谢你!
def rbf_kernel_safe(X, Y=None, gamma=None): 

      X, Y = sklearn.metrics.pairwise.check_pairwise_arrays(X, Y) 
      if gamma is None: 
          gamma = 1.0 / X.shape[1] 

      K = sklearn.metrics.pairwise.euclidean_distances(X, Y, squared=True) 
      K *= -gamma 
      K -= K.max()
      np.exp(K, K)    # exponentiate K in-place 
      return K 
LabelPropagation(kernel = rbf_kernel_safe, tol = 0.01, gamma = 20).fit(X, Y)
w = exp(-d**2/sigma**2)  # Equation (1)