r 哪些行在两个向量之间具有最长的部分字符串匹配
r which rows have longest partial string match between two vectors
我有两个包含城镇名称的向量,它们的格式不同,我需要将水区(水)的名称与其各自的人口普查数据(城镇)相匹配。基本上对于水中的每一行,我需要知道城镇中的最佳匹配项,因为它们中的大多数都包含类似的词,例如城市。我看到的另一个问题是单词在一个数据集中大写,而在另一个数据集中没有大写。这是我的示例数据:
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")
使用 tm
和 slam
包,这是一种不那么幼稚的方法,它结合了文本处理技术:
## load the requisite libraries
library(tm)
library(slam)
首先,从结合的城镇和水向量创建一个语料库。我们最终要根据文字计算出每个城镇和每个水体之间的距离。
corpus <- Corpus(VectorSource((c(towns, water))))
在这里,我通过删除标点符号和词干 "documents" 来进行一些标准预处理。词干提取找到单词的共同基础部分。例如,city 和 cities 具有相同的词干:citi
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, stemDocument)
标准的术语文档矩阵具有二进制指示器,用于指示哪些单词在哪些文档中。我们还想对有关该词在整个语料库中出现频率的附加信息进行编码。例如,我们不关心 "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。
另一种可能的方法是只使用基础R
。我们使用 strsplit
从 water
中拆分字符串,从而创建一个列表,然后我们使用 grepl
检查在 towns
中找到了哪些字符串。我们现在有一个包含 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))]
仅在矩阵中确实存在 'TRUE' 值时才计算 rowSums
。否则一个4×4逻辑矩阵全'FALSE'的rowSums
是0, 0, 0, 0
,取which.max(c(0, 0, 0, 0))
得到1
,挺有意思的[=25] =]
我有两个包含城镇名称的向量,它们的格式不同,我需要将水区(水)的名称与其各自的人口普查数据(城镇)相匹配。基本上对于水中的每一行,我需要知道城镇中的最佳匹配项,因为它们中的大多数都包含类似的词,例如城市。我看到的另一个问题是单词在一个数据集中大写,而在另一个数据集中没有大写。这是我的示例数据:
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")
使用 tm
和 slam
包,这是一种不那么幼稚的方法,它结合了文本处理技术:
## load the requisite libraries
library(tm)
library(slam)
首先,从结合的城镇和水向量创建一个语料库。我们最终要根据文字计算出每个城镇和每个水体之间的距离。
corpus <- Corpus(VectorSource((c(towns, water))))
在这里,我通过删除标点符号和词干 "documents" 来进行一些标准预处理。词干提取找到单词的共同基础部分。例如,city 和 cities 具有相同的词干:citi
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, stemDocument)
标准的术语文档矩阵具有二进制指示器,用于指示哪些单词在哪些文档中。我们还想对有关该词在整个语料库中出现频率的附加信息进行编码。例如,我们不关心 "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。
另一种可能的方法是只使用基础R
。我们使用 strsplit
从 water
中拆分字符串,从而创建一个列表,然后我们使用 grepl
检查在 towns
中找到了哪些字符串。我们现在有一个包含 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))]
仅在矩阵中确实存在 'TRUE' 值时才计算 rowSums
。否则一个4×4逻辑矩阵全'FALSE'的rowSums
是0, 0, 0, 0
,取which.max(c(0, 0, 0, 0))
得到1
,挺有意思的[=25] =]