如何取 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)))
一个dplyr
和tidyr
的解决方案可以是:
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中,用Map
和transpose
循环mn
和mx
并赋值:=
:
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)
我有一个包含 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)))
一个dplyr
和tidyr
的解决方案可以是:
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中,用Map
和transpose
循环mn
和mx
并赋值:=
:
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)