R: Подсчитать все комбинации в списке строк (определенный порядок) - PullRequest
0 голосов
/ 21 мая 2018

Я пытаюсь сосчитать все последовательности в большом списке символов, разделенных символом «>», но только те комбинации, которые находятся непосредственно рядом друг с другом.

например, учитывая вектор символов:

[1]Social>PaidSearch>PaidSearch>PaidSearch>PaidSearch>PaidSearch>PaidSearch>PaidSearch>PaidSearch>PaidSearch>PaidSearch>OrganicSearch>OrganicSearch>OrganicSearch
[2]Referral>Referral>Referral

Я могу запустить следующую строку, чтобы получить все комбинации с 2 символами:

split_fn <- sapply(p , strsplit , split = ">", perl=TRUE)

split_fn <- sapply(split_fn, function(x) paste(head(x,-1) , tail(x,-1) , sep = ">") )

Возвращает:

[[1]]

 [1] "Social>PaidSearch"           "PaidSearch>PaidSearch"       "PaidSearch>PaidSearch"       "PaidSearch>PaidSearch"       "PaidSearch>PaidSearch"      
 [6] "PaidSearch>PaidSearch"       "PaidSearch>PaidSearch"       "PaidSearch>PaidSearch"       "PaidSearch>PaidSearch"       "PaidSearch>PaidSearch"      
[11] "PaidSearch>OrganicSearch"    "OrganicSearch>OrganicSearch" "OrganicSearch>OrganicSearch"

[[2]]

[1] "Referral>Referral" "Referral>Referral"

Какая из двух возможных последовательностей символов в моих данных (разделяется по порядку)

Я знаю, что хочу иметь все возможные результаты по 3 символа.

например

"Social>PaidSearch>PaidSearch" "PaidSearch>PaidSearch>PaidSearch"..."Referral>Referral>Referral"

Пытался использовать

unlist(lapply(strsplit(p, split = ">"), function(i) combn(sort(i), 3, paste, collapse='>')))

Но он возвращает все комбинации, включая те, которые не следуют непосредственно.

Я также не хочу, чтобы он возвращал комбинации последнего значения в первой строке с первым значением в строке 2 и т. Д.

Ответы [ 3 ]

0 голосов
/ 21 мая 2018

Давайте начнем с создания некоторых данных:

set.seed(1)

data <- lapply(1:3, function(i) sample(LETTERS[1:3], rpois(1, 6), re = T))
data <- sapply(data, paste, collapse = ">")

data
#> [1] "B>B>C>A"           "C>B>B>A>A>A>C>B>C" "C>C>B>C>C>A"

Учитывая проблему, имеет смысл рассматривать эти данные как список векторов, которые мы получаем после разделения элементов по разделителю >:

strsplit(data, ">")
#> [[1]]
#> [1] "B" "B" "C" "A"
#> 
#> [[2]]
#> [1] "C" "B" "B" "A" "A" "A" "C" "B" "C"
#> 
#> [[3]]
#> [1] "C" "C" "B" "C" "C" "A"

Теперь суть проблемы заключается в том, чтобы найти все последовательные последовательности заданной длины из одного вектора.Как только мы сможем это сделать, просто применить к списку данных, которые у нас есть;преобразование обратно в формат с разделителями также будет простым.

Учитывая эту цель, мы можем затем создать функцию для извлечения последовательностей;здесь мы просто зацикливаемся на каждом элементе и извлекаем все последовательности заданной длины в список:

seqs <- function(x, length = 2) {
  if (length(x) < length)
    return(NULL)
  k <- length - 1
  lapply(seq_len(length(x) - k), function(i) x[i:(i + k)])
}

Теперь мы можем просто применить функцию к данным после разделения символов с разделителями на векторы, чтобы получить результат.Нам также понадобится дополнительный sapply с paste для преобразования данных обратно в формат с разделителями, с которого мы начали:

lapply(strsplit(data, ">"), function(x) {
  sapply(seqs(x, 3), paste, collapse = ">")
})
#> [[1]]
#> [1] "B>B>C" "B>C>A"
#> 
#> [[2]]
#> [1] "C>B>B" "B>B>A" "B>A>A" "A>A>A" "A>A>C" "A>C>B" "C>B>C"
#> 
#> [[3]]
#> [1] "C>C>B" "C>B>C" "B>C>C" "C>C>A"

Далее, чтобы получить последовательности нескольких длин одновременно, мы можем добавить еще один слой итерации:

lapply(strsplit(data, ">"), function(x) {
  unlist(sapply(c(2, 3), function(n) {
    sapply(seqs(x, n), paste, collapse = ">")
  }))
})
#> [[1]]
#> [1] "B>B"   "B>C"   "C>A"   "B>B>C" "B>C>A"
#> 
#> [[2]]
#>  [1] "C>B"   "B>B"   "B>A"   "A>A"   "A>A"   "A>C"   "C>B"   "B>C"  
#>  [9] "C>B>B" "B>B>A" "B>A>A" "A>A>A" "A>A>C" "A>C>B" "C>B>C"
#> 
#> [[3]]
#> [1] "C>C"   "C>B"   "B>C"   "C>C"   "C>A"   "C>C>B" "C>B>C" "B>C>C" "C>C>A"

Создан в 2018-05-21 с помощью пакета Представить (v0.2.0).

0 голосов
/ 21 мая 2018

Вы можете также адаптировать команду paste во второй sapply к:

paste(head(x,-2), head(tail(x,-1),-1), tail(x,-2) , sep = ">")

Теперь ваш полный код должен выглядеть следующим образом:

split_fn <- sapply(p , strsplit , split = ">", USE.NAMES = FALSE)

split_fn <- sapply(split_fn, function(x) paste(head(x,-2), head(tail(x,-1),-1), tail(x,-2), sep = ">") )

Результат:

> split_fn
[[1]]
 [1] "Social>PaidSearch>PaidSearch"              "PaidSearch>PaidSearch>PaidSearch"          "PaidSearch>PaidSearch>PaidSearch"         
 [4] "PaidSearch>PaidSearch>PaidSearch"          "PaidSearch>PaidSearch>PaidSearch"          "PaidSearch>PaidSearch>PaidSearch"         
 [7] "PaidSearch>PaidSearch>PaidSearch"          "PaidSearch>PaidSearch>PaidSearch"          "PaidSearch>PaidSearch>PaidSearch"         
[10] "PaidSearch>PaidSearch>OrganicSearch"       "PaidSearch>OrganicSearch>OrganicSearch"    "OrganicSearch>OrganicSearch>OrganicSearch"

[[2]]
[1] "Referral>Referral>Referral"
0 голосов
/ 21 мая 2018

Использование пакета stringr (или регулярного выражения в целом).

library(stringr)
str_extract_all(p, "(\\w+)>(\\w+)>(\\w+)")

С перекрытием, но код может быть упрощен.

str_extract_all_overlap <- function (x) {
  extractions <- character()
  x_curr <- x
  extr <- str_extract(x_curr, "(\\w+)>(\\w+)>(\\w+)")
  i = 1
  while (!is.na(extr)) {
    extractions[i] <- extr 
    x_curr <- str_replace(x_curr, "\\w+", replacement = "")
    extr <- str_extract(x_curr, "(\\w+)>(\\w+)>(\\w+)")
    i = i + 1
  }
  return(extractions)
}

lapply(p, str_extract_all_overlap)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...