R 简化计算,因此可以使用矩阵运算

R 简化计算,因此可以使用矩阵运算,r,algorithm,matlab,transformation,matrix-multiplication,R,Algorithm,Matlab,Transformation,Matrix Multiplication,我的基本运算是对两个相同长度的概率向量的运算。 我们把它们叫做A,B。R中的公式是: t = 1-prod(1-A*B) 也就是说,结果是标量,(1-AB)是逐点运算,其结果是第i个元素为1-a_i*b_i的向量。prod运算符给出向量元素的乘积。 这个(正如你所猜测的)的意思是:假设A是一种疾病(或其他信号)的N个来源中的每一个都有某种疾病的概率。B是每个传染源向目标传播疾病的概率向量(如果他们有)。结果是目标从(至少一个)来源获得疾病的概率 好的,现在我有很多类型的信号,所以我有很多“A”

我的基本运算是对两个相同长度的概率向量的运算。 我们把它们叫做A,B。R中的公式是:

t = 1-prod(1-A*B)
也就是说,结果是标量,
(1-AB)
是逐点运算,其结果是第i个元素为
1-a_i*b_i
的向量。
prod
运算符给出向量元素的乘积。
这个(正如你所猜测的)的意思是:假设A是一种疾病(或其他信号)的N个来源中的每一个都有某种疾病的概率。B是每个传染源向目标传播疾病的概率向量(如果他们有)。结果是目标从(至少一个)来源获得疾病的概率

好的,现在我有很多类型的信号,所以我有很多“A”向量。对于每种类型的信号,我有许多目标,每个目标都有不同的传输概率(或许多“B”向量),我想计算每对信号的“t”结果。
理想情况下,如果运算是向量的“内积”,则矩阵乘法可以实现这一点。但我的操作不是这样(我想)

我要找的是向量a和B上的某种变换,所以我可以使用矩阵乘法。任何其他简化我的计算的建议都是受欢迎的

下面是一个示例(R中的代码)


这是Rcpp擅长的工作。嵌套循环是直接实现的,并且不需要太多C++体验。(我喜欢RcppEigen,但你并不真的需要它。你可以使用“纯”Rcpp。)

基准:

library(microbenchmark)
microbenchmark(doupleApply(A,B), funRcpp(A,B))

# Unit: microseconds
#             expr     min       lq   median       uq     max neval
#doupleApply(A, B) 169.699 179.2165 184.4785 194.9290 280.011   100
#    funRcpp(A, B)   1.738   2.3560   4.6885   4.9055  11.293   100

set.seed(42)
A <- matrix(rnorm(3*1e3), ncol=3)
B <- matrix(rnorm(3*1e3), nrow=3)

all.equal(doupleApply(A,B), funRcpp(A,B))
#[1] TRUE
microbenchmark(doupleApply(A,B), funRcpp(A,B), times=5)

# Unit: milliseconds
#              expr        min         lq     median         uq        max neval
# doupleApply(A, B) 4483.46298 4585.18196 4587.71539 4672.01518 4712.92597     5
#     funRcpp(A, B)   24.05247   24.08028   24.48494   26.32971   28.38075     5
库(微基准)
微基准(doupleApply(A,B),funRcpp(A,B))
#单位:微秒
#expr最小lq中值uq最大neval
#doupleApply(A,B)169.699 179.2165 184.4785 194.9290 280.011 100
#funRcpp(A,B)1.7382.35604.68854.905511.293100
种子(42)

A首先,我应该注意,R代码可能会误导一些Matlab用户,因为R中的
A*B
相当于Matlab中的
A*B
(元素乘法)。我在计算中使用了符号变量,因此发生的操作更清晰

syms a11 a12 a21 a22 b11 b12 b21 b22
syms a13 a31 a23 a32 a33
syms b13 b31 b23 b32 b33

首先考虑最简单的情况,我们只有1个向量A和1个向量B:

A1 = [a11;a21] ;
B1 = [b11;b21] ;
你想要的结果是

1 - prod(1-A1.*B1)
=
1 - (a11*b11 - 1)*(a12*b12 - 1)
现在假设我们有3个向量A和2个向量B在列中一个挨着一个堆叠:

A3 = [a11 a12 a13;a21 a22 a23; a31 a32 a33];
B2 = [b11 b12 ;b21 b22 ; b31 b32];
为了获得A3列向量的所有可能组合与B2列向量的所有可能组合的索引,可以执行以下操作:

[indA indB] = meshgrid(1:3,1:2);
现在因为对于两个向量a,b的两两乘积,它认为
a.*b=b.*a
我们可以只保留唯一的索引对。您可以按如下方式执行此操作:

indA = triu(indA); indB = triu(indB);
indA = reshape(indA(indA>0),[],1); indB = reshape(indB(indB>0),[],1);
现在可以计算出您想要的结果:

result = 1 - prod(1-A3(:,indA).*B2(:,indB))
为了提高可读性:

pretty(result.')

=

  +-                                               -+ 
  |  (a11 b11 - 1) (a21 b21 - 1) (a31 b31 - 1) + 1  | 
  |                                                 | 
  |  (a12 b11 - 1) (a22 b21 - 1) (a32 b31 - 1) + 1  | 
  |                                                 | 
  |  (a12 b12 - 1) (a22 b22 - 1) (a32 b32 - 1) + 1  | 
  |                                                 | 
  |  (a13 b11 - 1) (a23 b21 - 1) (a33 b31 - 1) + 1  | 
  |                                                 | 
  |  (a13 b12 - 1) (a23 b22 - 1) (a33 b32 - 1) + 1  | 
  +-                                               -+

如果我理解amit的问题,您可以在Matlab中执行以下操作:

[indA indB] = meshgrid(1:3,1:2);
数据:

第一种解决方案

% One-liner solution:
tic
C = squeeze(1 - prod(1 - repmat(A, [1 1 K]) .* permute(repmat(B, [1 1 M]), [3 1 2]), 2));
toc
% Elapsed time is 6.695364 seconds.
第二种解决方案

% Partial vectorization 1
tic
D = zeros(M, K);
for hh = 1:M
  tmp = repmat(A(hh, :)', 1, K);
  D(hh, :) = 1 - prod((1 - tmp .* B), 1);
end
toc
% Elapsed time is 0.686487 seconds.
% Partial vectorization 2
tic
E = zeros(M, K);
for hh = 1:M
  for ii = 1:K
    E(hh, ii) = 1 - prod(1 - A(hh, :)' .* B(:, ii));
  end
end
toc
% Elapsed time is 2.003891 seconds.
第三种解决方案

% Partial vectorization 1
tic
D = zeros(M, K);
for hh = 1:M
  tmp = repmat(A(hh, :)', 1, K);
  D(hh, :) = 1 - prod((1 - tmp .* B), 1);
end
toc
% Elapsed time is 0.686487 seconds.
% Partial vectorization 2
tic
E = zeros(M, K);
for hh = 1:M
  for ii = 1:K
    E(hh, ii) = 1 - prod(1 - A(hh, :)' .* B(:, ii));
  end
end
toc
% Elapsed time is 2.003891 seconds.
第四种解决方案

% No vectorization at all
tic
F = ones(M, K);
for hh = 1:M
  for ii = 1:K
    for jj = 1:N
      F(hh, ii) = F(hh, ii) * prod(1 - A(hh, jj) .* B(jj, ii));
    end
    F(hh, ii) = 1 - F(hh, ii);
  end
end
toc
% Elapsed time is 19.201042 seconds.
解是等价的

chck1 = C - D;
chck2 = C - E;
chck3 = C - F;
figure
plot(sort(chck1(:)))
figure
plot(sort(chck2(:)))
figure
plot(sort(chck3(:)))

…但显然,不使用repmat和permute的部分矢量化方法在内存和执行时间方面更有效。

我不知道为什么1-prod(1-A1.*B1)变为粗体:)谢谢。我知道C++更快。但本质上它们是相同的——都需要O(N^3)计算。然而,矩阵乘法所需的时间比这少。这就是为什么我关注的是转换而不是实现优化我不同意。矩阵乘法不需要较少的计算。矩阵乘法的研究由来已久。我认为在20世纪60年代末或70年代初,有一种算法可以在O(n^2.7)左右乘以矩阵。从那以后,有了一些改进,我想现在你用不到O(n^2.4)就得到了它,但是你的评论给了我一个想法。我将研究更简单的矩阵算法,看看它们是否可以更改为我的规范。我会让你知道的。
% No vectorization at all
tic
F = ones(M, K);
for hh = 1:M
  for ii = 1:K
    for jj = 1:N
      F(hh, ii) = F(hh, ii) * prod(1 - A(hh, jj) .* B(jj, ii));
    end
    F(hh, ii) = 1 - F(hh, ii);
  end
end
toc
% Elapsed time is 19.201042 seconds.
chck1 = C - D;
chck2 = C - E;
chck3 = C - F;
figure
plot(sort(chck1(:)))
figure
plot(sort(chck2(:)))
figure
plot(sort(chck3(:)))