简化带条件的“while循环”

4

我的目标是在IT技术领域中,仅打印具有相似/相同字段名称的行而不重复。也就是说,如果三行是重复的,则仅打印每个行一次(而不是每个成对比较)。

一个可重现的最小数据集和库:

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。

那么您想要省略只出现一次的行吗? - Zahiro Mor
你可以像这样使用 adist 而不是 amatch,通过以下编程来计算: sapply(1:nrow(trye), function(x) sum(adist(trye[x,1], trye[,1])==0)>1) - jeremycg
这个例子可以工作,所以请随意将其添加为答案,我会接受。然而,我的实际数据集有50万行,因此每次通过减小数据集的大小非常非常需要!此外,在这个例子中,maxDist是1,但在我的实际设置中它更大。 - erasmortg
1个回答

3
你可以使用基础模块中的adist函数获取Levenshtein距离,并通过筛选至少有一个匹配项(不包括自身)来过滤结果:
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,这是一个可以加快此过程的方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接