#r #string #split #data.table
#r #строка #разделить #data.table
Вопрос:
data.table::tstrsplit имеет полезный аргумент type.convert. Но он выдает ошибку, когда после разделения каждая строка преобразуется в другой класс, см. Пример:
library(data.table)
x <- fread("CHROM POS REF ALT TYPE AF
chr1 1 A T MISSENSE 0.23
chr2 1 A T,G MISSENSE 0.17,0.09")
В столбце ALT у нас есть «T» и «T, G», поэтому первая строка преобразуется в логическое «TRUE», а вторая строка разбивается и преобразуется в символы «T» и «G». В результате мы получаем ошибку ниже:
x[, lapply(.SD, function(x) unlist(tstrsplit(x, ",", fixed = TRUE, type.convert = TRUE))),
by = .(CHROM, POS, REF, TYPE)]
# Error in `[.data.table`(x, , lapply(.SD, function(x) unlist(tstrsplit(x, :
# Column 1 of result for group 2 is type 'character' but expecting type
# 'logical'. Column types must be consistent for each group.
Мы могли бы избежать автоматического преобразования и преобразовать позже вручную, все отлично:
x[, lapply(.SD, function(x) unlist(tstrsplit(x, ",", fixed = TRUE))),
by = .(CHROM, POS, REF, TYPE)][, .(CHROM, POS, REF, ALT, TYPE, AF = as.numeric(AF))]
# CHROM POS REF ALT TYPE AF
# 1: chr1 1 A T MISSENSE 0.23
# 2: chr2 1 A T MISSENSE 0.17
# 3: chr2 1 A G MISSENSE 0.09
Но у tidyr::separate нет этой проблемы:
tidyr::separate_rows(x, ALT, AF, convert = TRUE)
# # A tibble: 3 x 6
# CHROM POS REF ALT TYPE AF
# <chr> <int> <chr> <chr> <chr> <dbl>
# 1 chr1 1 A T MISSENSE 0.23
# 2 chr2 1 A T MISSENSE 0.17
# 3 chr2 1 A G MISSENSE 0.09
Вопрос: есть ли лучший способ data.table для достижения этой цели? Мне нужно использовать преобразование типов, поскольку столбец AF должен быть числовым. Я бы хотел разделить столбец с разделителями одновременно. В реальных данных может быть более 2 столбцов с разделителями.
Комментарии:
1. @akrun хороший, но все же хотелось бы избежать этого «дополнительного» шага. separate_rows выглядит намного аккуратнее. Если ничего другого, это лучшее на данный момент, спасибо.
Ответ №1:
Это можно сделать проще с помощью cSplit
library(splitstackshape)
cSplit(x, c("ALT", "AF"), ",", "long")
# CHROM POS REF ALT TYPE AF
#1: chr1 1 A T MISSENSE 0.23
#2: chr2 1 A T MISSENSE 0.17
#3: chr2 1 A G MISSENSE 0.09
Что касается data.table
опции, другой способ — добавить пробел
x[, lapply(.SD, function(x)
trimws(unlist(tstrsplit(gsub("([TF]) ", " \1", x), ",",
fixed = TRUE, type.convert = TRUE)))),
by = .(CHROM, POS, REF, TYPE)]
# CHROM POS REF TYPE ALT AF
#1: chr1 1 A MISSENSE T 0.23
#2: chr2 1 A MISSENSE T 0.17
#3: chr2 1 A MISSENSE G 0.09
Комментарии:
1. Еще один отличный вариант с trimws, но все же я надеялся на более прямой способ сделать это.
Ответ №2:
Поскольку проблема заключается в том, что type.convert
T
первая группа идентифицируется как логическая TRUE
, вы могли бы явно использовать type.convert
результирующую data.table
where у вас также G
есть в переменной, так что у вас нет этой проблемы:
x[, lapply(.SD, function(x) unlist(str_split(x,","))),
by = .(CHROM, POS, REF, TYPE)] %>%
type.convert(.,as.is = T)
CHROM POS REF TYPE ALT AF
1: chr1 1 A MISSENSE T 0.23
2: chr2 1 A MISSENSE T 0.17
3: chr2 1 A MISSENSE G 0.09
$CHROM
[1] "character"
$POS
[1] "integer"
$REF
[1] "character"
$TYPE
[1] "character"
$ALT
[1] "character"
$AF
[1] "numeric"
Комментарии:
1. извините, я не видел вашего комментария (его здесь больше нет?)
2. все в порядке. Я удалил комментарии. Но потом я подумал, что не стоит включать это в ответы, поскольку OP выглядел более прямым. Хорошо, что вы пришли к тому же решению. Я просто сказал. Вы можете сохранить это решение
3. Вы намного быстрее и лучше меня (и другого), приятно, что вы добровольно подумали о том, чтобы не включать все ответы в свой 🙂
4. Хорошо, что у вас есть такая опция из вашего ответа. Я думаю, что нет прямого способа,
tstrsplit
если мы не внесем некоторые изменения в части ‘T’, ‘F’5. Да, это было предложено akrun уже в комментариях, я бы хотел избежать этого шага.