Разделение текста в столбцах фрейма данных на основе части шаблона

Используя 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), который может быть полезен для обработки данных в нисходящем направлении. С другой стороны, интересная вещь в принятом ответе состоит в том, что, когда число колонн, на которые разбиваются данные, заранее неизвестно (или зависит от переменной столбца исходного кадра), оно все равно будет работать как символ.

Другие вопросы по тегам