R: поиск строки по SIMILAR и возврата с условным символом

My df имеет следующие записи:

A
xxx
xxx
xxx1
xx1x
yyyy
gggg

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

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

  • Столбец A уже отсортирован. Так, проверка сходства для ONE выше необходим.

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

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

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

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

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

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

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

2 ответа

Настройка данных:

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


Здесь более "основное" решение (отредактированное для исправления некоторых проблем, поднятых в комментариях):

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="")}
}

licensed under cc by-sa 3.0 with attribution.