Я понимаю, что есть много вопросов, задающих нечто подобное, но я просто не могу воспроизвести эти решения.

У меня есть следующий фрейм данных:

 vcf<-data.frame(
   v1 = c(10, 15, 30),
   v2 = c(10, 30, 80),
   v3 = c(3,4,7),
   v4 = as.factor(c('4:4:3','.','.')),
   v5 = as.factor(c('4:7:2','4:2:7','3:5:7'))
 )

Чего я хочу добиться, так это двух последних столбцов, разделенных на шесть столбцов:

vcf2<-data.frame(
     v1 = c(10, 15, 30),
     v2 = c(10, 30, 80),
     v3 = c(3,4,7),
     v4 = as.factor(c(4,'.','.')),
     v5 = as.factor(c(4,'.','.')),
     v6 = as.factor(c(3,'.','.')),
     v7 = as.factor(c(4,4,3)),
     v8 = as.factor(c(7,2,5)),
     v9 = as.factor(c(2,7,7))
   )

До сих пор я пробовал решения из других постов, на которые я больше всего надеялся:

within(vcf, vcf$v4<-data.frame(do.call('rbind',strsplit(as.character(vcf$v4), '\\:', fixed=TRUE))))

Но это не приблизилось.

Любая помощь приветствуется, спасибо.

1
FatBerg 21 Авг 2018 в 19:56

3 ответа

Лучший ответ

Вы можете свернуть данные и прочитать их с разделителем :

read.table(text=sub("NA",".:.:.",do.call(paste,c(sep=':',vcf))),sep=":")

  V1 V2 V3 V4 V5 V6 V7 V8 V9
1 10 10  3  4  4  3  4  7  2
2 15 30  4  .  .  .  4  2  7
3 30 80  7  .  .  .  3  5  7

Чтобы преобразовать вышеупомянутое, просто добавьте аргумент na.strings=".", т.е. read.table(text=sub("NA",".:.:.",do.call(paste,c(sep=':',vcf))),sep=":",na.strings = ".")

Вы также можете написать рекурсивный метод, используя separate, так как метод Отдельный работает только в одном столбце за раз:

 library(tidyverse)
 M = function(df,x,i=1,...){
  df = separate(df,x[i],paste0(x[i],1:3),...)
  if (i==length(x)) df else M(df,x,i+1,...)
}
M(vcf,c("v4","v5"))
  v1 v2 v3  v41  v42  v43 v51 v52 v53
1 10 10  3    4    4    3   4   7   2
2 15 30  4 <NA> <NA> <NA>   4   2   7
3 30 80  7 <NA> <NA> <NA>   3   5   7

Чтобы преобразовать тип в числовой:

M(vcf,c("v4","v5"),convert=T)
  v1 v2 v3 v41 v42 v43 v51 v52 v53
1 10 10  3   4   4   3   4   7   2
2 15 30  4  NA  NA  NA   4   2   7
3 30 80  7  NA  NA  NA   3   5   7
3
Onyambu 21 Авг 2018 в 17:31

Вы можете использовать stringr::str_split_fixed:

library(stringr)

vcf_new <- cbind(vcf,str_split_fixed(vcf$v4, ":",3), str_split_fixed(vcf$v5, ":",3))

# drop the split columns
vcf_new <- vcf_new[,-c(4,5)]

# fix the names
names(vcf_new) <- paste0("v", seq(1,9))

# get rid of factors
vcf_new <- apply(vcf_new, 2, as.numeric)

     v1 v2 v3 v4 v5 v6 v7 v8 v9
[1,] 10 10  3  4  4  3  4  7  2
[2,] 15 30  4 NA NA NA  4  2  7
[3,] 30 80  7 NA NA NA  3  5  7

Если вы хотите использовать точки вместо NA s, вам нужно преобразовать их в типы символов, но это сработает: vcf_new[is.na(vcf_new)] <- '.'

1
Mako212 21 Авг 2018 в 17:15

Один из вариантов - использовать data.table::tstrsplit

library(data.table)
setDT(vcf)

vcf[, paste0('v', 4:9) := sapply(.SD, tstrsplit, ':')
    , .SDcols = c('v4', 'v5')]

vcf

#    v1 v2 v3 v4   v5   v6 v7 v8 v9
# 1: 10 10  3  4    4    3  4  7  2
# 2: 15 30  4  . <NA> <NA>  4  2  7
# 3: 30 80  7  . <NA> <NA>  3  5  7
1
IceCreamToucan 21 Авг 2018 в 17:39
51953446