首页 > 解决方案 > 在 Pandas DataFrame 上对迭代函数进行矢量化

问题描述

我有一个数据框,其中第一行是初始条件。

df = pd.DataFrame({"Year": np.arange(4),
                   "Pop": [0.4] + [np.nan]* 3})

和一个函数f(x,r) = r*x*(1-x),其中r = 2是一个常数和0 <= x <= 1

我想通过将函数Pop逐行迭代地应用于列来生成以下数据框。IE,df.Pop[i] = f(df.Pop[i-1], r=2)

df = pd.DataFrame({"Year": np.arange(4),
                   "Pop": [0.4, 0.48, 4992, 0.49999872]})

问题:是否有可能以矢量化的方式做到这一点?

我可以通过使用循环为 x 和 y 值构建列表来实现所需的结果,但这不是矢量化的。

我也试过这个,但所有nan地方都充满了0.48.

df.loc[1:, "Pop"] = R * df.Pop[:-1] * (1 - df.Pop[:-1])

标签: pythonpandasdataframeloopsvectorization

解决方案


以矢量化方式执行此操作是不可能的。

根据定义,向量化利用并行处理来减少执行时间。但是您问题中所需的值必须按顺序计算而不是并行计算。有关详细说明,请参阅此答案。df.expanding (2).apply(f)df.rolling(2).apply(f)之类的东西不起作用。

然而,获得更高的效率是可能的。您可以使用生成器进行迭代。这是实现迭代过程的非常常见的结构。

def gen(x_init, n, R=2):
    x = x_init
    for _ in range(n):
        x = R * x * (1-x)
        yield x

# execute            
df.loc[1:, "Pop"] = list(gen(df.at[0, "Pop"], len(df) - 1))

结果:

print(df)
        Pop
0  0.400000
1  0.480000
2  0.499200
3  0.499999

对于小型数据,在这里停下来是完全可以的。但是,如果该函数要执行很多次,您可以考虑使用numba优化生成器。

  • pip install numbaconda install numba首先在控制台中
  • import numba
  • @numba.njit在生成器前面添加装饰器。

把s的个数np.nan改成10^6,自己去看看执行时间的差异。在我的 Core-i5 8250U 64 位笔记本电脑上实现了从 468 毫秒到 217 毫秒的改进。


推荐阅读