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,只考虑与任何重复的索引列表
值相对应的最后一个新元组
。在我的问题中,我没有说任何关于索引列表生成的内容,假设它是不相关的,但是在存在重复的情况下,这两种方法都不起作用。