【问题标题】:Python: Conditional elements in arrayPython:数组中的条件元素
【发布时间】:2011-11-27 11:54:08
【问题描述】:

一个完整的 Python 新手的问题。

我有一个列数组,我需要根据应用于另一个数组的条件语句将某些值强制为零。我找到了两种解决方案,它们都提供了正确的答案。但是对于我通常需要的较大数组(>1E6 个元素)来说,它们都非常耗时——而且我怀疑这是一种糟糕的编程技术。这两个版本是:

from numpy import zeros,abs,multiply,array,reshape

def testA(y, f, FC1, FC2):
    c = zeros((len(f),1))
    for n in xrange(len(f)):
        if abs(f[n,0]) >= FC1 and abs(f[n,0]) <= FC2:
            c[n,0] = 1.
    w = multiply(c,y)
    return w

def testB(y, f, FC1, FC2):
    z = [(abs(f[n,0])>=FC1 and abs(f[n,0])<=FC2) for n in xrange(len(f))]
    z = multiply(array(z,dtype=float).reshape(len(f),1), y)
    return z

输入数组是列数组,因为这与要完成的后期处理相匹配。测试可以这样完成:

>>> from numpy.random import normal as randn
>>> fs, N = 1.E3, 2**22
>>> f = fs/N*arange(N).reshape((N,1))
>>> x = randn(size=(N,1))
>>> w1 = testA(x,f,200.,550.)
>>> z1 = testB(x,f,200.,550.)

在我的笔记本电脑上,testA 需要 18.7 秒,testB 需要 19.3 - N=2**22。在 testB 中,我还尝试包含 "z = [None]*len(f)" 以按照另一个线程中的建议进行预分配,但这并没有什么区别。

我有两个问题,希望得到相同的答案:

  1. 什么是“正确”的 Python 解决方案?
  2. 我可以做些什么来更快地得到答案?

例如,我故意不使用任何时间使用已编译的 Python - 我想先有一些工作代码。希望还有一些东西,这是很好的 Python 风格。我希望能够得到 N=2**22 的执行时间低于两秒左右。此特定操作将被多次使用,因此执行时间很重要。

如果问题很愚蠢,我提前道歉 - 我无法在大量并不总是易于访问的 Python 文档或其他线程中找到答案。

【问题讨论】:

  • y、f和返回值是否需要使用数组?为什么不使用列表呢?
  • 在接下来的处理中,我需要做一堆矩阵运算,我希望它是最简单的(以及代码用户所期望的)留在数组中。但如果列表更好,我也许可以稍后转移到数组。
  • HYRY 的提案效果很好。它在我的笔记本电脑上将时间缩短到 0.4 秒以下。我对此非常满意。非常感谢您的帮助!非常感谢。

标签: python arrays conditional


【解决方案1】:

使用 bool 数组访问数组 y 中的元素:

def testC(y, f, FC1, FC2):
    f2 = abs(f)
    idx = (f2>=FC1) & (f2<=FC2)
    y[~idx] = 0
    return y

【讨论】:

  • 是的,我也修改了。但它确实有很大的不同——仍然很容易阅读,而且确实表现得非常好。感谢您的所有 cmets 和帮助!
  • +1:据我所知,这是标准、高效的 NumPy 方式。
【解决方案2】:

所有这些都比 HYRY 解决方案慢很多:

怎么样

( x[1] if FC1&lt;=abs(x[0])&lt;=FC2 else 0 for x in itertools.izip(f,x) )

如果你需要做随机访问(很慢)

[ x[1] if FC1&lt;=abs(x[0])&lt;=FC2 else 0 for x in itertools.izip(f,x) ]

或者你也可以使用地图

map(lambda x: x[1] if FC1&lt;=abs(x[0])&lt;=FC2 else 0 , itertools,izip(f,x))

或使用矢量化(比 A 和 B 快,但比 C 慢得多)

b1v = np.vectorize(lambda a,b: a if 200<=abs(b)<=550 else 0)
b1 = b1v(f,x)

【讨论】:

  • NumPy 函数在数组上通常比标准 Python 函数快方式。因此,虽然这可行,但这并不完全符合问题的“大数组”部分。
  • map 本质上不是和你建议的第二个一样吗?我的印象是地图本质上是一个生成的列表。但我很容易误解了这一点。
  • 这相当于 numpy 的 map 吗? docs.scipy.org/doc/numpy/reference/generated/…
  • 啊..我测试了它们,包括使用矢量化。 HYRY 版本更快。
猜你喜欢
  • 2022-06-22
  • 2018-10-23
  • 2021-02-15
  • 2020-06-27
  • 1970-01-01
  • 1970-01-01
  • 2018-07-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多