如何无循环高效计算递推序列z?基于Pandas的技术问询
快速向量化实现递推序列计算
给定同长度的数值型DataFrame x、y 和初始值 a,需要计算满足以下递推规则的序列 z:
z[0] = az[i] = z[i-1]*(1+x[i]) + y[i](其中i ≥ 1)
核心思路:数学公式转化为向量化操作
递推式可展开为数学表达式,进而用numpy的累积乘积(cumprod)和累积求和(cumsum)实现完全向量化计算,彻底避免Python循环的性能损耗:
- 递推式的通解为:
$$z[i] = a \times \prod_{k=1}^i (1+x[k]) + \sum_{j=1}^i y[j] \times \prod_{k=j+1}^i (1+x[k])$$ - 将乘积项转化为累积乘积数组,求和项转化为累积求和与累积乘积的结合,利用numpy底层C实现完成计算,速度远优于Python循环。
实现代码
import pandas as pd import numpy as np # 示例输入 a = 213 x = pd.DataFrame({'RandomNumber': np.random.rand(200)}) y = pd.DataFrame({'RandomNumber': np.random.rand(200)}) # 提取数值数组(原逻辑中x、y的第0个元素未被使用,从索引1开始取数) p = 1 + x['RandomNumber'].values[1:] # p[i] = 1+x[1+i] q = y['RandomNumber'].values[1:] # 计算累积乘积数组P:P[0]=1,P[1]=p[0],P[2]=p[0]*p[1]...P[n] = 所有p的乘积 P = np.cumprod(np.concatenate([[1], p])) # 计算y项的累积求和部分 q_over_P = q / P[1:] # q[j]/P[j+1],对应通解中的y[j]/prod(1+x[1..j]) cum_sum_q_over_P = np.cumsum(q_over_P) Q = P[1:] * cum_sum_q_over_P # 通解中的求和项部分 # 构造最终的z序列 z = pd.Series( data=np.concatenate([[a], a * P[1:] + Q]), index=x.index, dtype=float )
验证正确性
用小数据集对比循环实现和向量化实现的结果:
# 测试用例 a_test = 1 x_test = pd.DataFrame({'RandomNumber': [0.1, 0.2, 0.3]}) y_test = pd.DataFrame({'RandomNumber': [10, 20, 30]}) # 循环实现 z_loop = pd.Series(index=x_test.index, dtype=float) z_loop[0] = a_test for i in range(1, len(x_test.index)): z_loop[i] = z_loop[i-1]*(1+x_test.iloc[i]) + y_test.iloc[i] # 向量化实现 p_test = 1 + x_test['RandomNumber'].values[1:] q_test = y_test['RandomNumber'].values[1:] P_test = np.cumprod(np.concatenate([[1], p_test])) q_over_P_test = q_test / P_test[1:] cum_sum_q_over_P_test = np.cumsum(q_over_P_test) Q_test = P_test[1:] * cum_sum_q_over_P_test z_vectorized = pd.Series( data=np.concatenate([[a_test], a_test * P_test[1:] + Q_test]), index=x_test.index, dtype=float ) # 对比结果 print(np.allclose(z_loop, z_vectorized)) # 输出True,说明结果一致
性能优势
对于大规模数据(比如100万条记录),向量化实现的速度会比Python循环快100~1000倍——numpy的cumprod和cumsum基于C语言底层优化,完全规避了Python循环的解释器开销。
内容的提问来源于stack exchange,提问作者Fred Dujardin
相关产品推荐
相关产品推荐

