Python Numpy:二维数组的元素绝对最大值的有符号值

Python Numpy:二维数组的元素绝对最大值的有符号值,python,performance,python-3.x,numpy,max,Python,Performance,Python 3.x,Numpy,Max,让我们假设我有一个名为arr的二维数组,其形状为(4,3),如下所示: >>> arr array([[ nan, 1., -18.], [ -1., -1., -1.], [ 1., 1., 5.], [ 1., -1., 0.]]) 也就是说,我想将元素绝对最大值的有符号值(1.0,1.0,-15.0)和行arr[[0,2],:]分配回arr。也就是说,我正在寻找输出: >>> arr array([[ 1.,

让我们假设我有一个名为
arr
的二维数组,其形状为(4,3),如下所示:

>>> arr
array([[ nan,   1., -18.],
   [ -1.,  -1.,  -1.],
   [  1.,   1.,   5.],
   [  1.,  -1.,   0.]])
也就是说,我想将元素绝对最大值的有符号值
(1.0,1.0,-15.0)
和行
arr[[0,2],:]
分配回
arr
。也就是说,我正在寻找输出:

>>> arr
array([[ 1.,   1.,  -18.],
   [ -1.,  -1.,  -1.],
   [  1.,   1., -15.],
   [  1.,  -1.,   0.]])
我在API参考中找到的最接近于此的东西是,但它没有绝对值。如果我使用:

arr[index_list, :] = np.fmax(arr[index_list, :], new_tuple)
我的数组最终看起来像:

>>> arr
array([[ 1.,   1., -15.],
   [ -1.,  -1.,  -1.],
   [  1.,   1.,   5.],
   [  1.,  -1.,   0.]])
现在,API说这个函数是

相当于
np。其中(x1>=x2,x1,x2)
当x1和x2都不是nan时,但是它更快并且进行正确的广播

我尝试使用以下方法:

arr[index_list, :] = np.where(np.absolute(arr[index_list, :]) >= np.absolute(new_tuple), 
                              arr[index_list, :], new_tuple)
虽然这产生了期望的输出,但我得到了警告:

/Applications/PyCharm CE.app/Contents/helpers/pydev/pydevconsole.py:1:RuntimeWarning:在较大值中遇到无效值

我相信这个警告是因为NaN在这里没有得到很好的处理,不像
np.fmax
函数。此外,API文档提到,
np.fmax
速度更快,广播正确(不确定
np.where
版本中缺少哪部分广播)

总之,我想要的是类似于:

arr[index_list, :] = np.fmax(arr[index_list, :], new_tuple, key=abs)
不幸的是,此函数没有可用的
属性

仅就上下文而言,我对尽可能快的解决方案感兴趣,因为
arr
数组的实际形状平均为(100000,50),并且我正在循环使用近1000个
新元组
元组(当然,每个元组的形状与
arr
中的列数相等)。每个
新元组的
索引列表
都会更改


编辑1:

一种可能的解决方案是,首先将
arr
中的所有NaN替换为
0
。i、 e.
arr[np.isnan(arr)]=0
。在这之后,我可以使用原始文本中提到的
np.where
np.absolute
技巧。然而,这可能比API建议的
np.fmax
慢得多


编辑2:


索引列表
可能在后续循环中有重复的索引。每个
new\u tuple
都有一个相应的规则,并根据该规则选择
index\u list
。没有什么能阻止不同的规则拥有它们匹配的重叠索引@对于
index\u list
没有重复的情况,Divakar有一个很好的答案。然而,其他解决方案也很受欢迎,涵盖了这两种情况

假设所有
索引的列表
没有重复索引:

方法#1

一旦我们将所有的
索引列表
新元组
存储在一个地方,最好是作为列表,我会提出更多的矢量化解决方案。因此,如果我们处理大量这样的元组和列表,这可能是首选方法

那么,假设我们将它们存储为以下内容:

new_tuples = [(1.0, 1.0, -15.0), (6.0, 3.0, -4.0)] # list of all new_tuple
index_lists =[[0,2],[4,1,6]]  # list of all index_list
此后的解决方案是手动重复,替换广播,然后使用
np.where
,如问题后面所示。如果
新元组
具有非NaN值,我们可以使用
np.
对上述警告的关注点进行忽略。因此,解决办法是-

idx = np.concatenate(index_lists)
lens = list(map(len,index_lists))

a = arr[idx]
b = np.repeat(new_tuples,lens,axis=0)
arr[idx] = np.where(np.abs(a) > np.abs(b), a, b)

方法#2

另一种方法是存储
arr
before和:
abs\u arr=np.abs(arr)
的绝对值,并使用
np.where
中的绝对值。这将在循环中节省大量时间。因此,相关计算将减少到:

arr[index_list, :] = np.where(abs_arr[index_list, :] > np.abs(b), a, new_tuple)

对于每个新的元组,
index\u列表
中的元素数是否会更改?@Divakar,是的,
index\u列表
中的元素数会更改。这个
索引列表
实际上是通过使用
新元组
来计算的,在上面讨论的语句之前有一些额外的魔力,在进入上述循环之前,我们是否有所有
索引列表
和所有
新元组
的列表?我必须运行一次循环,并创建一个包含这些值的大字典。我没有事先准备好。我宁愿不冒内存错误的风险。循环迭代次数是多少(通常,如果不是绝对数的话)?谢谢。第二种方法并不合适。索引列表中没有任何东西会停止这样的重复:
索引列表=[[0,2],[4,1,6],[1,7,9],[5,7,8]
new_tuple
中的负值将在后续循环中被重复索引覆盖。方法#1是一个好主意。它应该为
np.where
语句节省计算时间。我的问题只是,这个句柄如何在
索引列表中重复?这可能无关紧要,但你有重复的经验吗?我刚刚检查了方法1,只考虑与任何重复的
索引列表
值相对应的最后一个
新元组
。在我的问题中,我没有说任何关于
索引列表生成的内容,假设它是不相关的,但是在存在重复的情况下,这两种方法都不起作用。