哪个 R 函数用于文本自动更正?
which R function to use for Text Auto-Correction?
我有一个包含商品类别和商品名称的 2 列的 csv 文档。
例如:
Sl.No. Commodity Category Commodity Name
1 Stationary Pencil
2 Stationary Pen
3 Stationary Marker
4 Office Utensils Chair
5 Office Utensils Drawer
6 Hardware Monitor
7 Hardware CPU
我还有另一个包含各种商品名称的 csv 文件。
例如:
Sl.No. Commodity Name
1 Pancil
2 Pencil-HB 02
3 Pencil-Apsara
4 Pancil-Nataraj
5 Pen-Parker
6 Pen-Reynolds
7 Monitor-X001RL
我想要的输出是对商品名称进行标准化和分类,并将它们分类到相应的商品类别中,如下所示:
Sl.No. Commodity Name Commodity Category
1 Pencil Stationary
2 Pencil Stationary
3 Pencil Stationary
4 Pancil Stationary
5 Pen Stationary
6 Pen Stationary
7 Monitor Hardware
步骤 1) 我首先必须使用 NLTK(文本挖掘方法)并清理数据,以便将 "Pencil" 与 "Pencil-HB 02" 分开。
步骤 2) 清理后,我必须使用近似字符串匹配技术,即 agrep() 来匹配模式 "Pencil *" 或将 "Pancil" 更正为 "Pencil"。
第 3 步)纠正模式后,我必须进行分类。不知道怎么办。
这是我考虑过的。我从第 2 步开始,但只停留在第 2 步。
我没有找到对此进行编码的确切方法。
有什么办法可以按要求得到输出吗?
如果是,请建议我可以继续的方法。
您可以使用 stringdist
包。下面的 correct
函数将根据项目的距离将 file2 中的 Commodity.Name
更正为不同的 CName
。
然后用一个left_join
连接两个表
我还注意到,如果我使用 stringdistmatrix
的默认选项,会有一些分类。您可以尝试更改 stringdistmatrix
的 weight
参数以获得更好的校正结果。
> library(dplyr)
> library(stringdist)
>
> file1 <- read.csv("/Users/Randy/Desktop/file1.csv")
> file2 <- read.csv("/Users/Randy/Desktop/file2.csv")
>
> head(file1)
Sl.No. Commodity.Category Commodity.Name
1 1 Stationary Pencil
2 2 Stationary Pen
3 3 Stationary Marker
4 4 Office Utensils Chair
5 5 Office Utensils Drawer
6 6 Hardware Monitor
> head(file2)
Sl.No. Commodity.Name
1 1 Pancil
2 2 Pencil-HB 02
3 3 Pencil-Apsara
4 4 Pancil-Nataraj
5 5 Pen-Parker
6 6 Pen-Reynolds
>
> CName <- levels(file1$Commodity.Name)
> correct <- function(x){
+ factor(sapply(x, function(z) CName[which.min(stringdistmatrix(z, CName, weight=c(1,0.1,1,1)))]), CName)
+ }
>
> correctedfile2 <- file2 %>%
+ transmute(Commodity.Name.Old = Commodity.Name, Commodity.Name = correct(Commodity.Name))
>
> correctedfile2 %>%
+ inner_join(file1[,-1], by="Commodity.Name")
Commodity.Name.Old Commodity.Name Commodity.Category
1 Pancil Pencil Stationary
2 Pencil-HB 02 Pencil Stationary
3 Pencil-Apsara Pencil Stationary
4 Pancil-Nataraj Pencil Stationary
5 Pen-Parker Pen Stationary
6 Pen-Reynolds Pen Stationary
7 Monitor-X001RL Monitor Hardware
如果你需要"Others"类别,你只需要玩玩权重。
我在文件 2 中添加了一行 "Diesel"。然后使用 stringdist
和自定义权重计算分数(您应该尝试改变值)。如果分数大于 2(此值与权重的分配方式有关),则不会更正任何内容。
PS:因为我们不知道所有可能的标签,所以我们必须做 as.character
将 factor
转换为 character
。
PS2:我也在使用 tolower
进行不区分大小写的评分。
> head(file2)
Sl.No. Commodity.Name
1 1 Diesel
2 2 Pancil
3 3 Pencil-HB 02
4 4 Pencil-Apsara
5 5 Pancil-Nataraj
6 6 Pen-Parker
>
> CName <- levels(file1$Commodity.Name)
> CName.lower <- tolower(CName)
> correct_1 <- function(x){
+ scores = stringdistmatrix(tolower(x), CName.lower, weight=c(1,0.001,1,0.5))
+ if (min(scores)>2) {
+ return(x)
+ } else {
+ return(as.character(CName[which.min(scores)]))
+ }
+ }
> correct <- function(x) {
+ sapply(as.character(x), correct_1)
+ }
>
> correctedfile2 <- file2 %>%
+ transmute(Commodity.Name.Old = Commodity.Name, Commodity.Name = correct(Commodity.Name))
>
> file1$Commodity.Name = as.character(file1$Commodity.Name)
> correctedfile2 %>%
+ left_join(file1[,-1], by="Commodity.Name")
Commodity.Name.Old Commodity.Name Commodity.Category
1 Diesel Diesel <NA>
2 Pancil Pencil Stationary
3 Pencil-HB 02 Pencil Stationary
4 Pencil-Apsara Pencil Stationary
5 Pancil-Nataraj Pencil Stationary
6 Pen-Parker Pen Stationary
7 Pen-Reynolds Pen Stationary
8 Monitor-X001RL Monitor Hardware
{stingdist}
(至少在 0.9.4.6 中)有一个 'Approximate string matching' 函数 amatch()
,return 是预定义集合中最可能的匹配项的话。它有一个参数maxDist
可以设置匹配的最大距离,还有一个nomatch
参数可以用于'other'类别。否则method、weights等可以类似stringdistmatrix()
.
设置
因此,您的原始问题可以使用 tidyverse 兼容解决方案这样解决:
library(dplyr)
library(stringdist)
# Reading the files
file1 <- readr::read_csv("file1.csv")
file2 <- readr::read_csv("file2.csv")
# Getting the commodity names in a vector
commodities <- file1 %>% distinct(`Commodity Name`) %>% pull()
# Finding the closest string match of the commodities, and joining the file containing the categories
file2 %>%
mutate(`Commodity Name` = commodities[amatch(`Commodity Name`, commodities, maxDist = 5)]) %>%
left_join(file1, by = "Commodity Name")
这将 return 包含更正后的商品名称和类别的数据框。如果原始Commodity name
距离任何可能的商品名称超过5个字符(字符串距离的简化解释),则更正后的名称将为NA。
我有一个包含商品类别和商品名称的 2 列的 csv 文档。
例如:
Sl.No. Commodity Category Commodity Name
1 Stationary Pencil
2 Stationary Pen
3 Stationary Marker
4 Office Utensils Chair
5 Office Utensils Drawer
6 Hardware Monitor
7 Hardware CPU
我还有另一个包含各种商品名称的 csv 文件。
例如:
Sl.No. Commodity Name
1 Pancil
2 Pencil-HB 02
3 Pencil-Apsara
4 Pancil-Nataraj
5 Pen-Parker
6 Pen-Reynolds
7 Monitor-X001RL
我想要的输出是对商品名称进行标准化和分类,并将它们分类到相应的商品类别中,如下所示:
Sl.No. Commodity Name Commodity Category
1 Pencil Stationary
2 Pencil Stationary
3 Pencil Stationary
4 Pancil Stationary
5 Pen Stationary
6 Pen Stationary
7 Monitor Hardware
步骤 1) 我首先必须使用 NLTK(文本挖掘方法)并清理数据,以便将 "Pencil" 与 "Pencil-HB 02" 分开。
步骤 2) 清理后,我必须使用近似字符串匹配技术,即 agrep() 来匹配模式 "Pencil *" 或将 "Pancil" 更正为 "Pencil"。
第 3 步)纠正模式后,我必须进行分类。不知道怎么办。
这是我考虑过的。我从第 2 步开始,但只停留在第 2 步。 我没有找到对此进行编码的确切方法。 有什么办法可以按要求得到输出吗? 如果是,请建议我可以继续的方法。
您可以使用 stringdist
包。下面的 correct
函数将根据项目的距离将 file2 中的 Commodity.Name
更正为不同的 CName
。
然后用一个left_join
连接两个表
我还注意到,如果我使用 stringdistmatrix
的默认选项,会有一些分类。您可以尝试更改 stringdistmatrix
的 weight
参数以获得更好的校正结果。
> library(dplyr)
> library(stringdist)
>
> file1 <- read.csv("/Users/Randy/Desktop/file1.csv")
> file2 <- read.csv("/Users/Randy/Desktop/file2.csv")
>
> head(file1)
Sl.No. Commodity.Category Commodity.Name
1 1 Stationary Pencil
2 2 Stationary Pen
3 3 Stationary Marker
4 4 Office Utensils Chair
5 5 Office Utensils Drawer
6 6 Hardware Monitor
> head(file2)
Sl.No. Commodity.Name
1 1 Pancil
2 2 Pencil-HB 02
3 3 Pencil-Apsara
4 4 Pancil-Nataraj
5 5 Pen-Parker
6 6 Pen-Reynolds
>
> CName <- levels(file1$Commodity.Name)
> correct <- function(x){
+ factor(sapply(x, function(z) CName[which.min(stringdistmatrix(z, CName, weight=c(1,0.1,1,1)))]), CName)
+ }
>
> correctedfile2 <- file2 %>%
+ transmute(Commodity.Name.Old = Commodity.Name, Commodity.Name = correct(Commodity.Name))
>
> correctedfile2 %>%
+ inner_join(file1[,-1], by="Commodity.Name")
Commodity.Name.Old Commodity.Name Commodity.Category
1 Pancil Pencil Stationary
2 Pencil-HB 02 Pencil Stationary
3 Pencil-Apsara Pencil Stationary
4 Pancil-Nataraj Pencil Stationary
5 Pen-Parker Pen Stationary
6 Pen-Reynolds Pen Stationary
7 Monitor-X001RL Monitor Hardware
如果你需要"Others"类别,你只需要玩玩权重。
我在文件 2 中添加了一行 "Diesel"。然后使用 stringdist
和自定义权重计算分数(您应该尝试改变值)。如果分数大于 2(此值与权重的分配方式有关),则不会更正任何内容。
PS:因为我们不知道所有可能的标签,所以我们必须做 as.character
将 factor
转换为 character
。
PS2:我也在使用 tolower
进行不区分大小写的评分。
> head(file2)
Sl.No. Commodity.Name
1 1 Diesel
2 2 Pancil
3 3 Pencil-HB 02
4 4 Pencil-Apsara
5 5 Pancil-Nataraj
6 6 Pen-Parker
>
> CName <- levels(file1$Commodity.Name)
> CName.lower <- tolower(CName)
> correct_1 <- function(x){
+ scores = stringdistmatrix(tolower(x), CName.lower, weight=c(1,0.001,1,0.5))
+ if (min(scores)>2) {
+ return(x)
+ } else {
+ return(as.character(CName[which.min(scores)]))
+ }
+ }
> correct <- function(x) {
+ sapply(as.character(x), correct_1)
+ }
>
> correctedfile2 <- file2 %>%
+ transmute(Commodity.Name.Old = Commodity.Name, Commodity.Name = correct(Commodity.Name))
>
> file1$Commodity.Name = as.character(file1$Commodity.Name)
> correctedfile2 %>%
+ left_join(file1[,-1], by="Commodity.Name")
Commodity.Name.Old Commodity.Name Commodity.Category
1 Diesel Diesel <NA>
2 Pancil Pencil Stationary
3 Pencil-HB 02 Pencil Stationary
4 Pencil-Apsara Pencil Stationary
5 Pancil-Nataraj Pencil Stationary
6 Pen-Parker Pen Stationary
7 Pen-Reynolds Pen Stationary
8 Monitor-X001RL Monitor Hardware
{stingdist}
(至少在 0.9.4.6 中)有一个 'Approximate string matching' 函数 amatch()
,return 是预定义集合中最可能的匹配项的话。它有一个参数maxDist
可以设置匹配的最大距离,还有一个nomatch
参数可以用于'other'类别。否则method、weights等可以类似stringdistmatrix()
.
因此,您的原始问题可以使用 tidyverse 兼容解决方案这样解决:
library(dplyr)
library(stringdist)
# Reading the files
file1 <- readr::read_csv("file1.csv")
file2 <- readr::read_csv("file2.csv")
# Getting the commodity names in a vector
commodities <- file1 %>% distinct(`Commodity Name`) %>% pull()
# Finding the closest string match of the commodities, and joining the file containing the categories
file2 %>%
mutate(`Commodity Name` = commodities[amatch(`Commodity Name`, commodities, maxDist = 5)]) %>%
left_join(file1, by = "Commodity Name")
这将 return 包含更正后的商品名称和类别的数据框。如果原始Commodity name
距离任何可能的商品名称超过5个字符(字符串距离的简化解释),则更正后的名称将为NA。