在 R 中添加带条件的向量元素
Adding vector elements with condition in R
假设我有一个要添加的元素向量:
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
显然,元素的向量是事先不知道的,性能是个问题。一般情况下,是否有任何完全矢量化的方法或更有效的方法(避免循环)?
试试这个
f1 <- function(x) repeat{pos<-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
试试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
我发现 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 解决方案的竞争(这可以快 数万 倍)。
假设我有一个要添加的元素向量:
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
显然,元素的向量是事先不知道的,性能是个问题。一般情况下,是否有任何完全矢量化的方法或更有效的方法(避免循环)?
试试这个
f1 <- function(x) repeat{pos<-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
试试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
我发现 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 解决方案的竞争(这可以快 数万 倍)。