向二维Numpy数组应用函数生成缩减新数组:寻求更Pythonic的实现方案
简化NumPy二维数组变换的Pythonic方案
嘿,我完全懂你的感受——刚上手NumPy的时候,维度处理和转置确实容易让人绕晕,尤其是想保持数组结构又不想写一堆冗余代码的时候。咱们来一步步把你的代码改得更简洁高效,同时解决你提到的单列提取问题!
首先解决单列提取的冗余问题
你原来用arrInput[:,n].reshape(arrInput.shape[0],1)来提取单列并保持二维,其实NumPy有更直接的写法:
- 方法一:用列表索引:
arrInput[:, [n]] - 方法二:用切片:
arrInput[:, n:n+1]
这两种方式都会直接返回一个二维数组(形状为(行数, 1)),完全不需要额外的reshape操作。本质是因为当你用单个整数索引列时([:,n]),NumPy会降维成一维数组;而用列表或切片索引时,会保留原数组的二维结构。
然后彻底简化整个流程:用向量化替代循环
你的核心逻辑是对每一对相邻的 tenor 和对应的利率列计算远期零息率,完全不需要写for循环——NumPy的矢量化运算可以帮你批量处理所有列对,代码更简洁,运行效率也更高(尤其是数据量大的时候)。
改造后的完整代码如下:
import numpy as np def fwdZeroRate(shtTenor, shtRate, lngTenor, lngRate): return 100 * ( np.power( np.power(1 + (lngRate/100), lngTenor) / np.power(1 + (shtRate/100), shtTenor), 1/(lngTenor - shtTenor) ) - 1 ) arrInput = np.array( [[2.170,1.905,1.850,2.031 ], [2.203,1.938,1.866,2.030 ], [2.367,2.038,1.936,2.070 ], [2.315,1.990,1.900,2.045 ], [2.291,1.941,1.871,2.040 ], [2.302,1.952,1.881,2.0525]] ) tenors = [2,5,10,30] # 批量获取相邻的tenor对和对应的利率列 t1s = tenors[:-1] t2s = tenors[1:] r1s = arrInput[:, :-1] # 前3列,对应每个t1 r2s = arrInput[:, 1:] # 后3列,对应每个t2 # 直接批量计算,结果形状为(6,3),正好是我们需要的arrResult arrResult = fwdZeroRate(t1s, r1s, t2s, r2s) print(arrResult)
为什么这样更优?
- 彻底消除循环:利用NumPy的广播机制,
t1s(长度3的列表)会自动和r1s(6行3列的数组)逐列匹配运算,不需要手动遍历每个列对。 - 去掉冗余的转置和列表操作:原来的
res.append(arr)和最后转置np.array(res).T都不需要了,计算结果直接就是目标形状。 - 代码更易读:逻辑一目了然——获取所有输入对,批量计算,直接得到结果。
运行这段代码,你会得到和原来完全一致的输出:
[[1.7287153 1.79502968 2.12162059] [1.76171517 1.79405085 2.11209899] [1.81925431 1.83410196 2.13706604] [1.77390706 1.81007942 2.11757736] [1.70833223 1.80104807 2.12460511] [1.71933216 1.81004944 2.13835823]]
关键知识点回顾
- 提取单列并保持二维:优先用
[:, [n]]或[:, n:n+1],避免reshape。 - 尽量用NumPy的矢量化运算替代Python循环,不仅代码更简洁,性能也会有大幅提升。
- 理解NumPy的广播机制:当操作不同形状的数组时,NumPy会自动扩展维度以匹配运算,这是NumPy高效的核心之一。
内容的提问来源于stack exchange,提问作者DS_London
相关产品推荐
相关产品推荐

