当前位置: 首页 > 面试题库 >

使用多个自定义索引范围构建numpy数组,而无需显式循环

姜鸿
2023-03-14
问题内容

在Numpy中,有没有一种Pythonic的方法来创建具有array1和array2的自定义范围的array3而没有循环?在范围上进行迭代的直接解决方案是可行的,但是由于我的数组遇到了数百万个项目,因此我正在寻找一种更有效的解决方案(也许也是语法糖)。

例如

array1 = np.array([10, 65, 200]) 
array2 = np.array([14, 70, 204])
array3 = np.concatenate([np.arange(array1[i], array2[i]) for i in
                         np.arange(0,len(array1))])

print array3

结果:[10,11,12,13,65,66,67,68,69,200,201,202,203]


问题答案:

前瞻性方法

我将在如何处理此问题上倒退。

采取问题中列出的示例。我们有 -

array1 = np.array([10, 65, 200])
array2 = np.array([14, 70, 204])

现在,查看所需的结果-

result: [10,11,12,13,65,66,67,68,69,200,201,202,203]

让我们计算组的长度,因为接下来我们需要这些长度来说明解决方法。

In [58]: lens = array2 - array1

In [59]: lens
Out[59]: array([4, 5, 4])

想法是使用1的初始化数组,当在整个长度上累加总和时,将为我们提供所需的结果。这种累加的总和将是我们解决方案的最后一步。为什么要1初始化?好吧,因为我们有一个数组,它以的步长递增,1但在特定位置,我们有相应于新进来的班次的班次。

现在,由于cumsum这是最后一步,所以在此之前的步骤应为我们提供-

array([ 10,   1,   1,   1,  52,   1,   1,   1,   1, 131,   1,   1,   1])

如前所述1[10,52,131]在特定位置充满了它。这10似乎来自的第一个元素array1,但是其余的呢?第二个52进来的65-13(看result)和它13附带的组中的开始10就跑,因为第一组的长度4。因此,如果这样做65 - 10 - 4,我们将获得51,然后加上1accomodate作为边界停止,我们将有52,这是所需的平移值。同样,我们会得到131

因此,shifting-values可以这样计算:

In [62]: np.diff(array1) - lens[:-1]+1
Out[62]: array([ 52, 131])

接下来,要获得shifting-places发生此类偏移的位置,我们可以简单地对组长度进行累积求和-

In [65]: lens[:-1].cumsum()
Out[65]: array([4, 9])

为了完整起见,我们需要预先附加0与数组shifting-placesarray1[0]shifting-values

因此,我们将逐步介绍我们的方法!

放回碎片

1]获取每个组的长度:

lens = array2 - array1

2]获取发生移位的索引,并将值放入1的初始化数组中:

shift_idx = np.hstack((0,lens[:-1].cumsum()))
shift_vals = np.hstack((array1[0],np.diff(array1) - lens[:-1]+1))

3]安装程序1的初始化ID数组,用于将这些值插入到上一步中列出的索引处:

id_arr = np.ones(lens.sum(),dtype=array1.dtype)
id_arr[shift_idx] = shift_vals

4]最后,对ID数组进行累积求和:

output = id_arr.cumsum()

以函数格式列出,我们将-

def using_ones_cumsum(array1, array2):
    lens = array2 - array1
    shift_idx = np.hstack((0,lens[:-1].cumsum()))
    shift_vals = np.hstack((array1[0],np.diff(array1) - lens[:-1]+1))
    id_arr = np.ones(lens.sum(),dtype=array1.dtype)
    id_arr[shift_idx] = shift_vals
    return id_arr.cumsum()

它也适用于重叠范围!

In [67]: array1 = np.array([10, 11, 200]) 
    ...: array2 = np.array([14, 18, 204])
    ...:

In [68]: using_ones_cumsum(array1, array2)
Out[68]: 
array([ 10,  11,  12,  13,  11,  12,  13,  14,  15,  16,  17, 200, 201,
       202, 203])

运行时测试

让我们将建议的方法与中的其他矢量化方法进行比较@unutbu's flatnonzero based solution,该方法已经证明比循环方法好得多-

In [38]: array1, array2 = (np.random.choice(range(1, 11), size=10**4, replace=True)
    ...:                   .cumsum().reshape(2, -1, order='F'))

In [39]: %timeit using_flatnonzero(array1, array2)
1000 loops, best of 3: 889 µs per loop

In [40]: %timeit using_ones_cumsum(array1, array2)
1000 loops, best of 3: 235 µs per loop

改善!

现在,代码方式的NumPy不喜欢追加。因此,对于np.hstack下面列出的稍有改进的版本,可以避免这些调用-

def get_ranges_arr(starts,ends):
    counts = ends - starts
    counts_csum = counts.cumsum()
    id_arr = np.ones(counts_csum[-1],dtype=int)
    id_arr[0] = starts[0]
    id_arr[counts_csum[:-1]] = starts[1:] - ends[:-1] + 1
    return id_arr.cumsum()

让我们将其与我们的原始方法进行比较-

In [151]: array1,array2 = (np.random.choice(range(1, 11),size=10**4, replace=True)\
     ...:                                      .cumsum().reshape(2, -1, order='F'))

In [152]: %timeit using_ones_cumsum(array1, array2)
1000 loops, best of 3: 276 µs per loop

In [153]: %timeit get_ranges_arr(array1, array2)
10000 loops, best of 3: 193 µs per loop

因此,我们在 30% 那里提高了性能!



 类似资料:
  • 问题内容: 我想从一维numpy数组(或向量)中选择多个不相邻的范围。 假设: 当然,这可行: 这可以通过单个索引获取: 但是,如果我要选择范围,该怎么办? 我试过了: 有没有简单的方法可以执行此操作,或者我需要分别生成它们并进行连接? 问题答案: 您需要在索引之前或之后进行串联。 使它变得容易 扩展切片并将其连接。 您可以混合切片和列表: 在索引之前进行连接可能比在之后进行连接要快,但是对于这样

  • 问题 你想定义一个数组的范围。 解决方案 在 CoffeeScript 中,有两种方式定义数组元素的范围。 myArray = [1..10] # => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ] myArray = [1...10] # => [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] 要想反转元素的范围,则可以写成下面这样。 myLargeArray =

  • 问题内容: 我已经开始处理我的第一个Java程序,它是一个简单的计算器,但是我得到一个错误,声称我的数组超出范围。我尝试对其进行调试,以了解这样做的原因和原因,并遵循纸上的代码,两者均显示了我期望和期望的结果。因此,我看不到问题出在哪里。代码不完整。 根据调试器,此行出现错误: 这是我当前拥有的代码的主要部分: 这是我收到的错误消息: 问题答案: 当等于中的最后一个元素索引时,则将大于最后一个元素

  • 问题内容: 我要寻找一个量化的方式来索引的索引。 例如: 我想建立一个新的数组,以便该数组中的每一行(i)都是array的row(i),并由数组inds(i)的行索引。我想要的输出是: 我可以通过循环来实现: 但我正在寻找一种纯矢量化的解决方案。 问题答案: 使用索引数组对另一个数组进行索引时,每个索引数组的形状应与 输出 数组的形状匹配。您希望列索引匹配,并且您希望行索引匹配输出的行,例如: 由

  • 问题内容: 我已经声明了我的数组 然后我初始化它的值像 在运行时,它给出错误“数组索引超出范围” 问题答案: 正如评论员@C_X和@MartinR所说,您的数组为空。这是根据需要初始化的方法… …当然,如果您只想零,那么循环现在是多余的!

  • 我想在pyqt GUI中为matplotlib(python)中的多个绘图创建一个自定义图例。(pyqt建议不要使用pyplot,因此必须使用面向对象的方法)。 网格中将显示多个绘图,但用户可以定义要显示的绘图数量。我希望图例显示在所有绘图的右侧,因此我不能简单地为最后绘制的轴创建图例。我希望为整个图形创建图例,而不仅仅是最后一个轴(类似于pyplot中的plt.figlegend)。 在我在别处