如何用np.einsum高效实现数组分段的逐元素外积?
嘿,很高兴你已经搞定了这个功能!用np.einsum确实能让这个分块外积的操作更简洁高效,尤其是在处理大规模数据的时候,能充分利用numpy的向量化优化。咱们来聊聊怎么用它替代原来的实现:
核心思路与实现
首先明确需求核心:把foo和bar各自分成3个等长块,对每一组对应块计算外积(即np.outer的效果)。假设你对foo的“特定重新排列”最终是将其整理成(3, N)的形状(N为单个块的长度),那用einsum可以一步完成所有块的外积计算,无需循环逐个处理。
举个具体的代码示例:
import numpy as np # 模拟输入数据,长度为3*N(这里N=5) foo = np.random.rand(15) bar = np.random.rand(15) # 第一步:执行foo的特定重新排列,这里以reshape为例替换成你的实际逻辑 foo_reshaped = foo.reshape(3, -1) # bar同理处理成对应分块形状 bar_reshaped = bar.reshape(3, -1) # 用einsum一次性计算所有块的外积 result = np.einsum('bi, bj -> bij', foo_reshaped, bar_reshaped)
对einsum下标的解释
这里的'bi, bj -> bij'可以拆解为:
bi:代表foo_reshaped的维度——第一个维度是块索引(共3块),第二个维度是块内的元素索引bj:代表bar_reshaped的维度——和foo对应,第一个维度是块索引,第二个是块内元素-> bij:指定输出维度——保留块索引b,对每个块,将foo的元素i与bar的元素j相乘,得到对应块的外积矩阵(形状为(N, N))
相比原实现的优势
- 代码更简洁:去掉了循环逻辑,用一行代码完成所有计算
- 性能更优:numpy的
einsum会在底层做向量化优化,比Python循环+多次调用np.outer的效率高很多,数据量越大优势越明显 - 扩展性强:如果后续需要调整输出形状(比如把每个外积展平),可以直接修改einsum下标,比如写成
'bi, bj -> b(ij)'就能直接得到展平后的结果(需numpy 1.16+版本支持)
如果你的“特定重新排列”是更复杂的元素重排,只要最终能将foo整理成(3, N)的二维数组,就可以直接套用上面的einsum写法。
内容的提问来源于stack exchange,提问作者Kid Charlamagne
相关产品推荐
相关产品推荐

