我们希望将数组中的所有值设置为负值。
我尝试了很多东西,但还没有找到可行的解决方案。 我想到了一个带有条件的for循环,但这似乎不起作用。
#pred_precipitation is our array
pred_precipitation <-rnorm(25,2,4)
for (i in nrow(pred_precipitation))
{
if (pred_precipitation[i]<0) {pred_precipitation[i] = 0}
else{pred_precipitation[i] = pred_precipitation[i]}
}
答案 0 :(得分:44)
感谢可重复的例子。这是非常基本的R东西。您可以分配给矢量的选定元素(注意数组有尺寸,你给出的是矢量而不是数组):
> pred_precipitation[pred_precipitation<0] <- 0
> pred_precipitation
[1] 1.2091281 0.0000000 7.7665555 0.0000000 0.0000000 0.0000000 0.5151504 0.0000000 1.8281251
[10] 0.5098688 2.8370263 0.4895606 1.5152191 4.1740177 7.1527742 2.8992215 4.5322934 6.7180530
[19] 0.0000000 1.1914052 3.6152333 0.0000000 0.3778717 0.0000000 1.4940469
基准战争
@James找到了一种更快的方法并将其留在评论中。我支持他,只是因为我知道他的胜利将是短暂的。
首先,我尝试编译,但这似乎没有帮助任何人:
p <- rnorm(10000)
gsk3 <- function(x) { x[x<0] <- 0; x }
jmsigner <- function(x) ifelse(x<0, 0, x)
joshua <- function(x) pmin(x,0)
james <- function(x) (abs(x)+x)/2
library(compiler)
gsk3.c <- cmpfun(gsk3)
jmsigner.c <- cmpfun(jmsigner)
joshua.c <- cmpfun(joshua)
james.c <- cmpfun(james)
microbenchmark(joshua(p),joshua.c(p),gsk3(p),gsk3.c(p),jmsigner(p),james(p),jmsigner.c(p),james.c(p))
expr min lq median uq max
1 gsk3.c(p) 251.782 255.0515 266.8685 269.5205 457.998
2 gsk3(p) 256.262 261.6105 270.7340 281.3560 2940.486
3 james.c(p) 38.418 41.3770 43.3020 45.6160 132.342
4 james(p) 38.934 42.1965 43.5700 47.2085 4524.303
5 jmsigner.c(p) 2047.739 2145.9915 2198.6170 2291.8475 4879.418
6 jmsigner(p) 2047.502 2169.9555 2258.6225 2405.0730 5064.334
7 joshua.c(p) 237.008 244.3570 251.7375 265.2545 376.684
8 joshua(p) 237.545 244.8635 255.1690 271.9910 430.566
但是等等!德克写了这个Rcpp的东西。一个完整的C ++无能读取他的JSS论文,适应他的例子,并编写它们的最快功能吗?亲爱的听众,请继续关注。
library(inline)
cpp_if_src <- '
Rcpp::NumericVector xa(a);
int n_xa = xa.size();
for(int i=0; i < n_xa; i++) {
if(xa[i]<0) xa[i] = 0;
}
return xa;
'
cpp_if <- cxxfunction(signature(a="numeric"), cpp_if_src, plugin="Rcpp")
microbenchmark(joshua(p),joshua.c(p),gsk3(p),gsk3.c(p),jmsigner(p),james(p),jmsigner.c(p),james.c(p), cpp_if(p))
expr min lq median uq max
1 cpp_if(p) 8.233 10.4865 11.6000 12.4090 69.512
2 gsk3(p) 170.572 172.7975 175.0515 182.4035 2515.870
3 james(p) 37.074 39.6955 40.5720 42.1965 2396.758
4 jmsigner(p) 1110.313 1118.9445 1133.4725 1164.2305 65942.680
5 joshua(p) 237.135 240.1655 243.3990 250.3660 2597.429
这是肯定的,船长。
即使您未分配输入p
,也会修改输入cpp_ifclone_src <- '
Rcpp::NumericVector xa(Rcpp::clone(a));
int n_xa = xa.size();
for(int i=0; i < n_xa; i++) {
if(xa[i]<0) xa[i] = 0;
}
return xa;
'
cpp_ifclone <- cxxfunction(signature(a="numeric"), cpp_ifclone_src, plugin="Rcpp")
。如果你想避免这种行为,你必须克隆:
{{1}}
不幸的是,它扼杀了速度优势。
答案 1 :(得分:12)
我会使用pmax
因为ifelse
有时会有点慢,而子集替换会创建一个额外的向量(这可能是大数据集的问题)。
set.seed(21)
pred_precipitation <- rnorm(25,2,4)
p <- pmax(pred_precipitation,0)
子集替换是迄今为止最快的:
library(rbenchmark)
gsk3 <- function(x) { x[x<0] <- 0; x }
jmsigner <- function(x) ifelse(x<0, 0, x)
joshua <- function(x) pmin(x,0)
benchmark(joshua(p), gsk3(p), jmsigner(p), replications=10000, order="relative")
test replications elapsed relative user.self sys.self
2 gsk3(p) 10000 0.215 1.000000 0.216 0.000
1 joshua(p) 10000 0.444 2.065116 0.416 0.016
3 jmsigner(p) 10000 0.656 3.051163 0.652 0.000
答案 2 :(得分:7)
或者您也可以使用ifelse
:
ifelse(pred_precipitation < 0, 0, pred_precipitation)
答案 3 :(得分:3)
如果主要对象是小标题或数据框,则也可以使用整齐的包。与阿里·弗里德曼(Ari B. Friedman)提出的替代方案相比,该替代方案可以“即时”写入并结合其他突变。
使用dplyr和%>%
管道的示例如下所示:
df %>% mutate(varA = if_else(varA < 0, 0, varA))
您可以在mutate()
语句中添加其他突变(即新变量)。我在这种类型的编码中看到的一个优点是,您不会冒跳过或重新执行单个转换步骤的风险,因为它们全部归为一个语句。
例如,通过在RStudio中添加%>% View()
,您已经可以预览结果。但是,结果尚未存储在任何地方(“即时”)。这样,您可以在更改代码时保持名称空间/环境的整洁。