【问题标题】:Numpy Array SlicingNumpy 数组切片
【发布时间】:2012-06-16 08:30:00
【问题描述】:

我有一个 1D numpy 数组和一些偏移/长度值。我想从这个数组中提取所有属于偏移量、偏移量+长度的条目,然后用于从原始数组构建一个新的“缩减”数组,该数组仅包含偏移量/长度对选择的那些值.

对于单个偏移量/长度对,这对于标准数组切片 [offset:offset+length] 来说是微不足道的。但是对于许多偏移量/长度值,我怎样才能有效地(即没有任何循环)呢?

谢谢, 标记

【问题讨论】:

  • 那么,理想情况下,你最终会得到什么?二维数组?
  • 不,再次使用一维数组,它仅包含根据偏移量/长度值从原始一维数组中选取的值。
  • 我认为offset/lentgh values 是某种数组,还是您只是想将数组划分为一组较小的数组。
  • 是的,偏移量/长度是数组。我真的不想分区,因为我想最后有一个一维数组。所以我需要你提到的部分较小数组的串联。但都没有循环。

标签: python arrays numpy scipy numeric


【解决方案1】:
>>> import numpy as np
>>> a = np.arange(100)
>>> ind = np.concatenate((np.arange(5),np.arange(10,15),np.arange(20,30,2),np.array([8])))
>>> a[[ind]]
array([ 0,  1,  2,  3,  4, 10, 11, 12, 13, 14, 20, 22, 24, 26, 28,  8])

【讨论】:

  • 附带说明,np.r_ 非常适合您使用 concatenate 所做的事情。你的长连接线减少到ind = np.r_[:5, 10:15, 20:30:2, 8]
【解决方案2】:

有天真的方法;只是做切片:

>>> import numpy as np
>>> a = np.arange(100)
>>> 
>>> offset_length = [(3,10),(50,3),(60,20),(95,1)]
>>>
>>> np.concatenate([a[offset:offset+length] for offset,length in offset_length])
array([ 3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 50, 51, 52, 60, 61, 62, 63,
       64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 95])

以下可能更快,但您必须进行测试/基准测试。

它通过构建所需索引的列表来工作,这是索引 numpy 数组的有效方法。

>>> indices = [offset + i for offset,length in offset_length for i in xrange(length)]
>>> a[indices]
array([ 3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 50, 51, 52, 60, 61, 62, 63,
       64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 95])

目前尚不清楚这是否真的会比天真的方法更快,但如果您有很多非常短的间隔,则可能是这样。但我不知道。

(这最后一种方法与@fraxel的方案基本相同,只是使用了不同的制作索引列表的方法。)


性能测试

我测试了几种不同的情况:一些短间隔、一些长间隔、许多短间隔。我使用了以下脚本:

import timeit

setup = 'import numpy as np; a = np.arange(1000); offset_length = %s'

for title, ol in [('few short', '[(3,10),(50,3),(60,10),(95,1)]'),
                  ('few long', '[(3,100),(200,200),(600,300)]'),
                  ('many short', '[(2*x,1) for x in range(400)]')]:
  print '**',title,'**'
  print 'dbaupp 1st:', timeit.timeit('np.concatenate([a[offset:offset+length] for offset,length in offset_length])', setup % ol, number=10000)
  print 'dbaupp 2nd:', timeit.timeit('a[[offset + i for offset,length in offset_length for i in xrange(length)]]', setup % ol, number=10000)
  print '    fraxel:', timeit.timeit('a[np.concatenate([np.arange(offset,offset+length) for offset,length in offset_length])]', setup % ol, number=10000)

这个输出:

** few short **
dbaupp 1st: 0.0474979877472
dbaupp 2nd: 0.190793991089
    fraxel: 0.128381967545
** few long **
dbaupp 1st: 0.0416231155396
dbaupp 2nd: 1.58000087738
    fraxel: 0.228138923645
** many short **
dbaupp 1st: 3.97210478783
dbaupp 2nd: 2.73584890366
    fraxel: 7.34302687645

这表明我的第一种方法在您有几个间隔时最快(并且明显更快),而我的第二种方法在您有很多间隔时最快。

【讨论】:

  • 这是我正在寻找的,但有没有办法在没有 for 循环的情况下获得它?
  • @MarkVogelsberger,您是否出于性能原因尝试删除 for 循环?如果是这样,您应该测试这些(和 fraxel 的)以查看它们是否足够快,这样您就可以避免进行不必要的微优化:只有当这些都不够快时,您才应该担心完全删除 for 循环。跨度>
  • @MarkVogelsberger,我在答案中添加了一些性能统计数据。
猜你喜欢
  • 2020-12-11
  • 2011-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-28
  • 2015-01-29
  • 2021-11-23
相关资源
最近更新 更多