我有3d坐标系(X,Y,Z)中的点列表。此外,它们每个都分配了一个浮点值 v ,因此单个点可以描述为( x , y , z , v )。此列表表示为 shape =(N,4)的numpy数组。对于每个2d位置 x , y ,我需要获取 v 的最大值。一种直接但在计算上昂贵的方法是:
for index in range(points.shape[0]):
x = points[index, 0]
y = points[index, 1]
v = points[index, 3]
maxes[x, y] = np.max(maxes[x, y], v)
是否还有一种更“ numpy”的方法,可以在性能方面带来一些好处?
答案 0 :(得分:3)
设置
points = np.array([[ 0, 0, 1, 1],
[ 0, 0, 2, 2],
[ 1, 0, 3, 0],
[ 1, 0, 4, 1],
[ 0, 1, 5, 10]])
这里的总体思路是使用第一,第二和第四列进行排序,然后反转结果,以便当我们找到唯一值时,第四列中具有最大值的值将高于其他具有相似值的值x和y坐标。然后,我们使用np.unique
在第一和第二列中查找唯一值,然后返回这些结果,这些结果的最大值为v
:
lexsort
和numpy.unique
def max_xy(a):
res = a[np.lexsort([a[:, 3], a[:, 1], a[:, 0]])[::-1]]
vals, idx = np.unique(res[:, :2], 1, axis=0)
maximums = res[idx]
return maximums[:, [0,1,3]]
array([[ 0, 0, 2],
[ 0, 1, 10],
[ 1, 0, 1]])
unique
以获得更好的性能def max_xy_v2(a):
res = a[np.lexsort([a[:, 3], a[:, 1], a[:, 0]])[::-1]]
res = res[np.append([True], np.any(np.diff(res[:, :2],axis=0),1))]
return res[:, [0,1,3]]
max_xy_v2(points)
array([[ 1, 0, 1],
[ 0, 1, 10],
[ 0, 0, 2]])
请注意,尽管两者都将返回正确的结果,但它们将不会像原始列表那样进行排序,但您可以根据需要简单地在末尾添加另一个lexsort
。
答案 1 :(得分:2)
很抱歉,也不是纯粹的“ numpy”解决方案,但是numpy_indexed软件包提供了一种非常方便(快速)的方法。
import numpy_indexed as npi
npi.group_by(points[:, 0:2]).max(points[:,3])
%timeit npi.group_by(points[:, 0:2]).max(points[:,3])
58 µs ± 435 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit pd.DataFrame(points, columns=['X', 'Y', 'Z', 'V']).groupby(by=['X', 'Y']).apply(lambda r: r['V'].max()).reset_index().values
3.15 ms ± 36.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
def max_xy_ver1(a):
res = a[np.lexsort([a[:, 0], a[:, 1], a[:, 3]])[::-1]]
vals, idx = np.unique(res[:, :2], 1, axis=0)
maximums = res[idx]
return maximums[:, [0,1,3]]
%timeit max_xy_ver1(points)
63.5 µs ± 1.03 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
def max_xy_ver2(a):
res = a[np.lexsort([a[:, 3], a[:, 1], a[:, 0]])[::-1]]
res = res[np.append([True], np.any(np.diff(res[:, :2],axis=0),1))]
return res[:, [0,1,3]]
%timeit_max_xy_ver2(points) # current winner
31.7 µs ± 524 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
def findmaxes_simple(points):
maxes = {}
for index in range(points.shape[0]):
x = points[index, 0]
y = points[index, 1]
v = points[index, 3]
maxes[(x, y)] = v if (x,y) not in maxes else max(maxes[(x, y)],v)
return maxes
%timeit findmaxes_simple(points)
82.6 µs ± 632 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
pip install --user numpy_indexed
(如果您使用的是Ubuntu和其他Linux发行版,则可能必须使用pip3
安装python 3的软件包)
垃圾箱here。
答案 2 :(得分:1)
这不是纯粹的numpy
,我利用pandas
的优势,我相信它将竭尽所能进行矢量化:
a = [
[0, 0, 1, 1],
[0, 0, 2, 2],
[1, 0, 3, 0],
[1, 0, 4, 1],
[0, 1, 5, 10],
]
pd.DataFrame(a, columns=['X', 'Y', 'Z', 'V']).groupby(by=['X', 'Y']).apply(lambda r: r['V'].max()).reset_index().values
返回此:
array([[ 0, 0, 2],
[ 0, 1, 10],
[ 1, 0, 1]])
答案 3 :(得分:0)
以纯数字表示:
import numpy as np
points = np.array([(1,2,3,4),
(2,3,5,6),
(1,2,9,8)]) #an example,
def find_vmax(x, y) :
xpoints = points[np.where( points[:,0] == x)[0]]
xypoints = xpoints[np.where( xpoints[:,1] == y)[0]]
return np.max(xypoints[:, 3])
print(find_vmax(1, 2))