【问题标题】:Iterating and accumulating over a numpy array with a custom function使用自定义函数迭代和累积一个 numpy 数组
【发布时间】:2018-05-21 18:04:45
【问题描述】:

7 年多来一直存在一些相关问题,但我再次提出这个问题,因为我看不到提供 'numpy' 方式迭代方法。

任务如下: 如果我有一个 numpy 数组 'arr' 并且有一个 自定义函数 'fn',我如何在 'arr' 上迭代地应用 'fn'? 'fn' 不能由 ufunc 工具构造。

下面是我想出的玩具代码:

import numpy as np

r_list = np.arange(1,6,dtype=np.float32)
# r_list = [1. 2. 3. 4. 5.]
r_list_extended = np.append([0.],r_list)
R_list_extended = np.zeros_like(r_list_extended)
print(r_list)
gamma = 0.99
pv_mc = lambda a, x: x+ a*gamma

# no cumsum, accumulate available
for i in range(len(r_list_extended)):
    if i ==0: continue
    else: R_list_extended[i] = pv_mc(R_list_extended[i-1],r_list_extended[i])

R_list = R_list_extended[1:]
print(R_list)
# R_list == [ 1.          2.99        5.9601      9.900499   14.80149401]

r_list 是每个时间的 r 数组。 R_list 是折扣 r 的累积和。 假设 r_list 和 R_list 预先恢复。 上面的循环执行 R[t] : r[t] + gamma * R[t-1]

我认为这不是利用 numpy 的最佳方式.... 如果可以利用 tensorflow,那么 tf.scan() 的工作如下:

import numpy as np
import tensorflow as tf

r_list = np.arange(1,6,dtype=np.float32)
# r_list = [1. 2. 3. 4. 5.]
gamma = 0.99
pv_mc = lambda a, x: x+ a*gamma
R_list_graph = tf.scan(pv_mc, r_list, initializer=np.array(0,dtype=np.float32))

with tf.Session() as sess:
    R_list = sess.run(R_list_graph, feed_dict={})
    print(R_list)
    # R_list = [ 1.        2.99      5.9601    9.900499 14.801495]

提前感谢您的帮助!

【问题讨论】:

    标签: numpy tensorflow iterator numpy-ufunc


    【解决方案1】:

    您可以使用np.frompyfunc,其文档有些晦涩。

    import numpy as np
    
    r_list = np.arange(1,6,dtype=np.float32)
    # r_list = [1. 2. 3. 4. 5.]
    r_list_extended = np.append([0.],r_list)
    R_list_extended = np.zeros_like(r_list_extended)
    print(r_list)
    gamma = 0.99
    pv_mc = lambda a, x: x+ a*gamma
    ufunc = np.frompyfunc(pv_mc, 2, 1)
    R_list = ufunc.accumulate(r_list, dtype=np.object).astype(float)
    print(R_list)
    

    【讨论】:

    • 我已经多次推荐了frompyfunc,但没有意识到它会返回一个ufuncaccumulate 之类的方法。在其他地方,我发现与显式循环相比,它最多可以提供 2 倍的加速。在这里它似乎提供了 1.5 的加速,但它仍然比 cumsum 慢 20 倍(gamma=1 案例)。
    • dtype=object 是一个容易被忽略的重要参数。 frompyfunc 返回一个对象数组。
    • 哦,这太棒了。是的,我像 'vectorize' 或 sth 之类的东西四处游荡,但 np.frompyfunc 是我能做的最好的选择。正如@hpaulj 提到的,我不明白/不喜欢为什么只允许 np.object 累积,因为它使计算变慢并且最终需要另一个属性更改器 .astype(float) 。但同样,dtype 只接受 np.object(不是 np.float)所以我认为这个答案可能是要走的路。但是让我等一下其他人的想法
    • "返回的 ufunc 总是返回 PyObject 数组。" - 这就是他们所说的,,,不能避免使用'object' dtype
    • *更新:对于这个特定的计算,scipy.signal.lfilter 让你的生活更轻松
    猜你喜欢
    • 2018-08-17
    • 2012-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-29
    • 1970-01-01
    • 2017-04-02
    相关资源
    最近更新 更多