在R中进行多维聚类/匹配

5
我有一个非常庞大且复杂的数据集,其中包含许多公司的观察结果。其中一些公司的观察结果是冗余的,我需要创建一个密钥将这些冗余的观察结果映射到单个观察结果。然而,判断它们是否实际上代表同一家公司的唯一方法是通过各种变量的相似性。我认为适当的方法是一种基于各种条件的聚类,或者甚至可能是某种倾向性评分匹配。也许我只需要灵活的工具来制作复杂的相似度矩阵。
不幸的是,我不太确定如何在R中处理这个问题。我看到的大多数用于聚类和分类的工具似乎都是通过数值距离或分类数据进行的,但似乎不允许多个条件或用户指定的条件。
下面我尝试创建了一个更小的公共示例,展示我正在处理的数据类型和我想要产生的结果。必须应用某些条件,例如位置必须相同。有些特征可能会将一个与另一个关联起来,例如var1和var2。然后有些特征可能会将一个与另一个联系起来,但它们不能冲突,例如var3。
另一个复杂度层面是,我尝试使用的关联类型不同。例如,id1和id2是两次多余输入到数据中的同一家公司。在一个地方,它的名称是“苹果”,在另一个地方是“红苹果”。它们共享相同的位置、var1值和var3(调整格式后)。同样,ids 3、5和6也只是一家公司,尽管每个输入的大部分内容都不同。某些分类将识别多个观察结果,而其他分类将只有一个。理想情况下,我希望找到一种基于几个条件对观察结果进行分类或关联的方法,例如: 1. 测试位置是否相同 2. 测试var3是否不同 3. 测试名称是否为其他名称的子字符串 4. 测试名称的编辑距离 5. 测试观察结果之间的var1和var2的相似性
总之,希望能有更好、更灵活的工具来解决这个问题,或者有人有在R中处理这种数据工作的经验。非常感谢任何建议和意见!
数据
id  name        location    var1    var2    var3
1   apples        US        1       abc     12345
2   red apples    US        1       NA      12-345
3   green apples  Mexico    2       def     235-92
4   bananas       Brazil    2       abc     NA
5   oranges       Mexico    2       NA      23592
6   green apple   Mexico    NA      def     NA
7   tangerines    Honduras  NA      abc     3498
8   mango         Honduras  1       NA      NA
9   strawberries  Honduras  NA      abcd    3498
10  strawberry    Honduras  NA      abc     3498
11  blueberry     Brazil    1       abcd    2348
12  blueberry     Brazil    3       abc     NA
13  blueberry     Mexico    NA      def     1859
14  bananas       Brazil    1       def     2348
15  blackberries  Honduras  NA      abc     NA
16  grapes        Mexico    6       qrs     NA
17  grapefruits   Brazil    1       NA      1379
18  grapefruit    Brazil    2       bcd     1379
19  mango         Brazil    3       efaq    NA
20  fuji apples   US        4       NA      189-35

结果

id  name        location    var1    var2    var3        Result
1   apples        US        1       abc     12345       1
2   red apples    US        1       NA      12-345      1
3   green apples  Mexico    2       def     235-92      3
4   bananas       Brazil    2       abc     NA          4
5   oranges       Mexico    2       NA      23592       3
6   green apple   Mexico    NA      def     NA          3
7   tangerines    Honduras  NA      abc     3498        7
8   mango         Honduras  1       NA      NA          8
9   strawberries  Honduras  NA      abcd    3498        7
10  strawberry    Honduras  NA      abc     3498        7
11  blueberry     Brazil    1       abcd    2348        11
12  blueberry     Brazil    3       abc     NA          11
13  blueberry     Mexico    NA      def     1859        13
14  bananas       Brazil    1       def     2348        11
15  blackberries  Honduras  NA      abc     NA          15
16  grapes        Mexico    6       qrs     NA          16
17  grapefruits   Brazil    1       NA      1379        17
18  grapefruit    Brazil    2       bcd     1379        17
19  mango         Brazil    3       efaq    NA          19
20  fuji apples   US        4       NA      189-35      20

感谢您的时间和帮助!


还有一些软件包可以帮助您检查字符的相似度。它将允许您得出结论,即“苹果”和“红苹果”属于同一簇。 - Adii_
@Adii_ 没有任何包可以将“apples”与“red apples”匹配,而不匹配其中的其他苹果。 - stanekam
@Adii_ 嗯...当然!我会非常印象深刻! - stanekam
非常感谢迄今为止提供的想法和讨论。我有一些关于测试的一般想法,例如匹配分类、编辑距离(Levenhstein)和子字符串搜索(使用grep)。假设我已经有了这些分类规则/测试和一个非常非常大的数据集,但对于我正在尝试做的事情,我仍然不清楚如何灵活地将它们聚类。是否有聚类或分类工具可以让我指定各种条件,并且让结果足够灵活,以便某些聚类只有1个项目,而其他聚类则识别出多个项目? - DaedalusBloom
你所面临的是记录链接或去重问题。有相应的算法可以解决。然而,据我所知,R语言中的RecordLinkage包已经从CRAN中删除,因此无法使用。 - Jan van der Laan
显示剩余7条评论
1个回答

0
library(stringdist)
getMatches <- function(df, tolerance=6){
  out <- integer(nrow(df))
  for(row in 1:nrow(df)){
    dists <- numeric(nrow(df))
    for(col in 1:ncol(df)){
      tempDist <- stringdist(df[row, col], df[ , col], method="lv")

      # WARNING: Matches NA perfectly.
      tempDist[is.na(tempDist)] <- 0
      dists <- dists + tempDist
    }
    dists[row] <- Inf

    min_dist <- min(dists)
    if(min_dist < tolerance){
      out[row] <- which.min(dists)
    }
    else{
      out[row] <- row
    }
  }
  return(out)
}

test$Result <- getMatches(test[, -1])

test 是您的数据。这可能绝对需要一些改进,肯定需要一些后处理。这将创建一个带有最接近匹配项索引的列。如果它在给定的公差内找不到匹配项,则返回其自身的索引。

编辑:稍后我会尝试更多。


谢谢你的帮助。我会稍微调整一下,看看能否让这个东西起作用。 - DaedalusBloom

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