如何取 2 列生成长度为 N 的序列并添加为 R 中的列?

How to take 2 columns to generate sequence of length N and add as columns in R?

我有一个包含 2 列最小值和最大值的数据框。我想为每一行生成序列 b/w 这些数字。

df <- data.table("ID"=c("A","B","C"),
                 "mn" = c(1,2,3),
                 "mx" = c(10,5,10)
                 )
> df
    ID mn mx
 1:  A  1  10
 2:  B  2  5
 3:  C  3  10

我想获取这两列并为每一行生成 4 个序列号

>df
 ID | mn | mx | S1 | s2    | S3 |  s4
  A    1   10    1     4     7      10
  B    2   5     2     3     4      5
  C    3   10    3     5.33  7.66   10 

我可以遍历行并使用 seq(mn, mx, length=N) 但我想在 100 万行上应用此操作,请提出有效的解决方案。

使用 apply 的一种方式:

cbind(df, t(apply(df, 1, function(x) x[1]:x[2])))

#   mn mx V1 V2 V3 V4
#1:  1  4  1  2  3  4
#2:  2  5  2  3  4  5
#3:  3  6  3  4  5  6

mapply

cbind(df, t(mapply(`:`, df$mn, df$mx)))

一个dplyrtidyr的解决方案可以是:

df %>%
 rowwise() %>%
 mutate(cols = list(mn:mx)) %>%
 unnest_wider(cols) %>%
 rename_at(vars(-mn, -mx), ~ paste0("s", 1:length(.)))

     mn    mx    s1    s2    s3    s4
  <dbl> <dbl> <int> <int> <int> <int>
1     1     4     1     2     3     4
2     2     5     2     3     4     5
3     3     6     3     4     5     6

或者:

df %>%
 mutate(cols = Map(`:`, mn, mx)) %>%
 unnest_wider(cols) %>%
 rename_at(vars(-mn, -mx), ~ paste0("s", 1:length(.)))

另一个使用 data.table 的矢量化选项,无需逐行查看应该会更快:

df[, paste0("s", 1L:4L) := {
        d <- (mx - mn) / 3
        .(mn, mn + d, mn + 2*d, mx)
    }]

概括地说,thelatemail 建议:

N <- 4L
df[, paste0("s", seq(N)) := transpose(Map(`+`, mn, 
    lapply((mx - mn) / (N-1), `*`, seq(0, N-1))
))]

或等价地但更长,但我认为它会更快:

N <- 4L #assuming N >= 2
d <- df[, (mx - mn) / (N - 1)]
init <- df[["mn"]]
for (n in 1L:N) {
    set(df, j=paste0("s", n), value=init + (n-1) * d)
}

data.table中,用Maptranspose循环mnmx并赋值:=:

df[, paste0("s", seq(4)) := transpose(Map(seq, mn, mx, length.out=4))]
df
#   ID mn mx s1       s2       s3 s4
#1:  A  1 10  1 4.000000 7.000000 10
#2:  B  2  5  2 3.000000 4.000000  5
#3:  C  3 10  3 5.333333 7.666667 10

我们可以使用map2

library(dplyr)
library(purrr)
library(tidyr)
df %>%
     mutate(cols = map2(mn, mx, `:`)) %>%
     unnest_wider(cols)