如何在numpy中找到变长数组数组中的最小/最大值?

时间:2014-06-30 16:03:29

标签: python numpy

我有一个类似下面的数组:

data = [
  [-20],
  [-23],
  [-41],
  [1, 2, 3],
  [2, 3],
  [5, 6, 7, 8, 9],
]
arr = np.array(data)

如何使用numpy查找data中每个数组的最小/最大值? 即使我指定了不同的轴,np.minnp.max似乎都不起作用。 期望的结果如下所示:

>>> np.findmin(arr)
array([-20, -23, -41, 1, 2, 5])
>>> np.findmax(arr)
array([-20, -23, -41, 3, 3, 9])

此外,我还不完全清楚为什么np.minnp.max无法正常工作。也许它们只会按照我想要的方式工作,如果给定的数组有明确定义的轴,其中每行有固定数量的列?如果有人能解释这一点,我很想知道。

2 个答案:

答案 0 :(得分:4)

这是可能的,但这并不是numpy擅长的事情。一种可能的解决方案是使用nan填充数组并使用np.nanmax,如此

import numpy as np

def pad_array(arr):
    M = max(len(a) for a in arr)
    return np.array([a + [np.nan] * (M - len(a)) for a in arr])

data = [
  [-20],
  [-23],
  [-41],
  [1, 2, 3],
  [2, 3],
  [5, 6, 7, 8, 9],
]
arr = pad_array(data)
# array([[-20.,  nan,  nan,  nan,  nan],
#        [-23.,  nan,  nan,  nan,  nan],
#        [-41.,  nan,  nan,  nan,  nan],
#        [  1.,   2.,   3.,  nan,  nan],
#        [  2.,   3.,  nan,  nan,  nan],
#        [  5.,   6.,   7.,   8.,   9.]])

np.nanmin(arr, axis=1) #array([-20., -23., -41.,   1.,   2.,   5.])
np.nanmax(arr, axis=1) #array([-20., -23., -41.,   3.,   3.,   9.])

但这并不比常规列表理解快。 np.minnp.max 正在工作,但numpy并不支持不规则数组,所以np.array(data)正在创建一维对象数组,并且np.min为您提供最小的object - 与您使用Python的内置min功能时相同 - 与np.max相同

以下是比较创建填充数组和使用普通列表理解

的时序
%%timeit
arr = np.array(pad_array(data))
np.nanmin(arr, axis=1)
10000 loops, best of 3: 27 µs per loop

%timeit [min(row) for row in data]
1000000 loops, best of 3: 1.26 µs per loop

这有点人为,因为我在pad_array中使用了列表推导和生成器表达式,因此单个列表理解会更快,但如果你处于只有你的情况需要创建一次填充数组,单个列表理解仍然会更快。

%timeit np.nanmin(arr, axis=1)
100000 loops, best of 3: 13.3 µs per loop

修改

您可以使用np.vectorize制作Python内置maxmin函数的矢量化版本

vmax = np.vectorize(max)
vmax(data) #array([-20, -23, -41,   3,   3,   9])

它仍然不比列表理解快......

%timeit vmax(data)
10000 loops, best of 3: 25.6 µs per loop

编辑2

为了完整性/正确性,值得指出的是numpy解决方案将比纯Python列表理解解决方案更好地扩展。假设我们有600万行而不是6行需要执行多个元素操作,numpy会更好。例如,如果我们有

data = [
  [-20],
  [-23],
  [-41],
  [1, 2, 3],
  [2, 3],
  [5, 6, 7, 8, 9],
] * 1000000

arr = pad_array(data) #this takes ~6 seconds

时间更多地支持numpy

%timeit [min(row) for row in data]
1 loops, best of 3: 1.05 s per loop

%timeit np.nanmin(arr, axis=1)
10 loops, best of 3: 111 ms per loop

答案 1 :(得分:2)

为什么不使用列表理解?

>>> d
[[-20], [-23], [-41], [1, 2, 3], [2, 3], [5, 6, 7, 8, 9]]
>>> [max(sublist) for sublist in d]
[-20, -23, -41, 3, 3, 9]
>>> [min(sublist) for sublist in d]
[-20, -23, -41, 1, 2, 5]

也适用于numpy数组:

>>> from numpy import array
>>> d
array([[-20], [-23], [-41], [1, 2, 3], [2, 3], [5, 6, 7, 8, 9]], dtype=object)
>>> [max(sublist) for sublist in d]
[-20, -23, -41, 3, 3, 9]

当然,你可以把结果作为数组。

>>> array([max(sublist) for sublist in d])
array([-20, -23, -41,   3,   3,   9])