如何通过 R 中的 dplyr 逐行选择 tibble 中的随机元素? 数据

问题描述

我有一些 DNA 数据(等位基因),比如 3 个人,每行代表一个 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 行,这使得上面的代码非常慢。我曾尝试通过 mutate() 包中的 rowwise()acrossdplyr 进行操作,但未成功。

对其他更快的方法有什么建议吗?

解决方法

我们可以将 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    

或者另一种选择是重新整形为“长”格式,按 slice_sample 进行分组,然后重新整形为“宽”

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))

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...