【问题标题】:Find matching string patterns [closed]查找匹配的字符串模式 [关闭]
【发布时间】:2021-04-14 20:34:19
【问题描述】:

假设我有以下数据:

example = tibble::tibble(
  id = 1:10,
  vac = c("FFizer", "sinovasm", "aztraseneca", "phiser", "sonovac",
          "faizer", "sinivasc", "astraseneca", "sinocav", "aztraxeneca")
)

看起来像这样:

# A tibble: 10 x 2
      id vac        
   <int> <chr>      
 1     1 FFizer     
 2     2 sinovasm   
 3     3 aztraseneca
 4     4 phiser     
 5     5 sonovac    
 6     6 faizer     
 7     7 sinivasc   
 8     8 astraseneca
 9     9 sinocav    
10    10 aztraxeneca

我想知道变量 lab 是否在某种程度上与向量中的任何选项匹配。

假设用作标识符的向量是:

labs = c("sinovac", "pfizer", "astrazeneca")

用向量labs 交叉example data.frame 应该会给出如下输出:

correction = tibble::tibble(
  id = 1:10,
  vac = c("FFizer", "sinovasm", "aztraseneca", "phiser", "sonovac",
          "faizer", "sinivasc", "astraseneca", "sinocav", "aztraxeneca"),
  match = c("pfizer", "sinovac", "astrazeneca", "pfizer", "sinovac",
            "pfizer", "sinovac", "astrazeneca", "sinovac", "astrazeneca")
)

看起来像这样:

# A tibble: 10 x 3
      id vac         match      
   <int> <chr>       <chr>      
 1     1 FFizer      pfizer     
 2     2 sinovasm    sinovac    
 3     3 aztraseneca astrazeneca
 4     4 phiser      pfizer     
 5     5 sonovac     sinovac    
 6     6 faizer      pfizer     
 7     7 sinivasc    sinovac    
 8     8 astraseneca astrazeneca
 9     9 sinocav     sinovac    
10    10 aztraxeneca astrazeneca

主要思想是找到一种具有齐次vac变量的方法

除此之外,我想创建一个表示“匹配度”的变量。我的意思是,如果字符串是“FFizer”,那么它的匹配将是“pfizer”,它们的匹配度将在 0.66 左右

【问题讨论】:

  • 我认为您需要详细说明您的算法。你是怎么得出 0.66 的?你在检查有多少个字符匹配?如果它们被打乱或长度不同怎么办?
  • 我没有提供任何关于“匹配度”的更多细节,因为我不清楚匹配的情况。实际上,我说的 0.66 只是计算两个字符串之间共有多少个字符。但主要问题首先是如何将 vac 与实验室向量匹配。
  • @Cristhian 你想使用 Levenshtein 距离。有关选项+研究算法,请参见this question;我认为非常适合您的用例
  • @ctwheels,非常感谢。阅读那篇文章帮助我找到了stringdist 包!

标签: r regex string


【解决方案1】:

您应该查看库 fuzzyjoin 和 stringdist。使用 Levenshtein 距离:

library(fuzzyjoin)
library(dplyr)
library(stringdist)


labs <-  data.frame(vac = c("sinovac", "pfizer", "astrazeneca"))
fuzzyjoin::stringdist_left_join(df, labs,
                                by = c("vac"),
                                method = "lv") %>% 
  dplyr::rename(vac = vac.x, match = vac.y)

输出

   id         vac       match
1   1      FFizer      pfizer
2   2    sinovasm     sinovac
3   3 aztraseneca astrazeneca
4   4      phiser      pfizer
5   5     sonovac     sinovac
6   6      faizer      pfizer
7   7    sinivasc     sinovac
8   8 astraseneca astrazeneca
9   9     sinocav     sinovac
10 10 aztraxeneca astrazeneca

fuzzyjoin 的 method 采用来自 stringdist 库的 stringdist-method。

此外,fuzzyjoin 具有参数distance_col,您可以在其中命名计算距离测量的列。例如,使用 Jaro-Winker 距离(较小的值是“更接近”):

fuzzyjoin::stringdist_left_join(df, labs,
                                 by = c("vac"),
                                 method = "jw",
                                 distance_col = "dist") %>% 
   dplyr::rename(vac = vac.x, match = vac.y)

   id         vac       match       dist
1   1      FFizer     sinovac 0.56349206
2   1      FFizer      pfizer 0.22222222
3   1      FFizer astrazeneca 0.57575758
4   2    sinovasm     sinovac 0.13095238
5   2    sinovasm      pfizer 0.56944444
6   2    sinovasm astrazeneca 0.52272727
7   3 aztraseneca     sinovac 0.51082251
8   3 aztraseneca      pfizer 0.52020202
9   3 aztraseneca astrazeneca 0.03030303
10  4      phiser     sinovac 0.56349206
11  4      phiser      pfizer 0.22222222
12  4      phiser astrazeneca 0.52020202
13  5     sonovac     sinovac 0.15079365
14  5     sonovac      pfizer 1.00000000
15  5     sonovac astrazeneca 0.43290043
16  6      faizer     sinovac 0.56349206
17  6      faizer      pfizer 0.11111111
18  6      faizer astrazeneca 0.44823232
19  7    sinivasc     sinovac 0.13095238
20  7    sinivasc      pfizer 0.56944444
21  7    sinivasc astrazeneca 0.45075758
22  8 astraseneca     sinovac 0.43290043
23  8 astraseneca      pfizer 0.66161616
24  8 astraseneca astrazeneca 0.06060606
25  9     sinocav     sinovac 0.04761905
26  9     sinocav      pfizer 0.56349206
27  9     sinocav astrazeneca 0.51082251
28 10 aztraxeneca     sinovac 0.51082251
29 10 aztraxeneca      pfizer 0.52020202
30 10 aztraxeneca astrazeneca 0.12727273

【讨论】:

    【解决方案2】:

    根据这里的一些建议,我阅读了stringdist 包并找到了两个有用的功能,amatch 根据允许的最大距离从向量中找到匹配项,strindist 用于评估匹配项的不同程​​度( 0表示是同一个字符串,距离值越大表示字符串与目标不太相似)

    correction  = example %>% 
      mutate(
        m = amatch(x = vac, table = labs, maxDist = 2),
        matched_to = case_when(
          m == 1 ~ "sinovac",
          m == 2 ~ "pfizer",
          m == 3 ~ "astrazeneca"
        ),
        similarity = stringdist(vac, matched_to)
      )
    

    有这个输出:

    # A tibble: 10 x 5
          id vac             m matched_to  similarity
       <int> <chr>       <int> <chr>            <dbl>
     1     1 FFizer          2 pfizer               2
     2     2 astrazeneca     3 astrazeneca          0
     3     3 aztraseneca     3 astrazeneca          2
     4     4 phiser          2 pfizer               2
     5     5 sonovac         1 sinovac              1
     6     6 faizer          2 pfizer               2
     7     7 sinivasc        1 sinovac              2
     8     8 astraseneca     3 astrazeneca          1
     9     9 sinocav         1 sinovac              2
    10    10 aztraxeneca     3 astrazeneca          2
    

    【讨论】:

      猜你喜欢
      • 2013-10-31
      • 1970-01-01
      • 2020-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多