Мне нужно посчитать экземпляры шаблона (фиксированного) в строке, которая содержится в столбце в таблице. mutate(x = str_count(col, pattern))
делает именно то, что я хочу, но недостаточно для обработки объема строк, которые я должен оценить.
Упрощенный тиббл
test = tibble(
id=c(1,2,3),
seq=c("ATCG","ATTT","CGCG")
)
Работает, но слишком медленно в тестировании микробенчмарков
test %>% mutate(CpG = str_count(seq, "CG"))
Теоретически быстрее на отдельных последовательностях, но не работает на моем столбце тиблов
Это просто дает единственное значение числа первой строки
test %>% mutate(CpG = sum(gregexpr("CG", seq, fixed=TRUE)[[1]] > 0))
Я пытался заставить работать purrr :: map, но у меня ничего не получается ... вот мои попытки, которые победили ' t run:
test %>% mutate(CpG = map(~sum(gregexpr("CG", seq, fixed=TRUE)[[1]] > 0)))
test %>% mutate(CpG = map(seq, ~sum(gregexpr("CG", .x, fixed=TRUE)[[1]] > 0)))
Редактировать: контрольные показатели времени
Похоже, stringi::stri_count_fixed
является оптимальным выбором для тестового набора.
microbenchmark(
mutate(test, CpG = stringr::str_count(seq, "CG")),
mutate(test, CpG = purrr::map_int(seq, ~sum(gregexpr("CG", .x, fixed=TRUE)[[1]] > 0))),
mutate(test, CpG = Biostrings::vcountPattern("CG", DNAStringSet(seq))),
mutate(test, CpG = lengths(regmatches(seq, gregexpr("CG", seq)))),
mutate(test, CpG = stringi::stri_count_fixed(seq,"CG"))
)
Unit: microseconds
expr min lq mean median uq max neval
mutate(test, CpG = stringr::str_count(seq, "CG")) 125.502 133.9995 159.0844 147.9045 164.2925 441.242 100
mutate(test, CpG = purrr::map_int(seq, ~sum(gregexpr("CG", .x, fixed = TRUE)[[1]] > 0))) 167.210 183.4695 215.7746 202.8890 230.5275 450.177 100
mutate(test, CpG = Biostrings::vcountPattern("CG", DNAStringSet(seq))) 789.889 827.3810 955.8919 887.3400 989.7415 1845.212 100
mutate(test, CpG = lengths(regmatches(seq, gregexpr("CG", seq)))) 150.315 159.4750 178.9039 169.1840 185.1345 316.479 100
mutate(test, CpG = stringi::stri_count_fixed(seq, "CG")) 112.015 120.6615 131.4281 125.0470 135.4330 213.184 100
И вот результаты с одной частью моих реальных данных (~ 20 000 экземпляров последовательностей по 1500 нт), запущенных на удаленном сервере с ~ 3X доступной оперативной памятью и ядрами моего начального запуска. Я по-прежнему впечатлен реализацией stringi
, которая каким-то образом прочитала все за блестящие 20 с чем-то миллисекунд.
Unit: milliseconds
expr min lq mean median uq max neval
mutate(test, CpG = stringr::str_count(seq, "CG")) 402.55513 408.04101 419.82213 414.31085 425.4113 481.08128 100
mutate(test, CpG = purrr::map_int(seq, ~sum(gregexpr("CG", .x, fixed = TRUE)[[1]] > 0))) 429.84148 436.02402 474.08864 438.84198 447.3058 1054.48253 100
mutate(test, CpG = Biostrings::vcountPattern("CG", DNAStringSet(seq))) 301.26062 309.76674 310.97071 310.08229 310.8837 336.12834 100
mutate(test, CpG = lengths(regmatches(seq, gregexpr("CG", seq)))) 1981.78309 1990.84206 2050.41928 1999.07389 2020.3675 2980.62566 100
mutate(test, CpG = stringi::stri_count_fixed(seq, "CG")) 23.33313 23.55215 23.90881 23.66268 23.8916 27.40499 100
Так как я мог запустить это на собственном DNAStringSet, так как мои данные начинаются как объект GRanges, я также провел микробенчмаркирование вектора последовательностей и получил диапазоны в приблизительном интервале 240-250 мс.
У меня есть еще один вариант использования с 1000-100000 nt длинных последовательностей с более длинными шаблонами поиска, и я планирую обновить эти результаты, когда я вернусь к этому проекту.