通过值扩展数值向量

3

在这里,我有一个数字向量,我想要将val_to_add添加到每个元素中,并将那些额外的值附加到sample_vec中,并且最大值不能超过max_val

set.seed(53)

max_val = 50
val_to_add = 2

sample_vec <- sort(sample(1:max_val, 8))
[1]  3  5  6 15 29 30 35 50

例如,我想要将sample_vec中的每个元素加上2。对于第一个元素,它应该是3:(3+2),即3 4 5

重复的值应被丢弃,此时最大值应为50。期望的输出应如下所示:
[1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

这是我的当前代码:

out_vec <- unique(c(sapply(sample_vec, function(x) sequence(val_to_add + 1, from = x))))
out_vec[out_vec <= max_val]

[1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

是否有现有的函数可以在基本R中执行这种操作?

4个回答

4
创建一个从0到给定值的数字序列,使用循环和加号" +"进行相加。
s <- sort(unique(unlist(lapply(0:val_to_add, function(i) sample_vec + i))))
s[ s <= max_val ]
#  [1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

另一个选项是使用sapply而不是lapply(感谢Benson):
s <- unique(sort(sapply(0:val_to_add, function(i) sample_vec + i)))
s[ s <= max_val ]

1
你使用 unlist(lapply()) 而不是 sapply() 有什么原因吗? - benson23
@benson23 不想使用 "c" :sort(unique(c(sapply(... - zx8754
似乎 unique(sort(sapply(0:val_to_add, function(i) sample_vec + i))) 也可以完成这个任务。 - benson23
1
@benson23 这看起来更好,我会编辑答案。 - zx8754
令人惊讶的是,当我运行microbenchmark时,您的lapply版本似乎比sapply变体更有效。 - benson23
显示剩余2条评论

3

sequence 的另一种选项:

s = sequence(rep(val_to_add + 1, length(sample_vec)), sample_vec)
unique(s[s <= max_val])
#  [1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

2
使用mapply和seq创建序列,使用c将其展开为普通向量,取该向量的最小值和max_val,然后取唯一元素。
unique(pmin(c(mapply(seq, sample_vec, sample_vec + val_to_add)), max_val))
## [1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

或者使用sapply:

sample_vec |>
  sapply(seq, length = val_to_add + 1) |>
  c() |>
  pmin(max_val) |>
  unique()
##  [1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

或者外部:
sample_vec |>
  outer(X = seq(0, length = val_to_add + 1), FUN = `+`) |>
  c() |>
  pmin(max_val) |>
  unique()
##  [1]  3  4  5  6  7  8 15 16 17 29 30 31 32 35 36 37 50

注意

max_val <- 50
val_to_add <- 2
sample_vec <- c(3, 5, 6, 15, 29, 30, 35, 50)

2

数据

max_val = 100000
val_to_add = 100
sample_vec <- sort(sample(1:max_val, 1000))

微基准测试

microbenchmark::microbenchmark(
  mael = {
    s = sequence(rep(val_to_add + 1, length(sample_vec)), sample_vec)
    unique(s[s <= max_val])
  },
  zx_lapply = {
    s <- sort(unique(unlist(lapply(0:val_to_add, function(i) sample_vec + i))))
    s[ s <= max_val ]
  }, 
  zx_sapply = {
    s <- unique(sort(sapply(0:val_to_add, function(i) sample_vec + i)))
    s[ s <= max_val ]
  },
  grot_mapply = {
    unique(pmin(c(mapply(seq, sample_vec, sample_vec + val_to_add)), max_val))
  },
  grot_sapply = {
    sample_vec |>
      sapply(seq, length = val_to_add + 1) |>
      c() |>
      pmin(max_val) |>
      unique()
  },
  grot_outer = {
    sample_vec |>
      outer(X = seq(0, length = val_to_add + 1), FUN = `+`) |>
      c() |>
      pmin(max_val) |>
      unique()
  },
  bens = {
    out_vec <- unique(c(sapply(sample_vec, function(x) sequence(val_to_add + 1, from = x))))
    out_vec[out_vec <= max_val]
  },
  check = "equal")
    
Unit: milliseconds
        expr    min      lq      mean  median      uq      max neval  cld
        mael 5.4458 5.47895  5.704599 5.60350 5.90880   6.5259   100  bc 
   zx_lapply 7.0270 7.11250  7.363226 7.29015 7.60025   7.9951   100   cd
   zx_sapply 1.3772 1.42860  1.641764 1.46580 1.84930   2.6103   100 a   
 grot_mapply 5.9197 6.10410  7.600980 6.25440 6.73615 119.2962   100   cd
 grot_sapply 8.2296 8.49875 10.111101 8.64015 9.02135 127.2328   100    d
  grot_outer 2.3588 2.40995  2.673963 2.49130 2.96700   3.3915   100 ab  
        bens 7.8925 8.06655  9.526152 8.16770 8.58205 121.5818   100    d

你有没有想过为什么你的sapplylapply现在更快?我确定与昨天相比,代码是相同的,但昨天我们运行时,lapply版本更快。 - benson23
@benson23 我们确定我们在使用基准测试的相同输入吗?(我无法重新测试基准测试,没有最新的带管道符号的 R。) - zx8754
我认为是这样的。我在这个社区维基中使用“数据”标题下的“设置”,并检查了microbenchmark表达式中变量名是否一致。我刚刚再次运行了它,sapply方法仍然胜出。 - benson23

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接