【问题标题】:Fastest way to Select a random number from each row padded numpy array (excluding the pad) and number of non padded values, using numpy operations使用 numpy 操作从每行填充的 numpy 数组(不包括填充)和非填充值的数量中选择随机数的最快方法
【发布时间】:2020-05-26 02:35:18
【问题描述】:

我有一个 2D numpy 数组,每一行都填充有(下面的示例使用 -1)。

对于每一行,我想选择一个随机数,不包括填充,并且还获取每行的非填充值的数量,只使用 numpy 操作。

这是一个最小的例子。我为垫选择了-1,但垫可以是任何负整数。

import numpy as np
numList = [[0, 32, 84, 93, 1023, -1], [0, 23, 33, 45, -1, -1], [0, 10, 15, 21, 24, 25], [0, 23, -1, -1, -1, -1], [0 , 13, 33, 34, -1, -1]]
numArray = np.array(numList)
numArray

array([[   0,   32,   84,   93, 1023,   -1],
       [   0,   23,   33,   45,   -1,   -1],
       [   0,   10,   15,   21,   24,   25],
       [   0,   23,   -1,   -1,   -1,   -1],
       [   0,   13,   33,   34,   -1,   -1]])

对于长度,输出应该是这样的

LengthsResults
[5, 4, 6, 2, 4]. 

这是一个示例输出,用于为每一行选择一个随机的非填充数字。

randomNonPad
[84, 45, 0, 0, 34]

编辑:

我正在查看 np.where,它可以让您根据条件过滤掉 numpy 数组的一部分,以及 numpy 随机选择,它可以让您为数组选择一个随机数。我不确定如何处理 np.where ,但似乎您可以将其更改为某些内容,但我不确定是什么,或者即使它是正确的方法。对于 python,您可以从一个列表开始,并将其附加到任意长度,但对于 numpy,您需要提前确定数组长度。

【问题讨论】:

  • 您能否展示您的尝试并解释为什么您没有成功?

标签: python numpy random


【解决方案1】:

行中负数的索引,也就是非填充元素的长度,最简单的得到

lengths = np.argmin(numArray, axis=1)

这假定行内所有元素的填充数相同。这不适用于没有负数的行,因此您可以使用以下方法修复它:

lengths[np.take_along_axis(numArray, lengths.reshape(-1, 1), axis=1).ravel() >= 0] = numArray.shape[1]

您现在可以使用此信息为您的行生成一组随机索引:

indices = np.random.randint(lengths)

并应用索引获取对应的元素:

result = np.take_along_axis(numArray, indices.reshape(-1, 1), axis=1)

虽然清理 lengths 数组可能是更快的选择,但较短的表达式可能类似于

lengths = np.where(np.any(numArray < 0, axis=1), np.argmin(numArray, axis=1), numArray.shape[1])

此外,如果您的填充数不是一致的负数,则无论您使用哪种方法计算 lengths,都需要将 np.argmin(numArray, axis=1) 替换为 np.argmax(numArray &lt; 0, axis=1)np.argmin(numArray &gt;= 0, axis=1)

【讨论】:

  • @SantoshGupta7。我在手机上,所以有机会我会测试一下。
  • @SantoshGupta7。我犯了一个错误。你需要take_along_axis 而不仅仅是take。这涉及到一个额外的reshape/expland_dims,但这仍然比调用arange 来获得同等的花式索引便宜。
  • 我用我试图用于解决方案的策略更新了我的帖子,但我并没有走得太远。新的第二行结果为IndexError: too many indices for array。看起来你试图做的是找到它是 0 的位置,然后用 6 替换它?我试过 lengths[lengths ==0] =6 并且它有效,但我猜这有缺陷,或者你会首先使用它。
  • 我正在查看indices = np.random.randint(lengths),这也给出了错误。如果lengths是一个python列表,我可以使用indices = np.random.randint(0, lengths),但是由于它是一个numpy数组,我只能使用numpy,这不起作用。
  • @SantoshGupta7。除非您的索引严格增加并且您从未有一个完全填充的行,否则这将不起作用。我会在我离开移动设备时进行调试。与此同时,请继续阅读文档并尝试弄清楚。这是最好的学习方式。这就是为什么我尝试写出每个步骤的目的,以便您可以想象它应该做什么,即使我有错误。话虽如此,如果在此期间有任何不清楚的地方,请告诉我。
【解决方案2】:

注意 - 这可能与@Mad 的回答重叠;我会留下它,以防其他解释消除一些混乱。

In [32]: numList = [[0, 32, 84, 93, 1023, -1], [0, 23, 33, 45, -1, -1], [0, 10, 15, 21, 2
    ...: 4, 25], [0, 23, -1, -1, -1, -1], [0 , 13, 33, 34, -1, -1]] 
    ...: numArray = np.array(numList)                                                    
In [33]: numArray                                                                        
Out[33]: 
array([[   0,   32,   84,   93, 1023,   -1],
       [   0,   23,   33,   45,   -1,   -1],
       [   0,   10,   15,   21,   24,   25],
       [   0,   23,   -1,   -1,   -1,   -1],
       [   0,   13,   33,   34,   -1,   -1]])

每行的焊盘数:

In [34]: np.sum(numArray==-1, axis=1)                                                    
Out[34]: array([1, 2, 0, 4, 2])

每行非填充数:

In [35]: np.sum(numArray!=-1, axis=1)                                                    
Out[35]: array([5, 4, 6, 2, 4])

我不知道假设填充值都在最后是否会使这更有效。样本有点小,无法把握好时机。

从每一行中选择一个随机的非填充,第一次尝试显然是行列表理解:

In [40]: [np.random.choice(row[row!=-1]) for row in numArray]                            
Out[40]: [32, 0, 0, 23, 34]

或者根据长度(上图)(并假设尾部填充),我们可以为每一行选择一个随机索引:

In [46]: [np.random.choice(i) for i in Out[35]]                                          
Out[46]: [1, 2, 1, 0, 1]
In [47]: numArray[np.arange(numArray.shape[0]), [np.random.choice(i) for i in Out[35]]]  
Out[47]: array([93, 45, 21, 23, 13])

在@Mad 的提示中,randint 接受范围值的列表/数组,choice 推导可以替换为:

In [49]: np.random.randint(Out[35])                                                      
Out[49]: array([3, 1, 2, 1, 1])
In [50]: numArray[np.arange(numArray.shape[0]), np.random.randint(Out[35])]              
Out[50]: array([ 0, 23, 24,  0,  0])

【讨论】:

    猜你喜欢
    • 2013-11-18
    • 1970-01-01
    • 1970-01-01
    • 2018-05-07
    • 1970-01-01
    • 2019-07-23
    • 2016-02-25
    • 2016-11-06
    • 2017-06-11
    相关资源
    最近更新 更多