Разделение текста в столбцах фрейма данных на основе части шаблона
Используя R I, я пытаюсь разбить текст в столбце с указанным разделителем на два новых столбца. Пример кадра данных будет ниже:
repdf <- data.frame(a=c("abc(100)","def(95)","ghi(100)","j_(klm)(100)"),b=c("abc(100)","def(95)","ghi(100)","j_(klm)(100)"))
Проще говоря, я хочу разбить на каждую открытую скобку "(", но только если за ней следует число, но без потери числа. Т.е. желаемый результат должен выглядеть так:
a1 a2 b1 b2
abc 100) abc 100)
def 95) def 95)
ghi 100) ghi 100)
j_(klm) 100) j_(klm) 100)
Я пытался работать сsplitstackshape::cSplit
а также stringr::str_split_fixed
но безрезультатно.cSplit(repdf,c("a","b"),"(")
Разбивается на каждый "("
a_1 a_2 a_3 b_1 b_2 b_3
1: abc 100) NA abc 100) NA
2: def 95) NA def 95) NA
3: ghi 100) NA ghi 100) NA
4: j_ klm) 100) j_ klm) 100)
cSplit(repdf,c("a","b"),"\\(([0-9])",fixed=FALSE)
удаляет первый номер, если можно было бы использовать \1
добавить захват во вторую группу, что было бы неплохо, но, к сожалению, это не так.
a_1 a_2 b_1 b_2
1: abc 00) abc 00)
2: def 5) def 5)
3: ghi 00) ghi 00)
4: j_(klm) 00) j_(klm) 00)
as.data.frame(lapply(repdf,function(x)str_split_fixed(x,"\\(",n=2)))
позволяет мне действительно разбивать только на 2 столбца, но, конечно, принимает только первый матч:
a.1 a.2 b.1 b.2
1 abc 100) abc 100)
2 def 95) def 95)
3 ghi 100) ghi 100)
4 j_ klm)(100) j_ klm)(100)
2 ответа
Вот где заглядывание вперед пригодится... По сути, мы ищем (
за которым следует цифра \\d
но взгляд в будущее не использует цифру для разделения.
do.call(cbind, lapply(repdf, function(x){
do.call(rbind, strsplit(as.character(x), "\\((?=\\d)", perl = TRUE))
}))
# [,1] [,2] [,3] [,4]
# [1,] "abc" "100)" "abc" "100)"
# [2,] "def" "95)" "def" "95)"
# [3,] "ghi" "100)" "ghi" "100)"
# [4,] "j_(klm)" "100)" "j_(klm)" "100)"
Вдохновленный предложениями @Konrad, я нашел следующее для работы tidyr::extract
, но мне нужно было использовать его стандартную ознакомительную версию tidyr::extract_
:
do.call(cbind, lapply(seq_along(repdf),
function(df, i){
tidyr::extract_(data=df[i], col = names(df[i]),
into=c(paste0("tax",i),paste0("prob",i)),
regex = "(.*)\\((?=\\d)(.*)",perl=TRUE)}, df=repdf))
Преимущество здесь в том, что вы можете дать разделенным столбцам предварительно определенные имена (например, здесь tax
а также prob
), который может быть полезен для обработки данных в нисходящем направлении. С другой стороны, интересная вещь в принятом ответе состоит в том, что, когда число колонн, на которые разбиваются данные, заранее неизвестно (или зависит от переменной столбца исходного кадра), оно все равно будет работать как символ.