2015-04-23 48 views
3

我有一個包含商品類別和商品名稱的2列csv文檔。哪個R功能用於文本自動校正?

例:

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)I第一有使用NLTK(文本挖掘方法)並清理數據,以便將「鉛筆」從「鉛筆-HB 02」中分離出來。

步驟2)清潔後,我必須使用近似字符串匹配技術,即agrep()匹配模式「鉛筆*」或更正「鉛筆」到「鉛筆」。

步驟3)一旦糾正模式,我必須分類。不知道如何。

這是我想過的。我從第2步開始,僅在第2步停留。 我沒有找到確切的方法來編碼。 有沒有辦法根據需要獲得輸出? 如果是,請給我建議我可以繼續的方法。

回答

3

您可以使用stringdist包。下面的correct函數將根據項目到不同CName的距離來修正file2中的Commodity.Name

然後left_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來將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 
+0

感謝您的回覆蘭迪。你能建議我一種處理不匹配情況的方法嗎?例如:如果我在文件2中有「汽油」或「柴油」或「卡車」作爲商品名稱,它應該歸入其他類別。所以爲此,我無法在文件1中添加一長串商品名稱。如果您能爲我提供一種處理此案例的方法,那將非常有用。同樣在agrep中,我們有max.distance,它會告訴我匹配的百分比。在StringDist中有這樣的東西嗎?.. – Viamia

+0

查看更新後的結果。 –

+0

感謝蘭迪。由於我沒有最新版本的R,我在安裝stringDist軟件包時遇到了問題。我會嘗試使用你建議的方法執行並返回。再次感謝。 – Viamia

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。