背景
我正在尝试计算一组点之间的“社交旅行者”距离。对于 a 和 b 两个点,我们将 ST(a,b) 定义为 a之间欧氏距离的累积和em> 和 比 b 更接近 的所有点,直至并包括 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.cumsum(np.sort(ym, axis=1), axis=1)
的结果按 np.argsort(ym)
中的向量排序,你有我的hypothethical_new_y
大批。但这是我摔倒在地的最后一步。
我觉得我这里有维恩图的三分之二。关于如何迈出这最后一步有什么想法吗?我希望这是我发现的 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
最后一行的第 4 个元素。并将其放在第一个位置,即 bar
最后一行的第三个元素并将它放在第二个位置等。(回想一下 foo 的最后一行是 [4, 3, 0, 1, 2]
。)我想要的是取 bar
最后一行的 1st 元素。并将其放在第四 位置,即bar
的2 元素|并将其放在第三 位置等。并且np.put_along_axis
也不是我的果酱。
最佳答案
抱歉未能理解要求。我又试了一次,想出了这个。我无法弄清楚如何使用 for 循环执行此操作,但输出似乎与您的 hypothetical_new_y 匹配,除了第一行中的舍入问题。但我认为这个逻辑应该成立。
>>> x
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. ]])
>>> 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)
>>> g=np.cumsum(np.sort(ym, axis=1), axis=1)
>>> g
masked_array(data =
[[0.0 2.24 5.07 9.07 --]
[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)
>>> n = np.zeros_like(x, dtype=float).view(np.ma.masked_array)
>>> for i in range(n.shape[0]):
... n[i][x[i].argsort(axis=0)] = g.data[i]
...
>>>
>>> n.mask = ym.mask
>>> n
masked_array(data =
[[0.0 2.24 5.07 -- 9.07]
[2.24 0.0 -- -- --]
[2.83 -- 0.0 -- --]
[-- -- -- 0.0 2.83]
[6.83 -- -- 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)
有点笨拙,如果我再错了,我会举起白旗 😕
关于python - 在 argsort 索引上排序的 numpy 累积和,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63103165/