计算数组中下n个元素的乘积

ese*_*sem 4 arrays matlab matrix multiplication sliding-window

我想计算n矩阵的下一个相邻元素的乘积.n要乘以的元素数量应在函数输入中给出.例如,对于此输入,我应该从第一个开始计算每3个连续元素的乘积.

[p, ind] = max_product([1 2 2 1 3 1],3);
Run Code Online (Sandbox Code Playgroud)

这给了[1*2*2, 2*2*1, 2*1*3, 1*3*1] = [4,4,6,3].

有没有实用的方法呢?现在我这样做:

for ii = 1:(length(v)-2)
    p = prod(v(ii:ii+n-1));
end
Run Code Online (Sandbox Code Playgroud)

v输入向量在哪里,是n要乘的元素数.

在此示例中,n=3但可以采用任何正整数值.

根据n是奇数还是偶数还是length(v)奇数或偶数,我有时得到正确的答案但有时会出错.
例如参数:

v = [1.35912281237829 -0.958120385352704 -0.553335935098461 1.44601450110386 1.43760259196739 0.0266423803393867 0.417039432979809 1.14033971399183 -0.418125096873537 -1.99362640306847 -0.589833539347417 -0.218969651537063 1.49863539349242 0.338844452879616 1.34169199365703 0.181185490389383 0.102817336496793 0.104835620599133 -2.70026800170358 1.46129128974515 0.64413523430416 0.921962619821458 0.568712984110933] 
n = 7
Run Code Online (Sandbox Code Playgroud)

我收到错误:

Index exceeds matrix dimensions.
Error in max_product (line 6)  
p = prod(v(ii:ii+n-1));
Run Code Online (Sandbox Code Playgroud)

有没有正确的一般方法呢?

Dev*_*-iL 7

基于Fast numpy rolling_product中的解决方案,我想建议一个MATLAB版本,它利用了R2016a中movsum引入的功能.

数学推理是数字的乘积等于它们的对数之和的指数:

在此输入图像描述

上面可能的MATLAB实现可能如下所示:

function P = movprod(vec,window_sz)
  P = exp(movsum(log(vec),[0 window_sz-1],'Endpoints','discard'));
  if isreal(vec)   % Ensures correct outputs when the input contains negative and/or
    P = real(P);   %   complex entries.
  end
end
Run Code Online (Sandbox Code Playgroud)

几点说明:

  1. 我没有对此解决方案进行基准测试,也不知道它在性能方面与其他建议的比较.
  2. 它应该适用于包含零和/或负和/或复杂元素的向量.
  3. 它可以很容易地扩展到接受一个维度来操作(对于数组输入),以及由其提供的任何其他自定义movsum.
  4. 1 ST输入被假定为或者是double或一个complex double 向量.
  5. 输出可能需要四舍五入.


the*_*alk 5

更新

受到Dev-iL精心设计的答案的启发,这个方便的解决方案不需要Matlab R2016a或更高版本:

out = real( exp(conv(log(a),ones(1,n),'valid')) )
Run Code Online (Sandbox Code Playgroud)

基本思想是将乘法转换为和,并且可以使用移动平均,这反过来可以通过解决方案来实现conv.


老答案

这是使用gallery循环矩阵并在乘以元素之前索引结果矩阵的相关部分的一种方法:

a = [1 2 2 1 3 1]
n = 3

%// circulant matrix
tmp = gallery('circul', a(:))
%// product of relevant parts of matrix
out = prod(tmp(end-n+1:-1:1, end-n+1:end), 2)
Run Code Online (Sandbox Code Playgroud)
out =

     4
     4
     6
     3
Run Code Online (Sandbox Code Playgroud)

如果输入中没有零,则内存效率更高:

a = [10 9 8 7 6 5 4 3 2 1]
n = 2

%// cumulative product
x = [1 cumprod(a)] 
%// shifted by n and divided by itself
y = circshift( x,[0 -n] )./x 
%// remove last elements 
out = y(1:end-n) 
Run Code Online (Sandbox Code Playgroud)
out =

    90    72    56    42    30    20    12     6     2
Run Code Online (Sandbox Code Playgroud)