R: Поиск строки ПОХОЖИЕ и возврат с условным символом - PullRequest
4 голосов
/ 29 июня 2011

У моего df есть следующие записи:

A
xxx
xxx
xxx1
xx1x
yyyy
gggg

Я хочу добавить символы в столбец B моего df на основе сходства столбца A, основываясь на следующих условиях.

  • Я установил порог как = или> 75% аналогично.

  • Столбец А уже отсортирован.Таким образом, проверка сходства для ОДНОГО выше.

  • Если верхний аналогичен, символ будет скопирован из верхнего столбца B.

  • Если верхний отличен, символбудет скопирован из столбца той же строки A.

Например, строки 1 и 2 совпадают.Их символ такой же, как в столбце А. Как и строка 3 (3 буквы из 4 с одинаковыми буквами и в одинаковой последовательности) на 75% аналогичны строке 1 и строке 2.его символ в столбце B будет скопирован из верхнего, то есть ххх.Поскольку xx1x (row4) только 2 из 4 букв, похожих на row3, он будет использовать только свой собственный символ, то есть xx1x.Поскольку yyyy и gggg совершенно разные, они сохранят свой собственный символ, как в столбце A.

Таким образом, мой конечный результат должен быть таким:

A      B
xxx    xxx
xxx    xxx
xxx1   xxx
xx1x   xx1x
yyyy   yyyy
gggg   gggg

Я выясняю это сходство%по предположению (его не нужно использовать, если есть формальный метод для поиска сходства строк), если есть какой-либо формальный метод для проверки сходства строк в R, было бы неплохо использовать.

Не могли бы вы рассказать, как эффективно добавить этот столбец символов с помощью R?

Ответы [ 2 ]

6 голосов
/ 29 июня 2011

Настроить данные:

x=c("xxx", "xxx", "xxx1", "xx1x", "yyyy", "gggg")

код:

same <- sapply(seq(length(x)-1), 
  function(i)any(agrep(x[i+1], x[1], max.distance=0.25)))
ex <- embed(x, 2)
cbind(A=x, B=c(x[1], ifelse(same, ex[, 2], ex[, 1])))

Результат:

     A      B     
[1,] "xxx"  "xxx" 
[2,] "xxx"  "xxx" 
[3,] "xxx1" "xxx" 
[4,] "xx1x" "xxx1"
[5,] "yyyy" "yyyy"
[6,] "gggg" "gggg"

Почему это работает?

Некоторые ключевые понятия и действительно полезные функции:

Во-первых, agrep предоставляет тест на то, насколько похожи строки, используя Levenshtein edit distance, который эффективно подсчитывает количество индивидуальных изменений символов, необходимых для преобразования одной строки в другую. Параметр max.distance=0.25 означает, что 25% строки шаблона может быть другим.

Например, проверьте, похожа ли какая-либо из исходных строк на «xxx»: это возвращает 1: 4:

agrep("xxx", x, max.distance=0.25)
[1] 1 2 3 4

Во-вторых, embed предоставляет полезный способ проверки лаговых переменных. Например, embed(x, 2) turns x` в массив с задержкой. Это позволяет легко сравнивать x [1] с x [2], поскольку теперь они находятся в одной строке массива:

embed(x, 2)
     [,1]   [,2]  
[1,] "xxx"  "xxx" 
[2,] "xxx1" "xxx" 
[3,] "xx1x" "xxx1"
[4,] "yyyy" "xx1x"
[5,] "gggg" "yyyy"

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


Чтобы это работало не с вектором, а над кадром данных, я превратил код в функцию следующим образом:

df <- data.frame(A=c("xxx", "xxx", "xxx1", "xx1x", "yyyy", "gggg"))

f <- function(x){
  x <- as.vector(x)
  same <- sapply(seq(length(x)-1), 
      function(i)any(agrep(x[i+1], x[1], max.distance=0.25)))
  ex <- embed(x, 2)
  c(x[1], ifelse(same, ex[, 2], ex[, 1]))
}
df$B <- f(df$A)
df

     A    B
1  xxx  xxx
2  xxx  xxx
3 xxx1  xxx
4 xx1x xxx1
5 yyyy yyyy
6 gggg gggg
0 голосов
/ 29 июня 2011

Вот более «базовое» решение (отредактированное для устранения некоторых проблем, поднятых в комментариях):

dat <- data.frame(A=c('xxx','xxx','xxx1','xx1x','yyyy','gggg'))
dat$B <- rep(NA,nrow(dat))

tmp <- strsplit(as.character(dat$A),"")
dat$B[1] <- dat$A[1]
for (i in 2:length(tmp)){
    n <- min(length(tmp[[i]]),length(tmp[[i-1]]))
    x <- sum(tmp[[i]][1:n] == tmp[[i-1]][1:n]) / length(tmp[[i]])
    if (x >= 0.75){
        dat$B[i] <- paste(tmp[[i-1]],collapse="")
    }
    else{ dat$B[i] <- paste(tmp[[i]],collapse="")}
}
...