我想知道是否有可能将带有多个 if-else 语句的 for 循环转换为 Python 中的向量化版本。假设我有几个 numpy 数组
a,b,c,d
,其中 a,b,c,d
具有相同的长度。我需要编写以下 for 循环来计算 c
和 'd' 的值
for i in range(2, len(a)):
if (
a[i - 2] < b[i - 2]
and a[i - 1] > b[i - 1]
and c[i - 1] == 0
):
d[i] = -1
c[i] = c[i - 1] - 1
elif (
a[i - 2] > b[i - 2]
and a[i - 1] < b[i - 1]
and c[i - 1] == 0
):
d[i] = 1
c[i] = c[i - 1] + 1
else:
d[i] = 0
c[i] = c[i - 1]
问题是数组的大小是
10^5
,我必须为 10^3' times, the time complexity is
O(10^8)` 执行这个 for 循环,使用带有 if-else 语句的 for 循环非常慢且计算量大。我想知道是否有矢量化或更快的方法在 Python 中执行这些操作?
我已经向 ChatGPT 寻求帮助,它建议将
if
, elif
条件改为
condition1 = (
(a[:-2] < b[:-2]) &
(a[1:-1] > b[1:-1]) &
(d 1:-1] == 0)
)
condition2 = (
(a[:-2] > b[:-2]) &
(a[1:-1] < b[1:-1]) &
(d 1:-1] == 0)
)
分别是。然后,它使用
np.where
来执行条件
c[2:] = np.where(condition1, -1,0)
d[2:] = np.where(condition1, d[1:-1] - 1, d[1:-1])
c[2:] = np.where(condition2, 1, 0)
d[2:] = np.where(condition2, d1:-1] + 1, d[1:-1])
但是,与 for 循环结果相比,这些结果并不正确。另外,我不知道
else
语句的条件在哪里。
首先,你(或chatgpt)混合c和d(原始代码测试a,b和c,以决定影响-1,0,1到d。尝试的答案测试a,b,d以决定影响 -1,0,1 到 c)
其次,您的 chatgpt 答案没有正确链接
if/then/else
来创建 if cond1 thenCase1 else (if cond2 thenCase2 elseCase3)
。
但是如果您了解
np.where
的作用 (np.where(arrayOfBoolConds, thenArray, elseArray)
),您就可以自己完成。
例如
d[2:] = np.where(condition1, -1, np.where(condition2, 1, 0))
第三,你的问题不能直接矢量化。至少如果您一般性地考虑它的话(也许,在更仔细地思考您的问题的具体情况时,我们可能会将其转换为矢量化函数和累积函数的组合)。 ChatGPT 没有看到这一点。 您不能执行
c[2:] = vectorizedFunctionOf(c[1:-1])
并期望它正确迭代。无论如何,“向量化”和“迭代”是两个矛盾的词。向量化是同时处理情况的事实(这个词与 numpy 一起使用是说,从 python 的角度来看,它是在一个 numpy 的调用中完成的,即使在该调用内部,可能会发生迭代。但严格来说,矢量化是在 Cray 的超级计算机或英特尔 MMX 和下一个指令中发生的事情 - 当然,还有新的矢量化处理器:在不同的数据上同时执行多个相同的指令)
话虽这么说,有一些函数,如
cumsum
或 cumprod
在 numpy 的世界中被称为“向量化”,同时执行一些迭代过程(但同样,在单个 numpy 的调用中)。也许他们可以帮忙。
如果
c
不是条件的一部分,我会建议 c[2:]
是 c[1]+d[2:].cumsum()
。但是你需要一个完全计算的 c
来执行 np.where
,并且你需要那些 np.where
来计算 c
。因此,不可矢量化,除非您设法以不同的方式编写算法。
一般来说(除了一些可以通过
cumsum
的巧妙组合来完成的特定情况之外),你不能矢量化迭代过程。