【问题标题】:How can I use a vectorised function in R in alternate sequence?如何以交替顺序在 R 中使用矢量化函数?
【发布时间】:2021-07-28 16:47:14
【问题描述】:

假设我有一个带有n 元素的向量x。我想在 x 的每个交替数字上使用任何矢量化函数,比如 cumprod,即每 1、3、5 等,然后在 2、4、6 等上使用另一个。我正在添加一个代表并尝试了代码。该代码有效,但似乎我不必要地走了很长的路,并且可以缩短代码。可以吗?

x <- 5:14

cumprod((x * (seq_along(x) %% 2)) + (seq_along(x)-1) %% 2) * seq_along(x) %% 2 +
  cumprod((x * ((seq_along(x)-1) %% 2)) + seq_along(x) %% 2) * (seq_along(x)-1) %% 2
#>  [1]     5     6    35    48   315   480  3465  5760 45045 80640

这里的cumprod 只是一个示例函数。我可能还必须以交替顺序使用其他功能。

【问题讨论】:

  • 如果 base R 有一个相当于 Clojure 中的 take-nth 的函数,那就太棒了。
  • @BillO'Brien 我不熟悉 Clojure,但是 y &lt;- x[seq(1,n,by=2)] 怎么样?这基本上是 thelatemail 的回答
  • 昨天没有。下面的所有答案都令人惊叹。另一种方法是 Reduce(function(x, y) c(x, y*tail(x, 2)[1]), x, init = 1)[-1] 这意味着您可以随时将 2 更改为任何数字。即 3、4 等

标签: r sequence modulo


【解决方案1】:

在创建matrix 之后,我们可以用rowCumprods 以简洁的方式做到这一点(假设vector 的长度是偶数)

library(matrixStats)
c(rowCumprods(matrix(x, nrow = 2)))

-输出

[1]     5     6    35    48   315   480  3465  5760 45045 80640

如果它可以是奇数长度,那么只需在末尾附加一个NA

 c(rowCumprods(matrix(c(x,  list(NULL, NA)[[1 +
         (length(x) %%2 != 0)]]), nrow = 2)))

-输出

 [1]     5     6    35    48   315   480  3465  5760 45045 80640

或者我们可以使用ave 以通用方式执行此操作(适用于偶数/奇数长度)

ave(x, seq_along(x) %% 2, FUN = cumprod)
 [1]     5     6    35    48   315   480  3465  5760 45045 80640

【讨论】:

  • 亲爱的 Arun,最后一个太棒了。我认为我们可以在那里使用任何功能。接受它。 :)
【解决方案2】:

选择奇数 (c(TRUE, FALSE)) 或偶数 (c(FALSE, TRUE)) 索引。编织两个结果向量 (c(rbind)

c(rbind(cumprod(x[c(TRUE, FALSE)]), cumprod(x[c(FALSE, TRUE)])))
# [1]     5     6    35    48   315   480  3465  5760 45045 80640

要处理奇数向量长度,您需要将结果截断为向量的长度。

x = 1:5

c(rbind(cumprod(x[c(TRUE, FALSE)]), cumprod(x[c(FALSE, TRUE)])))[1:length(x)]
# [1]  1  2  3  8 15

当与偶数索引(少一个元素)相对应的较短结果向量在rbind 步骤中被回收时,将出现警告。

【讨论】:

  • 其实我只想要这样的东西。但是当 x 有奇数个元素时它会起作用吗?
  • 感谢您的建设性意见。
【解决方案3】:

偶数和奇数元素的一个选项可能是:

c(t(apply(matrix(x, 2, sum(seq_along(x) %% 2)), 1, cumprod)))[1:length(x)]

x &lt;- 1:5:

[1]  1  2  3  8 15

x &lt;- 1:6:

[1]  1  2  3  8 15 48

或者一个不太有效的选项,但是,没有任何警告:

y <- Reduce(`c`, sapply(split(setNames(x, seq_along(x)), !seq_along(x) %% 2), cumprod))
y[order(as.numeric(names(y)))]

【讨论】:

  • 减少一个,你可以有Reduce(function(x, y) c(x, y*tail(x, 2)[1]), x, init = 1)[-1]
  • @Onyambu 这是一个不错的选择!我认为您应该将其作为单独的答案发布:)
【解决方案4】:

另一种选择 - 获取一个序列,然后将结果填回:

x <- 5:14

s <- seq(1, length(x), 2)
o <- x
o[s]  <- cumprod(x[s])
o[-s] <- cumprod(x[-s])
o 
# [1]     5     6    35    48   315   480  3465  5760 45045 80640

或者如果你想打代码:

s <- seq(1, length(x), 2)
replace(replace(x, s, cumprod(x[s])), -s, cumprod(x[-s]))
# [1]     5     6    35    48   315   480  3465  5760 45045 80640

【讨论】:

  • 迟到总比不到好。很棒的方法。我喜欢这个,因为我可以在这里应用任何矢量化函数,而无需注意这里的身份。谢谢。不用说已经 +1了
  • 再次感谢您的精彩回答。对不起,我不能两个答案,在那种情况下,我会选择你的。 :)
【解决方案5】:

更新的解决方案

这听起来可能有点冗长,但它适用于奇数和偶数长度以及@Henrik 的自定义向量:

x <- 5:14
lapply(split(x, !(seq_len(length(x)) %% 2)), cumprod) |>
  setNames(c("a", "b")) |>
  list2env(globalenv())

c(a, b)[order(c(seq_along(a)*2 - 1, seq_along(b)*2))]

[1]     5     6    35    48   315   480  3465  5760 45045 80640

使用奇数向量:

x <- 5:13
[1]     5     6    35    48   315   480  3465  5760 45045

x = c(1, 0, 3, 4)

[1] 1 0 3 0

最后是x = c(2, 4, 2, 4):

[1]  2  4  4 16

【讨论】:

  • x%%2 不会分成奇数和偶数 ,而我认为 OP 想要拆分奇数和偶数 索引,例如seq_along(x) %% 2?试穿,例如x = c(2, 4, 2, 4)。干杯
  • 所以也许l = lapply(split(x, seq_along(x)%%2), cumprod); c(l[[2]], l[[1]])[order(c(seq_along(l[[2]]), seq_along(l[[1]])))]
  • 请查看我修改后的终极版:D
  • 太棒了! (希望您不要介意我的 cmets。我只是尝试从其他答案中学习,并且在玩耍时,我有时会偶然发现有可能会发生 tweeking 的事情,这通常是我自己与自己的尝试进行斗争的结果)。干杯
  • 一点也不。事实上,我真的很感谢你花时间批评我的解决方案,在我们通过调整和改变来解决这个问题时引发这些讨论,这是一种很好的学习方式。我仍然是这里经验最少的贡献者,很荣幸能向你们学习。再次感谢您。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-03
  • 1970-01-01
相关资源
最近更新 更多