Разделить строку в каждом столбце на несколько столбцов

У меня есть эта таблица (data1) с четырьмя столбцами

SNP rs6576700 rs17054099 rs7730126
sample1 G-G T-T G-G

Мне нужно разделить столбцы 2–4 на два столбца каждый, чтобы в новом выводе было 7 столбцов. Нравится :

SNP rs6576700 rs6576700 rs17054099 rs17054099 rs7730126 rs7730126
sample1 G G T T C C

С помощью следующей функции я мог бы разделить все столбцы одновременно, но результат - не то, что мне нужно.

split <- function(x){
    x <- as.character(x)
    strsplit(as.character(x), split="-")
  }

data2=apply(data1[,-1], 2, split)

data2
$rs17054099
$rs17054099[[1]]
[1] "T" "T"


$rs7730126
$rs7730126[[1]]
[1] "G" "G"


$rs6576700
$rs6576700[[1]]
[1] "C" "C"

В Stack Overflow я нашел метод для преобразования вывода strsplit в фрейм данных, но числа rs находятся в строках, а не в столбцах (я получил аналогичный результат с другими методами в этом потоке strsplit by row и распределить результаты по столбцам в data.frame)

> n <- max(sapply(data2, length))
> l <- lapply(data2, function(X) c(X, rep(NA, n - length(X))))
> data.frame(t(do.call(cbind, l)))
           t.do.call.cbind..l..
rs17054099                 T, T
rs7730126                  G, G
rs2061700                  C, C

Если я не использую функцию transpose (... (t (do.call ...), на выходе будет список, который я не могу записать в файл.

Я хотел бы иметь решение на R, чтобы сделать его частью конвейера.

Я забыл сказать, что мне нужно применить это к миллиону столбцов.


person Sami    schedule 13.08.2015    source источник
comment
Как вы ожидаете различать столбцы с одинаковыми именами? - намек: Вы не можете. Во-первых, вам нужно определить явные имена столбцов.   -  person N8TRO    schedule 14.08.2015
comment
В конце заголовок использовать не буду. Я хочу сохранить его в первую очередь, чтобы быть уверенным в порядке SNP. Я могу добавить rs17054099.1 и rs17054099.2. Мне нужно создать файл plink ped, поэтому я добавлю информацию о каждом образце (FID, IDD и т. Д.). Спасибо за интерес к моему вопросу. Саами   -  person Sami    schedule 14.08.2015
comment
Хорошо, спасибо за предложение. Если порядок столбцов не меняется, заголовок не имеет значения.   -  person Sami    schedule 14.08.2015
comment
Ответ на этот вопрос уже дан здесь. Data.table также является очень быстрым решением для больших данных.   -  person N8TRO    schedule 14.08.2015
comment
@DavidArenburg Полезно знать. Сам не пробовал. Придется взглянуть на это более внимательно. Я думал о комбо _1 _-_ 2_ .. Конечно, cSplit намного проще.   -  person N8TRO    schedule 14.08.2015
comment
@ N8TRO сработало решение с использованием splitstackshape. Спасибо, Сами   -  person Sami    schedule 14.08.2015
comment
@ N8TRO На самом деле, когда я попробовал еще раз, все заработало. Не знаю, почему это не удалось с первой попытки, хотя вам нужно будет определить имена столбцов каким-то умным способом. Попробую вкратце что-нибудь придумать.   -  person David Arenburg    schedule 14.08.2015


Ответы (2)


Это просто с помощью функции splitstackshape::cSplit. Просто укажите индексы столбцов в параметре splitCols и разделитель в параметре sep, и все готово. Он будет даже пронумеровать ваши новые имена столбцов, чтобы вы могли различать их. Я указал type.convert = FALSE, поэтому T значения не станут TRUE. Направление по умолчанию - wide, поэтому указывать его не нужно.

library(splitstackshape)
cSplit(data1, 2:4, sep = "-", type.convert = FALSE)
#        SNP rs6576700_1 rs6576700_2 rs17054099_1 rs17054099_2 rs7730126_1 rs7730126_2
# 1: sample1           G           G            T            T           G           G

Вот решение по предоставленной ссылке с использованием функции tstrsplit для версии разработки data.table в GH. здесь мы определим индекс, сначала передав в субаренду имена столбцов, а затем пронумеруем их, используя paste. Это немного более громоздкий подход, но его преимущество в том, что он обновит ваши исходные данные на месте вместо того, чтобы создавать копию все данные

library(data.table) ## V1.9.5+
indx <- names(data1)[2:4]
setDT(data1)[, paste0(rep(indx, each = 2), 1:2) := sapply(.SD, tstrsplit, "-"), .SDcols = indx]
data1
#        SNP rs6576700 rs17054099 rs7730126 rs65767001 rs65767002 rs170540991 rs170540992 rs77301261 rs77301262
# 1: sample1       G-G        T-T       G-G          G          G           T           T          G          G
person David Arenburg    schedule 13.08.2015
comment
Привет, спасибо за ответ. Я попробовал cSplit, но ничего не вышло. Я забыл добавить, что у меня есть файл с почти миллионом столбцов, поэтому мне нужен способ не указывать каждый столбец одновременно. Спасибо, - person Sami; 14.08.2015
comment
Что именно не сработало? Можете ли вы предоставить dput своего набора данных? Смотрите мою правку. Вместо имен можно указать индексы столбцов. Так, например, вы можете сделать что-то вроде 2:1e3. - person David Arenburg; 14.08.2015
comment
Должна быть моя вина, я не могу указать несколько столбцов splitGeno1 = cSplit (data1, splitcols = data1 [, 2: 4], seps = -) Ошибка в cSplit (data2, splitcols = data2 [, 2: 4], seps = - ): неиспользуемые аргументы (splitcols = data2 [, 2: 4], seps = -) - person Sami; 14.08.2015
comment
Но вы используете неправильный синтаксис. Почему data2[, 2:4]? Это не то, что я показал. Попробуйте cSplit(data2, splitcols = 2:4, seps = "-", type.convert = FALSE) - person David Arenburg; 14.08.2015
comment
Я ошибался, когда впервые попробовал сам. Теперь я попробовал команду, она сработала отлично, большое спасибо, Сами. - person Sami; 14.08.2015
comment
Я думал, что видел это раньше. Да ладно, может я ошибаюсь. В любом случае (+1) - person akrun; 14.08.2015

Здесь вы хотите использовать применить к строкам вместо столбцов:

df <- rbind(c("SNP", "rs6576700", "rs17054099", "rs7730126"),
c("sample1", "G-G", "T-T", "G-G"),
c("sample2", "C-C", "T-T", "G-C"))

t(apply(df[-1,], 1, function(col) unlist(strsplit(col, "-"))))
#    [,1]      [,2] [,3] [,4] [,5] [,6] [,7]
#[1,] "sample1" "G"  "G"  "T"  "T"  "G"  "G" 
#[2,] "sample2" "C"  "C"  "T"  "T"  "G"  "C"  
person mattdevlin    schedule 13.08.2015
comment
Это метод base, намного медленнее, но все же отличный ответ. - person N8TRO; 14.08.2015