3

我有一个包含 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() 来匹配模式“铅笔 *”或将“铅笔”更正为“铅笔”。

第 3 步)一旦纠正了模式,我必须进行分类。不知道怎么做。

这是我所考虑的。我从第 2 步开始,我只停留在第 2 步。我没有找到一个确切的方法来编码。有没有办法根据需要获得输出?如果是,请建议我可以继续使用的方法。

4

2 回答 2

3

你可以使用这个stringdist包。下面的函数将根据项目到不同的距离correct更正in file2 。Commodity.NameCName

然后 aleft_join用于连接两个表。

我还注意到,如果我使用stringdistmatrix. 您可以尝试更改weight参数以stringdistmatrix获得更好的校正结果。

> 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

如果您需要“其他”类别,您只需要使用权重即可。我在 file2 中添加了一行“Diesel”。然后使用自定义权重计算分数stringdist(您应该尝试改变值)。如果分数大于 2(这个值与权重的分配方式有关),它不会纠正任何事情。

PS:由于我们不知道所有可能的标签,我们必须做对as.character流到.factorcharacter

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
于 2015-04-23T06:16:12.037 回答
0

amatch(){stingdist}(至少在 0.9.4.6 中)有一个“近似字符串匹配”函数,它从预定义的单词集中返回最可能的匹配。它有一个参数maxDist可以设置为要匹配的最大距离,还有一个nomatch参数可以用于“其他”类别。否则,方法、权重等可以类似地设置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")

这将返回一个包含更正商品名称和类别的数据框。如果原件Commodity name与任何可能的商品名称相距超过 5 个字符(字符串距离的简化解释),则更正后的名称将为 NA。

于 2018-01-09T14:58:41.190 回答