【问题标题】:How can I get an array of alternating values in python?如何在 python 中获得一组交替值?
【发布时间】:2011-08-22 23:22:55
【问题描述】:

这里有一个简单的问题:

我正在尝试获取一个在给定长度下交替值(1、-1、1、-1.....)的数组。 np.repeat 只给了我 (1, 1, 1, 1,-1, -1,-1, -1)。想法?

【问题讨论】:

  • 步幅或视图怎么样?有可能吗?

标签: python numpy


【解决方案1】:

我喜欢@Benjamin 的解决方案。不过,另一种选择是:

import numpy as np
a = np.empty((15,))
a[::2] = 1
a[1::2] = -1

这也允许奇数长度的列表。

编辑:还只是为了注意速度,对于 10000 个元素的数组

import numpy as np
from timeit import Timer

if __name__ == '__main__':

    setupstr="""
import numpy as np
N = 10000
"""

    method1="""
a = np.empty((N,),int)
a[::2] = 1
a[1::2] = -1
"""

    method2="""
a = np.tile([1,-1],N)
"""

    method3="""
a = np.array([1,-1]*N)   
"""

    method4="""
a = np.array(list(itertools.islice(itertools.cycle((1,-1)), N)))    
"""
    nl = 1000
    t1 = Timer(method1, setupstr).timeit(nl)
    t2 = Timer(method2, setupstr).timeit(nl)
    t3 = Timer(method3, setupstr).timeit(nl)
    t4 = Timer(method4, setupstr).timeit(nl)

    print 'method1', t1
    print 'method2', t2
    print 'method3', t3
    print 'method4', t4

导致以下时间:

method1 0.0130500793457
method2 0.114426136017
method3 4.30518102646
method4 2.84446692467

如果N = 100,事情开始变得平衡,但从空的numpy数组开始仍然明显更快(nl更改为10000)

method1 0.05735206604
method2 0.323992013931
method3 0.556654930115
method4 0.46702003479

Numpy 数组是特别棒的对象,不应像 python 列表那样对待。

【讨论】:

  • +1:这相当快,很可能是使用 numpy 的最佳方式。
  • 你也可以使用 a = np.ones(15) 而不是 empty 和 =1。
  • @DSM 这是另一种可能性,但在我的测试中,它仍然比我发布的解决方案慢一点(但仍然比其他所有方法都快)。我不久前发现了这个填充技巧,但仍然不确定为什么它通常比更直接/直观的解决方案更快。我是timeit 的忠实粉丝,因为它是一个客观的仲裁者。
  • @JoshAdel:是的timeit 在某种意义上是客观的,但请记住,python 通常是为了简单和可读性而编写的,而不仅仅是为了速度!特别是如果您没有真正的理由来优化 CPU 时间或内存,我会说坚持使用更常见、更易读的解决方案,例如列表理解或cycle:您和其他人将来可能会喜欢它。
  • @JoshAdel:那我就听你的了,因为我不是 numpy 专家,但据记录,困扰我的是 define/iterslice/reiterslice 组合,而不是 numpy功能。我认为numpy.ones() 会更好,因为您只需对数组进行一次切片,这更易读,因为它只有两个语句并且您直截了当。我同意您的解决方案非常易读且聪明,这就是为什么它得到了我的支持,但这并不意味着它是完美的! :)
【解决方案2】:

使用调整大小():

In [38]: np.resize([1,-1], 10) # 10 is the length of result array
Out[38]: array([ 1, -1,  1, -1,  1, -1,  1, -1,  1, -1])

它可以产生奇数长度的数组:

In [39]: np.resize([1,-1], 11)
Out[39]: array([ 1, -1,  1, -1,  1, -1,  1, -1,  1, -1,  1])

【讨论】:

    【解决方案3】:

    使用numpy.tile

    import numpy
    a = numpy.tile([1,-1], 15)
    

    【讨论】:

    • 不允许奇数长度的列表
    • 大声笑不是我的!有人生气了还是怎么了?
    【解决方案4】:

    如果你想要一个内存效率高的解决方案,试试这个:

    def alternator(n):
        for i in xrange(n):
            if i % 2 == 0:
                yield 1
            else:
                yield -1
    

    然后你可以像这样迭代答案:

    for i in alternator(n):
        # do something with i
    

    【讨论】:

    • 我不是反对者,但我想这是因为重新实现 itertools.islice(itertools.cycle((1,-1)), n) 没有意义。
    • +1 好吧,你得到了我的支持,因为它既新颖又高效!在库中看到某些东西的原始实现总是很高兴,这样您就可以看到它的内部工作原理。可能会更笼统一些,但是嗯。也很好地结合了奇数长度。绝对不值得投反对票。
    • agf,这是另一种方式。我的实现并不过分冗长、过于简洁或浪费,并且向 OP 展示了如何以不同的方式做事。这并不愚蠢。机器向往:谢谢
    【解决方案5】:

    使用乘法:

    [1,-1] * n
    

    【讨论】:

    • 或者*(int)(n/2)如果你想让n成为列表的长度。
    • 不允许奇数长度的列表
    【解决方案6】:

    也许您正在寻找 itertools.cycle?

    list_ = (1,-1,2,-2)  # ,3,-3, ...
    
    for n, item in enumerate(itertools.cycle(list_)):
        if n==30:
            break
    
        print item
    

    【讨论】:

      【解决方案7】:

      我将把它们扔掉,因为它们在某些情况下可能更有用。

      如果你只是想在正负之间交替:

      [(-1)**i for i in range(n)]
      

      或更通用的解决方案

      nums = [1, -1, 2]
      [nums[i % len(nums)] for i in range(n)]
      

      【讨论】:

        猜你喜欢
        • 2018-07-13
        • 2020-07-19
        • 2016-06-10
        • 1970-01-01
        • 2015-12-13
        • 1970-01-01
        • 2013-06-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多