2016-04-28 38 views
1

我有两个包含城镇名称的向量,这两个向量都是不同的格式,我需要将水区名称(水)与各自的人口普查数据(城镇)。基本上,对于水中的每一行,我需要知道城镇中的最佳匹配,因为它们中的大多数都包含类似的词,如城市。我看到的另一个问题是,单词在一个数据集中被大写,并且不会在另一个数据集中大写。这里是我的示例数据:r哪些行具有两个向量之间最长的部分字符串匹配

towns= c("Acalanes Ridge CDP, Contra Costa County", "Bellflower city, Los Angeles County", "Arvin city, Kern County", "Alturas city, Modoc County") 

water=c("Alturas City of","Casitas Municipal Water District","California Water Service Company Bellflower City", "Contra Costa City of Public Works") 
+0

如果你有一个列表与所有城市apriori然后这变得很容易解决。我认为最好尽量避免部分匹配 – Sotos

+0

不幸的是,我没有那个。如果我打算列出这份清单,那么只需穿过400个水区,并手工将它们与1500个城镇中的任何一个匹配就可能更容易。 –

回答

2

使用tmslam包,这是一个不太幼稚的做法,采用了文本处理技术:

## load the requisite libraries 
library(tm) 
library(slam) 

首先,从组合的城镇创建语料库和水载体​​。我们最终将根据文本计算每个城镇和每个水体之间的距离。

corpus <- Corpus(VectorSource((c(towns, water)))) 

在这里,我做一些标准的预处理,通过删除标点符号和“文件”。词干找出词的共同基础部分。例如,城市和城市具有相同的词干:城市和城市具有相同的词干:城市和城市具有相同的词干:城市和城市具有相同的词干:城市和城市具有相同的词干:标准的术语文档矩阵具有二进制指示符,其中文字在哪个文档中。我们想编码关于这个词在整个语料库中的频繁程度的附加信息。例如,我们不在乎“the”出现在文档中的频率,因为它非常常见。

tdm <- weightTfIdf(TermDocumentMatrix(corpus)) 

最后,我们计算每个文档之间的余弦距离。 tm包创建通常非常有效的稀疏矩阵。 slam包具有稀疏矩阵的矩阵数学函数。

cosine_dist <- function(tdm) { 
    crossprod_simple_triplet_matrix(tdm)/(sqrt(col_sums(tdm^2) %*% t(col_sums(tdm^2)))) 
} 

d <- cosine_dist(tdm) 
> d 
    Docs 
Docs   1   2   3   4   5   6   7   8 
    1 1.00000000 0.034622992 0.038063800 0.044272011 0.00000000 0.0000000 0.000000000 0.260626250 
    2 0.03462299 1.000000000 0.055616255 0.064687275 0.01751883 0.0000000 0.146145917 0.006994714 
    3 0.03806380 0.055616255 1.000000000 0.071115850 0.01925984 0.0000000 0.006633427 0.007689843 
    4 0.04427201 0.064687275 0.071115850 1.000000000 0.54258275 0.0000000 0.007715340 0.008944058 
    5 0.00000000 0.017518827 0.019259836 0.542582752 1.00000000 0.0000000 0.014219656 0.016484228 
    6 0.00000000 0.000000000 0.000000000 0.000000000 0.00000000 1.0000000 0.121137618 0.000000000 
    7 0.00000000 0.146145917 0.006633427 0.007715340 0.01421966 0.1211376 1.000000000 0.005677459 
    8 0.26062625 0.006994714 0.007689843 0.008944058 0.01648423 0.0000000 0.005677459 1.000000000 

现在我们在同一个矩阵中的所有城镇和水体之间有一个相似度分数矩阵。不过,我们只关心这个矩阵的一半距离。因此,在下面的应用函数索引符号:

best.match <- apply(d[5:8,1:4], 1, function(row) if(all(row == 0)) NA else which.max(row)) 

而这里的输出:

> cbind(water, towns[best.match]) 
    water                      
[1,] "Alturas City of"         "Alturas city, Modoc County"    
[2,] "Casitas Municipal Water District"     NA          
[3,] "California Water Service Company Bellflower City" "Bellflower city, Los Angeles County"  
[4,] "Contra Costa City of Public Works"    "Acalanes Ridge CDP, Contra Costa County" 

通知NA值。当一个水体和所有城镇之间没有一个单词匹配时,NA被返回。

+0

@ Zelanzy7感谢您的回复。我无法通过创建tdm。也许我应该提一下,我的水数据只有400行,而城镇的数据是1500。错误给了我:在simple_triplet_matrix(i = i,j = j,v = as.numeric(v),nrow = length(allTerms),: 'i,j,v'不同长度的错误 另外:警告消息: 1:在mclapply(未命名(内容(x)),termFreq,控制)中: 所有调度内核在用户代码中遇到错误 2:在simple_triplet_matrix(i = i,j = j,v = as.numeric (v),nrow = length(allTerms),: 通过强制引入的NDA –

+0

我不确定你的例子发生了什么,如果你运行我的代码到你的虚拟数据上,它工作得很好。 ?或者是数据以其他方式存储在data.frames中? – Zelazny7

+0

@ Zelanzy7我试图回到这个位置,但仍然无法正常工作。我知道我给你的例子有效,但可以用我的方法解决真实的数据。数据我h ave存储在data.frames中,但我试过做Corpus(VectorSource((c(example example,example2 $ example2))))。我也试过做tmp1 = as.vector(例如$ example),然后将tmp1和tmp2添加到语料库命令中。我试图用as.list做同样的事情。我迷失在为什么这可能不工作。再一次,我得到的唯一错误是在尝试制作tdm时失败。我可以发布我的数据 –

0

另一种可能的方式,只使用基地R。我们使用strsplitwater分割字符串,从而创建一个列表,我们检查使用grepltowns中找到哪些字符串。我们现在有一个4个逻辑矩阵的列表。通过应用rowSums,我们得到每行的“TRUE”的总和。我们使用which.max来标识具有大部分'TRUE'值的行。最后,我们使用这些值来索引towns

lst <- lapply(strsplit(water, ' '), function(i) 
         sapply(tolower(i), function(j) 
           grepl(j, tolower(towns)))) 

ind <- unlist(as.numeric(lapply(lst, function(i) 
        which.max(rowSums(i)[!is.na(match(TRUE, i))])))) 

cbind(water, towns[ind]) 
#   water                      
#[1,] "Alturas City of"         "Alturas city, Modoc County"    
#[2,] "Casitas Municipal Water District"     NA          
#[3,] "California Water Service Company Bellflower City" "Bellflower city, Los Angeles County"  
#[4,] "Contra Costa City of Public Works"    "Acalanes Ridge CDP, Contra Costa County" 

侧面说明:我用[!is.na(match(TRUE, i))]仅在矩阵计算rowSums时确有“TRUE”值。否则,所有'FALSE'的4×4逻辑矩阵的rowSums0, 0, 0, 0,并且采取which.max(c(0, 0, 0, 0))给出1,这非常有趣。