Найти строки с самой длинной подходящей строкой - PullRequest
0 голосов
/ 27 апреля 2020

У меня есть кадр данных, состоящий из групп с соответствующими животными в виде строки:

data = data.frame(group = c(1,2,3,4), animal = c("cat, dog, horse, mouse", "cat, dog, horse", "cat, dog,", "cat, dog, frog, cow"))

Я хотел бы вернуть группы, в которых совпадают самые длинные строки. В этом примере группы 1 и 2 совпадают, так как 3 из 4 животных одинаковы. Также группы 2 и 3 будут совпадать, так как совпадут 2 из 3 животных. Но ни одна группа не совпадает с группой 4, потому что совпадают только 2 из 4 животных.

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

group_a group_b
   1       2
   2       3

Я не уверен, возможно ли это. Я изучил, как сопоставить частичные строки, но изо всех сил пытался найти похожие примеры для адаптации. Есть идеи?

Спасибо.

Ответы [ 2 ]

1 голос
/ 27 апреля 2020

Учитывая ваш комментарий о желании сопоставить слова, вот начало текстового подхода, который может оказаться полезным. По сути, мы хотим выделить каждое слово и посчитать вхождение в каждом утверждении.

library(tidytext)
library(dplyr)
library(tidyr)

dtm <- data %>%
  unnest_tokens("word", "animal", token = "regex", pattern = ",") %>% 
  mutate(word = str_trim(word)) %>%
  count(group, word) %>% 
  pivot_wider(names_from = "word", values_from = "n", values_fill = list(n = 0)) 

Что вы знаете, так это матрица терминов документа. Теперь мы изменили вашу задачу с регулярного выражения, соответствующего одному, на поиск векторов с наибольшим количеством совпадений.

# A tibble: 4 x 7
  group   cat   dog horse mouse   cow  frog
  <dbl> <int> <int> <int> <int> <int> <int>
1     1     1     1     1     1     0     0
2     2     1     1     1     0     0     0
3     3     1     1     0     0     0     0
4     4     1     1     0     0     1     1

Легче всего было бы извлечь часть матрицы и просто умножить.

mat <- as.matrix(select(dtm, -group))
matches <- (mat %*% t(mat))

Это даст вам матрицу для каждой группы матчей. Например, строка 1, столбец 2 показывает совпадение трех слов (кошка, собака и лошадь) между группами 1 и 2.

matches
     [,1] [,2] [,3] [,4]
[1,]    4    3    2    2
[2,]    3    3    2    2
[3,]    2    2    2    2
[4,]    2    2    2    4

Затем вы можете поиграть с вещами оттуда. Например, извлечение идентификаторов строки и столбца, а затем верхней три angular части матрицы может дать вам сводную информацию. Я думаю, что отсюда все зависит от того, как вы хотите отфильтровать таблицу.

data.frame(row = c(row(matches)),
           col = c(col(matches)),
           value = c(matches),
           upper = c(upper.tri(matches))) %>% 
  filter(upper == TRUE)

  row col value upper
1   1   2     3  TRUE
2   1   3     2  TRUE
3   2   3     2  TRUE
4   1   4     2  TRUE
5   2   4     2  TRUE
6   3   4     2  TRUE
1 голос
/ 27 апреля 2020

Это то, что вы ищете?

lst <- regmatches(data$animal,gregexpr("\\w+",data$animal))

u <- lapply(seq_along(lst)[-length(lst)], 
            function(p) subset(data.frame(group_a = p,
                                          group_b = seq_along(lst)[-(1:p)],
                                          longestmatch = sapply(seq_along(lst)[-(1:p)], 
                                                                function(q) length(intersect(lst[[p]],lst[[q]])))),
                               longestmatch == max(longestmatch)))

res <- do.call(rbind,c(make.row.names = FALSE,u))

такой, что

> res
  group_a group_b longestmatch
1       1       2            3
2       2       3            2
3       2       4            2
4       3       4            2
...