背景
我正在尝试计算一组点之间的“社交旅行者”距离。对于两个点a和b,我们定义ST(a,b)为从a到所有比b更接近a的点的欧几里得距离的累积和,包括到b的距离。
(假设a正在拜访各种人。他们首先看见最近的人,然后是下一个最近的人,以此类推。社交旅行者距离是他们抵达b时已经走过的路程(仅计算出发距离)。)
社交旅行者距离在某个任意半径内定义;超出该范围,“访问”的点被定义为不可到达。这是因为某些原因。 ;)
到目前为止我做了什么
我使用numpy数组存储了一些点。以下是一个示例:
>>> import numpy as np
>>> x = np.array([(0,0), (-1,2), (-2,-2), (6,-2), (4,0)])
>>> x
array([[ 0, 0],
[-1, 2],
[-2, -2],
[ 6, -2],
[ 4, 0]])
我生成了一个数组,其中包含每个点之间的成对距离。在这个例子中,我考虑的上限距离为4。
>>> from sklearn.metrics import pairwise_distances
>>> y = pairwise_distances(x)
>>> y
array([[0. , 2.24, 2.83, 6.32, 4. ],
[2.24, 0. , 4.12, 8.06, 5.39],
[2.83, 4.12, 0. , 8. , 6.32],
[6.32, 8.06, 8. , 0. , 2.83],
[4. , 5.39, 6.32, 2.83, 0. ]])
>>> import numpy.ma as ma
>>> ym = ma.masked_greater(y, 4)
>>> ym
masked_array(
data=[[0.0 , 2.24, 2.83, --, 4.0 ],
[2.24, 0.0 , --, --, --],
[2.83, --, 0.0 , --, --],
[ --, --, --, 0.0 , 2.83],
[4.0 , --, --, 2.83, 0.0 ]],
mask=[[False, False, False, True, False],
[False, False, True, True, True],
[False, True, False, True, True],
[ True, True, True, False, False],
[False, True, True, False, False]],
fill_value=1e+20)
(我已经缩短了数字以保证大家的理智。)
我的目标是用该行非缺失值的累积总和来替换每个行元素,直到包括该元素为止。(为简化起见,忽略并列的问题。)也就是说,我想得到这个数组:
>>> hypothetical_new_y
array([[0. , 2.24, 5.06, nan, 9.06],
[2.24, 0. , nan, nan, nan],
[2.83, nan, 0. , nan, nan],
[nan , nan, nan, 0. , 2.83],
[6.83, nan, nan, 2.83, 0. ]])
我知道如何沿着行获取累计总和:
>>> np.cumsum(ym, axis=1)
masked_array(
data=[[0.0 , 2.24, 5.06, --, 9.06],
[2.24, 2.24, --, --, --],
[2.83, --, 2.83, --, --],
[ --, --, --, 0.0 , 2.83],
[4.0 , --, --, 6.83, 6.83]],
...
由于这是按行顺序添加而不是排序,因此它会给出错误的值(除了这里的第一行巧合)。我可以做同样的事情,首先对行进行排序:
>>> np.cumsum(np.sort(ym, axis=1), axis=1)
masked_array(
data=[[0.0 , 2.24, 5.06, 9.06, --],
[0.0 , 2.24, --, --, --],
[0.0 , 2.83, --, --, --],
[0.0 , 2.83, --, --, --],
[0.0 , 2.83, 6.83, --, --]],
mask=[[False, False, False, False, True],
[False, False, True, True, True],
[False, False, True, True, True],
[False, False, True, True, True],
[False, False, False, True, True]],
fill_value=1e+20)
这使我获得了正确的值,但它们按升序排列而不是我想要的顺序。我希望这些累加和根据原始数组的argsort值定位:
>>> np.argsort(ym)
array([[0, 1, 2, 4, 3],
[1, 0, 2, 3, 4],
[2, 0, 1, 3, 4],
[3, 4, 0, 1, 2],
[4, 3, 0, 1, 2]])
看起来我需要一种方法来对这些行进行排序,做累积求和,然后将按照 argsort 向量排序的累积求和返回。请注意,如果按照 np.argsort(ym) 中的向量呈现 np.cumsum(np.sort(ym, axis=1), axis=1) 的结果,则得到了我的 hypothethical_new_y 数组。但就是在最后一步,我卡住了。
我感觉自己有三分之二的 Venn 图表了。你有什么想法可以帮我完成最后这一步吗?我的希望是这只是我发现的 numpy 语法知识中相对简单的一个漏洞。
编辑:发布后继续查找后,我认为已经找到了 np.take_along_axis()
的“显而易见”的答案 - 但并不是。请考虑以下代码:
>>> foo = np.argsort(ym)
>>> bar = np.cumsum(np.sort(ym, axis=1), axis=1)
>>> np.take_along_axis(bar, foo, axis=1)
masked_array(
data=[[0.0 , 2.24, 5.06, --, 9.06],
[2.24, 0.0 , --, --, --],
[ --, 0.0 , 2.83, --, --],
[ --, --, 0.0 , 2.83, --],
[ --, --, 0.0 , 2.83, 6.83]],
...
例如,如果您查看最后一行,很明显该命令正在获取
bar
的最后一行的第四个元素并将其放入第一个位置,获取bar
的最后一行的第三个元素并将其放入第二个位置等等 (回想一下foo的最后一行是[4, 3, 0, 1, 2]
)。相反,我想要的是获取bar
的最后一行的第一个元素并将其放入第四个位置,获取bar
的第二个元素并将其放入第三个位置等等。而np.put_along_axis
对我来说也不太适用。