【问题标题】:repeat arange with numpy用 numpy 重复范围
【发布时间】:2013-02-26 12:36:30
【问题描述】:

我有一个包含整数值的数组。

a = [2,1,4,0,2]

我想要一个 apply arange 函数到 a 中的每个值,以便拥有:

b = [0,1,0,0,1,2,3,1,2]
b "=" [arange(2),arange(1),arange(4),arange(0),arange(2)] 

实际上我使用 np.repeat 函数根据数组 a 重复数组行,并且我希望有一个 i 标记将每个重复值链接到原始值,并有一个标识号来区分它们。

我尝试使用 np.vectorize 但没有成功。

【问题讨论】:

  • 您能否再展示一些您的代码 - 您究竟是如何从 ab 的?最重要的是,What have you tried?

标签: python numpy repeat


【解决方案1】:

肯定有更多 numpythonic 的做事方式。一种可能是这样的:

import numpy as np
from numpy.lib.stride_tricks import as_strided

def concatenated_ranges(ranges_list) :
    ranges_list = np.array(ranges_list, copy=False)
    base_range = np.arange(ranges_list.max())
    base_range =  as_strided(base_range,
                             shape=ranges_list.shape + base_range.shape,
                             strides=(0,) + base_range.strides)
    return base_range[base_range < ranges_list[:, None]]

如果您只连接几个范围,那么 E 先生的纯 python 解决方案可能是您的最佳选择,但如果您要连接的范围只有 100 个,那么这颗星的速度明显更快。为了比较,我使用了从其他答案中提取的这两个函数:

def junuxx(a) :
    b = np.array([], dtype=np.uint8)
    for x in a:
        b = np.append(b, np.arange(x))
    return b

def mr_e(a) :
    return reduce(lambda x, y: x + range(y), a, [])

这里有一些时间安排:

In [2]: a = [2, 1, 4, 0 ,2] # the OP's original example

In [3]: concatenated_ranges(a) # show it works!
Out[3]: array([0, 1, 0, 0, 1, 2, 3, 0, 1])

In [4]: %timeit concatenated_ranges(a)
10000 loops, best of 3: 31.6 us per loop

In [5]: %timeit junuxx(a)
10000 loops, best of 3: 34 us per loop

In [6]: %timeit mr_e(a)
100000 loops, best of 3: 2.58 us per loop

In [7]: a = np.random.randint(1, 10, size=(10,))

In [8]: %timeit concatenated_ranges(a)
10000 loops, best of 3: 27.1 us per loop

In [9]: %timeit junuxx(a)
10000 loops, best of 3: 79.8 us per loop

In [10]: %timeit mr_e(a)
100000 loops, best of 3: 7.82 us per loop

In [11]: a = np.random.randint(1, 10, size=(100,))

In [12]: %timeit concatenated_ranges(a)
10000 loops, best of 3: 57.4 us per loop

In [13]: %timeit junuxx(a)
1000 loops, best of 3: 756 us per loop

In [14]: %timeit mr_e(a)
10000 loops, best of 3: 149 us per loop

In [15]: a = np.random.randint(1, 10, size=(1000,))

In [16]: %timeit concatenated_ranges(a)
1000 loops, best of 3: 358 us per loop

In [17]: %timeit junuxx(a)
100 loops, best of 3: 9.38 ms per loop

In [18]: %timeit mr_e(a)
100 loops, best of 3: 8.93 ms per loop

【讨论】:

  • 看时代很有趣。谢谢。
  • +1,我喜欢有基准的答案!我得研究一下这个as_strided 函数,它让我很困惑。
  • @Junuxx 这是那些让人无法抗拒的麻木小事之一。 These gists 来自 numpy wiz seberg 有一些很好的例子。
  • 非常感谢。读完之后,我查看了here 一些文档。它非常有帮助和有用。
【解决方案2】:

我的回答和 Junuxx 类似——我不确定你给 b 的答案是不是你想要的

a = [2, 1, 4, 0 ,2]
reduce(lambda x, y: x+range(y), a, [])

给我

[0, 1, 0, 0, 1, 2, 3, 0, 1]

【讨论】:

  • 另一个不一致的地方是问题标题和标签提到了 Numpy,但示例显示了列表。您的代码适用于列表,但不适用于 Numpy 数组(加上数组不做追加但向量加法)
  • 确实如此。我认为它提到了np.repeat,因为它与期望的行为很接近,而不是专门提出一个麻木的问题
【解决方案3】:

这就是您所描述的,即a 中所有值的串联。虽然这意味着您提供的b 中有一些错误:

>>> a = [2, 1, 4, 0, 2]
>>> b = np.array([], dtype=np.uint8)
>>>for x in a:
>>>    b = np.append(b, np.arange(x))
>>> print b
array([0,1,0,0,1,2,3,0,1,])

在你的编辑解释你想要一个范围列表之后,我认为这会更有效:

>>> a = [2, 1, 4, 0, 2]
>>> b = [np.arange(x) for x in a]
>>> print b
[array([0, 1]), array([0]), array([0, 1, 2, 3]), array([], dtype=int32),
 array([0, 1])]

【讨论】:

  • 当我开始使用 Python 时,拥有不同的解决方案总是好的。这将有助于解决未来的问题。我只是提到 Junuxx 的解决方案似乎比 E 先生的解决方案更快。
【解决方案4】:

一般来说,另一种内存效率更高且速度稍快的方法:

import numpy as np
def concatenated_ranges2(ranges_list):
    cumsum = np.append(0, np.cumsum(ranges_list[:-1]))
    cumsum = np.repeat(cumsum, ranges_list)
    return np.arange(cumsum.shape[0]) - cumsum

测试这个功能和上一个功能:

>>> a = np.random.randint(1, 10, size=(1000,))
>>> %timeit concatenated_ranges(a)
10000 loops, best of 3: 142 us per loop
>>> %timeit concatenated_ranges2(a)
10000 loops, best of 3: 72.6 us per loop

【讨论】:

    猜你喜欢
    • 2017-05-06
    • 2018-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 2012-11-13
    • 2019-03-26
    相关资源
    最近更新 更多