Сокращение цикла while с условиями

Моя цель, по большому счету, состоит в том, чтобы печатать только те строки, которые имеют одинаковое/одинаковое имя поля без повторения. То есть, если три строки дублируются, вывести каждую из них только один раз (а не каждое попарное сравнение).

Минимальный набор данных и библиотека для воспроизведения:

library(stringdist)
trye <-  data.frame(names = c('aa','aa','aa','bb','bb','cc'),
                    values = 1:6,
                    id = c('row 1', 'row 2', 'row 3', 'row 4', 'row 5', 'row 6'), 
                    stringsAsFactors = FALSE)

Моим ожидаемым результатом будут строки с одинаковыми/похожими именами (1,2,3,4 и 5):

trye 
#   names values    id
# 1    aa      1 row 1
# 2    aa      2 row 2
# 3    aa      3 row 3
# 4    bb      4 row 4
# 5    bb      5 row 5

Вот две попытки, которые не сработали (некоторые другие модификации выдавали ошибки):

#this one prints row 1,2,3,3,5,5
i <- 1
while (i < length(trye$names)) {

  dupe <- amatch(trye$names[[i]],trye$names[-i], maxDist = 1)

  if(dupe  + 1 > 0) {
    print(trye[i,])
    duperow <- dupe + 1
    print(trye[duperow,])
    trye <- trye[-c(i), ]
    i <- i + 1


  } else {
    i <- i + 1
    trye <- trye[-c(i), ]
  }

}



# this one prints rows 1,2,4,5 which is almost correct,
# it's missing row 3 (as it shares the name with row 1 and 2.
i <- 1
while (i < length(trye$names)) {

  dupe <- amatch(trye$names[[i]],trye$names[-i], maxDist = 1)

  if(dupe  + 1 > 0) {
    print(trye[i,])
    duperow <- dupe + 1
    print(trye[duperow,])
    trye <- trye[-c(i,duperow), ]
    i <- i + 1


  } else {
    i <- i + 1
    trye <- trye[-c(i,duperow), ]
  }

}

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


person erasmortg    schedule 25.01.2016    source источник
comment
так вы хотите опустить строки с одним вхождением?   -  person Zahiro Mor    schedule 25.01.2016
comment
что-то вроде этого? sapply(1:nrow(trye), function(x) sum(adist(trye[x,1], trye[,1])==0)>1) ? используя adist вместо amatch   -  person jeremycg    schedule 25.01.2016
comment
Это работает для этого примера, поэтому, пожалуйста, не стесняйтесь добавлять его в качестве ответа, и я приму. Мой фактический набор данных, однако, составляет 500krows, поэтому очень желательно уменьшать размер набора данных с каждым проходом! Кроме того, maxDist в этом примере равен 1, но в моем реальном наборе он больше.   -  person erasmortg    schedule 25.01.2016


Ответы (1)


вы можете использовать adist из базы, чтобы получить расстояние Левенштейна, и отфильтровать те, у которых есть хотя бы одно совпадение (кроме самих себя):

sapply(1:nrow(trye), function(x) sum(adist(trye[x,1], trye[,1])==0)>1)

Если ваши данные очень велики, так как adist дорого, вы можете удалить все дубликаты, кроме первого и последнего:

trye[(!duplicated(trye$names) | rev(!duplicated(rev(trye$names)))),]

и добавить их обратно после этого. Вы также можете проверить openrefine, что может ускорить процесс.

person jeremycg    schedule 25.01.2016