Разделить строки символов в столбце и создать новые строки - PullRequest
0 голосов
/ 23 марта 2019

У меня есть датафрейм с 2 столбцами. Столбец 2 содержит гены, разделенные ;, такие как A;B, A;B;C;D. Количество этих генов может варьироваться от 2 до многих. Я хочу разбить гены на пары по 2 и поместить их в новые ряды. Важно отметить, что мне нужны все возможные комбинации этих генов (изначально вместе) для создания новых строк. Конечно, если для начала есть только 2 гена, то ничего не нужно делать. Кроме того, я хотел бы сохранить значения (текст) в столбце 1 для вновь создаваемых строк. Я ничего не пробовал, потому что понятия не имею, как подойти к проблеме. Пример ввода и желаемый результат приведены ниже. Любая помощь или предложения о том, как справиться с этим, будут высоко оценены. У меня есть некоторый (ограниченный) опыт работы с Tidyverse. Спасибо за ваше время.

input = data.frame(col1 = c("example1", "example2"), col2 = c("A;B", "A;B;C;D"))

output = data.frame(col1 = c("example1", 
                             "example2", 
                             "example2", 
                             "example2", 
                             "example2", 
                             "example2"), col2 = c("A;B",
                                                   "A;B", 
                                                   "A;C",
                                                   "A;D", 
                                                   "B;C", 
                                                   "B;D", 
                                                   "C;D"))

Ответы [ 3 ]

2 голосов
/ 23 марта 2019

Вот подход tidyverse:

library(tidyverse)

input %>%
  filter(grepl(";", col2)) %>%
  mutate(x = str_split(col2, ";") %>% map(~combn(., 2, paste0, collapse = ";"))) %>%
  unnest() %>%
  select(-col2)

# A tibble: 7 x 2
# Groups:   col1 [2]
  col1     x    
  <fct>    <chr>
1 example1 A;B  
2 example2 A;B  
3 example2 A;C  
4 example2 A;D  
5 example2 B;C  
6 example2 B;D  
7 example2 C;D 
2 голосов
/ 23 марта 2019

Давайте сначала создадим вспомогательную функцию (из вашего input у меня получилось stringsAsFactors = FALSE; если это не вариант, просто добавьте as.character() к вспомогательной функции):

char_comb <- function(aString) {

   str_split(aString, pattern = ';') %>% 
      unlist() %>% 
      combn(2, paste0, collapse = ";")

}

NB - продемонстрировать вспомогательную функцию с минимальным примером запуска: char_comb(aString = "A;B;C;D")

А потом:

map2(.x = input[['col1']], 
     .y = input[['col2']], .f = function(idx, cell) {


    if(nchar(cell) > 3) {

        res <- char_comb(cell)
        tibble(col1 = idx, col2 = res)

    } else {

        tibble(col1 = idx, col2 = cell)
        }
    }) %>% 
    bind_rows()

Result:
  col1     col2 
  <chr>    <chr>
1 example1 A;B  
2 example2 A;B  
3 example2 A;C  
4 example2 A;D  
5 example2 B;C  
6 example2 B;D  
7 example2 C;D  

p.s. мое решение включает в себя также "A; B". Это будет тривиально исключить их в случае.

РЕДАКТИРОВАТЬ: добавление тестов.

Из комментариев видно, что @ ip2018 обеспокоен временем исполнения. Оборачивание обоих решений в функцию ...

microbenchmark("pasqui" = res_fn(col1 = input[['col1']], col2 = input[['col2']]), 
               "H 1" = h1_res()
               )

Результаты тестов:

Unit: milliseconds
   expr      min       lq      mean    median        uq       max neval cld
 pasqui 1.137418 1.198085  1.403278  1.297016  1.611183  2.310684   100  a 
    H 1 9.140376 9.811799 12.126555 10.730754 13.036842 45.186844   100   b
0 голосов
/ 23 марта 2019

Вот еще одно решение, которое вычисляет все внутри цикла for. Не уверен, как оно будет сравниваться с ответом pasqui с точки зрения времени обработки.

col1<-c()
col2<-c()

for(i in 1:nrow(input)){
 name<-input$col1[i]
 splt<-unlist(strsplit(input$col2[i],";"))

 #Generate Matrix of Pair-Wise Combinations
 combs<-sapply(splt, function(x) sapply(splt, function(y) paste(x,y, sep=";") ))

 #Limit to Unique Combinations
 uni_combinations<-combs[lower.tri(combs)] 

 #Save vector of names
 n<-length(uni_combinations)
 col1<-c(col1,rep(name,n))

 # Save vector of gene combinations
 col2<-c(col2, uni_combinations)
}

# Put results in data.frame()
result<-data.frame(col1=col1, col2 = col2)
result
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...