看GLVQ的代码时候,发现下面一段(已经被我拆分了,方便调试),本来不知所云,后来发现,里面文章大得很。
def _squared_euclidean(a, b=None):
if b is None:
d = np.sum(a ** 2, 1)[np.newaxis].T + np.sum(a ** 2, 1) - 2 * a.dot(
a.T)
else:
d = np.sum(a ** 2, 1)[np.newaxis].T
e = np.sum(b ** 2, 1)
f = d + e
g = 2 * a.dot(b.T)
h = f - g
return np.maximum(h, 0), d, d.shape, e, e.shape, f, f.shape, g, g.shape
a = np.array([[1, 2], [3, 4]])
b = np.array([[2, 3], [4, 1]])
c = _squared_euclidean(a, b)
print(c)
结果为:
C:\anconda3\python.exe C:/hellopytorch/mel_ceshi.py
(array([[ 2, 10],
[ 2, 10]]), array([[ 5],
[25]], dtype=int32), (2, 1), array([13, 17], dtype=int32), (2,), array([[18, 22],
[38, 42]], dtype=int32), (2, 2), array([[16, 12],
[36, 32]]), (2, 2))
Process finished with exit code 0
比较d,e
的形状,我发现了[np.newaxis].T
的作用:d
本来应该是e
的形状,也就是(2,)
,应该是一个一维的数组,当然只是一行;经过[np.newaxis]
之后,增加了一个维度,也就是在最外面加了一对[]
,形状变为(1, 2)
,虽然变成了二维数组,依然是一行;紧接着进行了转置.T
,形状变成了(2, 1)
,就变成了最终的形式[[ 5], [25]]
。
还有很重要的一点是,d + e
时候,他们的形状本来是不同的,numpy
这个模块中,实现了低维的轴扩展成高维的轴再相加,其实是实现了[[5, 5], [25, 25]] + [[13, 17], [13, 17]]
,最后的结果就是[[18, 22], [38, 42]]
。
其实,这个函数想实现的就是两个样本点之间的距离平方和。比如这里就是a, b
所包含的两个样本之间的距离,这里各有两个样本,所以产生了四个距离,只不过这里巧了,其中存在距离是一样的。h
中第一行表示 a
中第一个样点(第一行表示的样本点)与b
中第一个和第二个样本点之间的距离。第二行以此类推。
从中get到的一点心得就是,比较复杂的公式,拆成一段一段去分析,化繁为简,或许能有好结果。