Rcpp-如何计算rowSums正好为1的矩阵

SeG*_*eGa 4 floating-point precision r rcpp

我正在尝试创建随机数rowSums为1 的矩阵。

我已经有一个条件检查它rowSums是否不是1并尝试纠正它。

当我打印出结果时,它看起来是正确的,但是如果我测试所有值是否均为1,它就会给我一些FALSE值。

我该如何纠正?

library(Rcpp)

cppFunction('
NumericMatrix imembrandc(int n, int k) {
  NumericMatrix u( n , k );
  IntegerVector sequ = seq(1,100);
  NumericVector sampled;
  for (int i=0; i < k; ++i) {
    sampled = sample(sequ, n);
    u(_,i) = sampled / sum(sampled);
  }

  if (is_true(any(rowSums(u) != 1))) {
    u(_,1) = u(_,1) + (1 - rowSums(u));
  }

  return(u);
}')
Run Code Online (Sandbox Code Playgroud)

当我打印出rowSums结果的时,它看起来是正确的:

res = imembrandc(n = 10, k = 5)
rowSums(res)
Run Code Online (Sandbox Code Playgroud)

[1] 1 1 1 1 1 1 1 1 1 1 1

但是检查它会带来一些错误:

rowSums(res) == 1
Run Code Online (Sandbox Code Playgroud)

[1]是是是是是是否是是否是

Ral*_*ner 5

生成总和为1的随机数的典型方法n是从生成n - 1[0,1),将0和1加到列表中并取已排序列表的差。当然,这取决于您想要的随机数分布。可以用R表示为

set.seed(42)
v <- diff(sort(c(0, runif(5), 1)))
v
#> [1] 0.28613953 0.35560598 0.18870211 0.08435842 0.02226937 0.06292459
sum(v)
#> [1] 1
Run Code Online (Sandbox Code Playgroud)

reprex软件包(v0.2.1)创建于2019-05-24

在C ++中,

#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::export]]
NumericMatrix imembrandc(int n, int k) {
  NumericMatrix u(n, k);
  for (int i = 0; i < n; ++i) {
    NumericVector row = runif(k - 1);
    row.push_back(0.0);
    row.push_back(1.0);
    u(i, _) = diff(row.sort());
  }
  return u;
}

/*** R
set.seed(42)
res = imembrandc(n = 10, k = 5)
rowSums(res)
rowSums(res) == 1
all.equal(rowSums(res),rep(1, nrow(res)))
*/
Run Code Online (Sandbox Code Playgroud)

请注意,当您生成列,然后尝试更正时,我正在生成行rowSum。输出:

> set.seed(42)

> res = imembrandc(n = 10, k = 5)

> rowSums(res)
 [1] 1 1 1 1 1 1 1 1 1 1

> rowSums(res) == 1
 [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE

> all.equal(rowSums(res),rep(1, nrow(res)))
[1] TRUE
Run Code Online (Sandbox Code Playgroud)

顺便说一句,因为差异真的很小,所以也为您的矩阵all.equal给出TRUE了。但是我发现最好从一开始就避免问题。

  • [此问题](/sf/ask/3878904081/)提供了一个证明。为了说明起见,请考虑带有两个有效数字的十进制浮点数。递增数字的顺序可能是0,.005,.11、1。则实数差异为.005,.105和.89。三位数的.105必须四舍五入为两位数,四舍五入关系到偶数规则为0.1。因此,生成的数字是.005,.10和.89。前两个相加产生0.10(实数总和.105,四舍五入为.10),第三个相加.99。 (3认同)
  • 正如我对那里的回答的评论所指出的那样,这种情况很少见。 (2认同)