在R中添加带有条件的向量元素

Posted

技术标签:

【中文标题】在R中添加带有条件的向量元素【英文标题】:Adding vector elements with condition in R 【发布时间】:2016-11-18 04:25:21 【问题描述】:

假设我有一个要添加的元素向量:

a <- c(1,2,-7,5)

以下是一些额外的测试用例:

a <- c(1,2,-3,5)
a <- c(1,2,-7,-3,5)

我知道我可以使用sum(a) 来获得结果,但是如果我有一个需要注意的条件怎么办:

current_sum = 0
for(i in 1:length(a))    
 last_sum = current_sum
 current_sum = current_sum + a[i]
 if(current_sum < 0)
 
  current_sum = last_sum
  current_sum = current_sum + (a[i]*-1)
 

在这里,每次总和为负时,我们都会返回上一个总和,并加上使总和变为负数的那个数字的相反数。作为第一个示例的结果输出 15

显然,元素的向量事先是未知的,性能是个问题。是否有任何完全矢量化的方法或更有效的方法来做到这一点(避免循环)?

【问题讨论】:

您如何从您的描述中得到5 as a result?你是说 15 岁吗? @xxfelixxx 现在假设我有这个向量 a @thelatemail 你是对的,我在 5 之前忘记了 1。我已修复它 @Imlerith - 只是sum(a) 适用于这种情况。 我认为它类似于sum(ifelse(cumsum(a) &lt; 0, -a, a)),尽管它并不可靠。 【参考方案1】:

我发现 R/C 接口对于性能很重要的任务非常有用,没有明显的矢量化 R 解决方案并且 C 中的代码很容易编写。试试这个:

require(inline)
.internalSumPositive<-cfunction(sig=c(v="SEXP"), language="C", body="
   double sum=0.0;
   int i,n = length(v);
   double *values = REAL(v);
   SEXP ret = PROTECT(allocVector(REALSXP,1));
   for (i=0;i<n;i++) 
      sum += values[i];
      if (sum<0) sum = sum - 2*values[i];
   
   REAL(ret)[0] = sum;
   UNPROTECT(1);
   return ret;")

sumPositive<-function(v) 
   if (!is.numeric(v)) stop("Argument must be numeric")
   if (length(v)==0) return(numeric(0))
   .internalSumPositive(as.numeric(v))

那你可以试试:

sumPositive(c(1,2,-7,5))
#[1] 15
sumPositive(c(1,2,-3,5))
#[1] 5
sumPositive(c(1,2,-7,-3,5))
#[1] 12

我不会报告基准,因为它甚至不是与其他提议的 R 解决方案的竞争(这可能快 数万 倍)。

【讨论】:

这真的很简洁,并且是如何在 R 中使用 C 的一个非常有凝聚力的示例。作为一个不知道 C 之类的东西的人,我将窃取它作为模板。所以....谢谢! 我喜欢用 C 编写代码的想法。但是为什么在 R 中用 C 编写的循环会比在 R 中的循环获得更好的性能? R 是否将所有内容都翻译成 C ? 我不知道那里发生了什么。我不熟悉这种类型的编码。也许有一天我会的。向你致敬。 @nicola 此代码是否需要任何其他软件包?我收到编译错误 @Imlerith 如果您使用的是 Windows,您可能会错过编译工具。见这里:***.com/questions/3442305/…【参考方案2】:

试试这个

f1 <- function(x) repeatpos<-min(which(cumsum(x)<0))
                    x[pos]<-abs(x[pos])
                    if(all(cumsum(x)>=0))return(sum(x));break
a <- c(1,2,-7,-3,5)
f1(a)
#[1] 12

【讨论】:

对于一个 是的。我知道。但是,仍然返回正确的答案。【参考方案3】:

试试Reduce,它可以用二元函数折叠向量:

a <- c(1,2,-7,5)
Reduce(function(x, y)x + ifelse(x + y < 0, -y, y), a)
## [1] 15

a <- c(1,2,-3,5)
Reduce(function(x, y)x + ifelse(x + y < 0, -y, y), a)
## [1] 5

a <- c(1,2,-7,-3,5)
Reduce(function(x, y)x + ifelse(x + y < 0, -y, y), a)
## [1] 12

【讨论】:

我也喜欢这个答案,不知道reduce函数

以上是关于在R中添加带有条件的向量元素的主要内容,如果未能解决你的问题,请参考以下文章

R语言中向量的定义以及基本操作

R:来自具有 2 个可能条件 (+/-) 的元素向量的所有可能组合

如何在带有向量作为值类型的地图中添加值?

递归向量返回

R:删除向量的最后一个元素

在 C++ 中将(预定义的)原子值添加到向量