如何通过 R 中的 dplyr 逐行 select tibble 中的随机元素?
How to rowwise select random elements in a tibble via dplyr in R?
我有一些 3 个人的 DNA 数据(等位基因),每行代表一个 SNP。为了获得一些可共享的测试数据,我想按行将数据随机抽样到一个新的 tibble 中,以获得一些不代表真人的假 DNA 数据。
例如,我的初始标题 data
可能如下所示:
person_1, person_2, person_3
AA, AG, GG (i.e. data from person_1 person_2 person_3)
AC, CC, AC (i.e. data from person_1 person_2 person_3)
.. .. ..
我希望结果是这样的:
random_1, random_2, random_3
GG, AA, AG (i.e. randomly assigned to person_3, person_1, person_2)
CC, AC, AC (i.e. randomly assigned to person_2, person_3, person_1)
...
我已经可以使用以下代码执行此操作:
data %>%
split(f = 1:nrow(.)) %>%
purrr::map_dfr(~ .x[,sample(1:ncol(.x),ncol(.x))] %>%
rename( setNames(object = names(.),
nm = paste0("test_",sprintf("%02d", 1:length(.))))
)
)
但是,我的挑战是我的 tibble 有超过 700.000 行,这使得上面的代码非常慢。我曾尝试通过 dplyr
包中的 mutate()
、rowwise()
和 across
进行操作,但没有成功。
对其他更快的方法有什么建议吗?
我们可以将 pmap
(来自 purrr
)与 sample
一起使用。
library(dplyr)
library(purrr)
library(stringr)
df1 %>%
pmap_dfr(~ sample(c(...))) %>%
rename_all(~ str_c('random_', seq_along(.)))
-输出
# A tibble: 2 x 3
# random_1 random_2 random_3
# <chr> <chr> <chr>
#1 AG AA GG
#2 CC AC AC
或者另一种选择是重塑为 'long' 格式,按 slice_sample
进行分组,然后重塑回 'wide'
library(tidyr)
df1 %>%
mutate(rn = row_number()) %>%
pivot_longer(cols = -rn) %>%
group_by(rn) %>%
slice_sample(prop = 1) %>%
mutate(name = str_c('random_', row_number())) %>%
ungroup %>%
pivot_wider(names_from = name, values_from = value)
# A tibble: 2 x 4
# rn random_1 random_2 random_3
# <int> <chr> <chr> <chr>
#1 1 AG GG AA
#2 2 CC AC AC
有一个选项可以使用 rowwise
,但是,假设行数为 700000
,效率会降低
df1 %>%
rowwise %>%
transmute(col1 = list(sample(c_across(everything())))) %>%
unnest_wider(c(col1), names_repair = ~ str_c('random_', seq_along(.)))
# A tibble: 2 x 3
# random_1 random_2 random_3
# <chr> <chr> <chr>
#1 AG AA GG
#2 CC AC AC
在 base R
中,可以使用 apply
来完成
out <- as.data.frame(t(apply(df1, 1, sample)))
names(out) <- paste0('random_', seq_along(out))
数据
df1 <- structure(list(person_1 = c("AA", "AC"), person_2 = c("AG", "CC"
), person_3 = c("GG", "AC")), class = "data.frame", row.names = c(NA,
-2L))
我有一些 3 个人的 DNA 数据(等位基因),每行代表一个 SNP。为了获得一些可共享的测试数据,我想按行将数据随机抽样到一个新的 tibble 中,以获得一些不代表真人的假 DNA 数据。
例如,我的初始标题 data
可能如下所示:
person_1, person_2, person_3
AA, AG, GG (i.e. data from person_1 person_2 person_3)
AC, CC, AC (i.e. data from person_1 person_2 person_3)
.. .. ..
我希望结果是这样的:
random_1, random_2, random_3
GG, AA, AG (i.e. randomly assigned to person_3, person_1, person_2)
CC, AC, AC (i.e. randomly assigned to person_2, person_3, person_1)
...
我已经可以使用以下代码执行此操作:
data %>%
split(f = 1:nrow(.)) %>%
purrr::map_dfr(~ .x[,sample(1:ncol(.x),ncol(.x))] %>%
rename( setNames(object = names(.),
nm = paste0("test_",sprintf("%02d", 1:length(.))))
)
)
但是,我的挑战是我的 tibble 有超过 700.000 行,这使得上面的代码非常慢。我曾尝试通过 dplyr
包中的 mutate()
、rowwise()
和 across
进行操作,但没有成功。
对其他更快的方法有什么建议吗?
我们可以将 pmap
(来自 purrr
)与 sample
一起使用。
library(dplyr)
library(purrr)
library(stringr)
df1 %>%
pmap_dfr(~ sample(c(...))) %>%
rename_all(~ str_c('random_', seq_along(.)))
-输出
# A tibble: 2 x 3
# random_1 random_2 random_3
# <chr> <chr> <chr>
#1 AG AA GG
#2 CC AC AC
或者另一种选择是重塑为 'long' 格式,按 slice_sample
进行分组,然后重塑回 'wide'
library(tidyr)
df1 %>%
mutate(rn = row_number()) %>%
pivot_longer(cols = -rn) %>%
group_by(rn) %>%
slice_sample(prop = 1) %>%
mutate(name = str_c('random_', row_number())) %>%
ungroup %>%
pivot_wider(names_from = name, values_from = value)
# A tibble: 2 x 4
# rn random_1 random_2 random_3
# <int> <chr> <chr> <chr>
#1 1 AG GG AA
#2 2 CC AC AC
有一个选项可以使用 rowwise
,但是,假设行数为 700000
df1 %>%
rowwise %>%
transmute(col1 = list(sample(c_across(everything())))) %>%
unnest_wider(c(col1), names_repair = ~ str_c('random_', seq_along(.)))
# A tibble: 2 x 3
# random_1 random_2 random_3
# <chr> <chr> <chr>
#1 AG AA GG
#2 CC AC AC
在 base R
中,可以使用 apply
out <- as.data.frame(t(apply(df1, 1, sample)))
names(out) <- paste0('random_', seq_along(out))
数据
df1 <- structure(list(person_1 = c("AA", "AC"), person_2 = c("AG", "CC"
), person_3 = c("GG", "AC")), class = "data.frame", row.names = c(NA,
-2L))