Из ваших шаблонов видно, что строки могут фактически принадлежать нулю или более, а не только одному.Если это так, то первым шагом было бы определить, какими категориями (0 или более) обладает строка.
Мне не хватает вашего strings
для реального тестирования, поэтому я сгенерирую несколькопростые данные и шаблоны:
strings <- c("something", "something else", "nothing", "nothing here either",
"something or nothing", "interesting",
"something interesting", "nothing interesting")
pats <- c(p1 = "something", p2 = "nothing", p3 = "interesting")
(Шаблоны называются для удобства, когда сами шаблоны становятся громоздкими в качестве меток.) Начните с создания logical
матрицы:
m <- sapply(pats, grepl, strings, ignore.case = TRUE)
m
# p1 p2 p3
# [1,] TRUE FALSE FALSE
# [2,] TRUE FALSE FALSE
# [3,] FALSE TRUE FALSE
# [4,] FALSE TRUE FALSE
# [5,] TRUE TRUE FALSE
# [6,] FALSE FALSE TRUE
# [7,] TRUE FALSE TRUE
# [8,] FALSE TRUE TRUE
Если вы должны применить только одну категорию к строке, то, предполагая, что шаблоны расположены в порядке приоритета, вы можете сделать:
apply(m, 1, function(a) head(c(which(a), NA), n = 1))
# [1] 1 1 2 2 1 3 1 2
names(pats)[ apply(m, 1, function(a) head(c(which(a), 0), n = 1)) ]
# [1] "p1" "p1" "p2" "p2" "p1" "p3" "p1" "p2"
Примечание: это создаст NA
s, когда строки не содержат ни одного из шаблонов, демонстрируя:
m[8,] <- FALSE
apply(m, 1, function(a) head(c(which(a), NA), n = 1))
# [1] 1 1 2 2 1 3 1 NA
Вы должны остерегаться этого в своих предположениях.(Сейчас я сохраню m
с этим изменением.)
Если вам нужно сохранить категории для каждой строки, то как сделать это зависит от того, как вы собираетесь хранитьуказанные классификации.Для этого можно начать:
str(m2 <- apply(m, 1, function(r) names(which(r))))
# List of 8
# $ : chr "p1"
# $ : chr "p1"
# $ : chr "p2"
# $ : chr "p2"
# $ : chr [1:2] "p1" "p2"
# $ : chr "p3"
# $ : chr [1:2] "p1" "p3"
# $ : chr(0)
Это одно прямое хранилище: каждый элемент list
соответствует strings
и содержит ноль или более имен шаблонов.Если это для человеческого глаза, вы можете преобразовать это в набор с разделителями-запятыми:
sapply(m2, paste, collapse = ",")
# [1] "p1" "p1" "p2" "p2" "p1,p2" "p3" "p1,p3" ""
или для более формального хранения базы данных, как насчет
stringids <- seq_len(length(strings)) # perhaps you have something better?
d <- data.frame(
stringid = rep(stringids, times = lengths(m2)),
ptnmatch = unlist(m2),
stringsAsFactors = FALSE
)
d
# stringid ptnmatch
# 1 1 p1
# 2 2 p1
# 3 3 p2
# 4 4 p2
# 5 5 p1
# 6 5 p2
# 7 6 p3
# 8 7 p1
# 9 7 p3
Обратите вниманиекак строка 8 (которую я изменил, чтобы не было категорий) не включена, здесь это просто дизайн.Когда-то всегда можно заставить его вернуться с помощью:
misses <- setdiff(stringids, unique(d$stringid))
misses
# [1] 8
d <- rbind(d, data.frame(stringid = misses, ptnmatch = rep(NA, length(misses))),
stringsAsFactors = FALSE)
d
# stringid ptnmatch
# 1 1 p1
# 2 2 p1
# 3 3 p2
# 4 4 p2
# 5 5 p1
# 6 5 p2
# 7 6 p3
# 8 7 p1
# 9 7 p3
# 10 8 <NA>