脾气暴躁:从积分列表中获得最大收益的正确方法

时间:2018-09-19 14:58:46

标签: python numpy max

我有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”的方法,可以在性能方面带来一些好处?

4 个答案:

答案 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

使用lexsortnumpy.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安装numpy_indexed

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))