Соответствие строки символ за символом в R - PullRequest
0 голосов
/ 07 октября 2018

У меня есть этот фрейм данных, содержащий строки строк и идентификаторы.Я называю это историей.

history
ID   string
1.1  a b b b c c s d s ....
1.2  a b b b b c s s d ....
2.1  a c c s s d b d b ....
2.2  a c s c s d b d b ....
3.1  a z z x d b d d f ....
3.2  a z x z d d f b d ....
...

Строки в каждом ряду довольно длинные.Идентификаторы, принадлежащие одному и тому же номеру, например 1.1 и 1.2, имеют похожие строки с небольшими отличиями1.1 и 2.2, хотя будут иметь большие различия между ними.В исходных данных около 70 строк.

test
string
a c c c s s d b d b....

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

Весь смысл в том, чтобы узнать, могу ли я определить, к какому идентификатору относится строка в «тесте», не сопоставляя всю строку.Одна идея, о которой я подумал, - отфильтровать историю, когда мы делаем больше совпадений в тесте.

Мой ожидаемый результат: здесь я предполагаю, что совпадение начинается с первого символа строки в «тесте» с первыми символами строк в «истории».И мы идем персонаж за персонажем.Оба эти предположения не являются фиксированными.Также длины строк в «history» и «test» могут быть разными.

Первый символ «a» из «test» соответствует всем в «history».Так что в этом случае фильтрации не происходит.

test
string
a 

результат:

history
    ID   string
    1.1  a b b b c c s d s ....
    1.2  a b b b b c s s d ....
    2.1  a c c s s d b d b ....
    2.2  a c s c s d b d b ....
    3.1  a z z x d b d d f ....
    3.2  a z x z d d f b d ....
    ...

Второй символ "c".Здесь, чтобы убедиться, что мы не совпадаем со случайным «c» из «истории», я думаю, что установление правила будет полезным.Нечто похожее происходит, если «а» то «с».

test
    string
    a c

результат:

history
    ID   string
    2.1  a c c s s d b d b ....
    2.2  a c s c s d b d b ....

Это уже сузило совпадение с историческими ID 2.1 и 2.2.Честно говоря, мы можем даже остановиться здесь, как я уже сказал, прежде чем различия между этими двумя будут крошечными.Итак, в заключение, как только история была отфильтрована до одного идентификатора, она должна вывести, какой идентификатор наилучшим образом соответствовал «тестовой» строке.

Ответы [ 2 ]

0 голосов
/ 07 октября 2018

Вот два tidyverse решения, которые будут возвращать значения ID с максимальным количеством совпадений с вашей тестовой строкой и количеством совпадений:

df = data.frame(ID = c(1.1,1.2,2.1,2.2,3.1,3.2),
                string = c("a b b b c c s d s",
                           "a b b b b c s s d",
                           "a c c s s d b d b",
                           "a c s c s d b d b",
                           "a z z x d b d d f",
                           "a z x z d d f b d"), 
                stringsAsFactors = F)

library(tidyverse)

# string to test
test = "a c c c s s"

Опция1 (с учетом матчей в любой позиции)

df %>%
  separate_rows(string) %>%
  group_by(ID) %>%
  mutate(test = unlist(strsplit(test, split = " "))[row_number()]) %>%
  na.omit() %>%
  summarise(matches = sum(string == test)) %>%
  filter(matches == max(matches))

# # A tibble: 2 x 2
#      ID matches
#   <dbl>   <int>
# 1   2.1       4
# 2   2.2       4

Опция 2 (с учетом последовательных матчей)

df %>%
  separate_rows(string) %>%
  group_by(ID) %>%
  mutate(test = unlist(strsplit(test, split = " "))[row_number()]) %>%
  na.omit() %>%
  summarise(matches = sum(cumprod(string == test))) %>%
  filter(matches == max(matches))

# # A tibble: 1 x 2
#        ID matches
#     <dbl>   <dbl>
#   1   2.1       3
0 голосов
/ 07 октября 2018

Построение поверх превосходного примера, приведенного выше AntoniosK:

Вы можете применить некоторый весовой коэффициент для каждого столбца.Поэтому, если столбец 1 очень важен, умножьте его на 10.000, а второй столбец только на 1.000.Затем суммируйте значения по строкам и найдите наибольшую сумму, чтобы получить наилучшие подходящие строки.

(Aka abcdef соответствует abcxxx лучше, чем abxdef)

library(tidyverse)
df = data.frame(ID = c(1.1,1.2,2.1,2.2,3.1,3.2),
                string = c("a b b b c c s d s",
                           "a b b b b c s s d",
                           "a c c s s d b d b",
                           "a c s c s d b d b",
                           "a z z x d b d d f",
                           "a z x z d d f b d"), 
                stringsAsFactors = F)
# string to test
test <-  "a c c c s s"

weights <- c(1000,100,10,10,10,10,10,10,10)

df_answer <- df %>%
  separate_rows(string) %>%
  group_by(ID) %>%
  mutate(test = unlist(strsplit(test, split = " "))[row_number()]) %>% 
  mutate(scores = (string == test) * weights) %>% 
  summarise(scores = sum(scores, na.rm = TRUE)) %>%
  filter(scores == max(scores))

# A tibble: 2 x 2
#     ID scores
#  <dbl>  <dbl>
#1   2.1   1120
#2   2.2   1120
...