Какую функцию R использовать для автокоррекции текста?

У меня есть документ CSV с 2 столбцами, который содержит категорию товара и название товара.

Пример:

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 (методы интеллектуального анализа текста) и очистить данные, чтобы отделить "Карандаш" от "Карандаш-HB 02" .

Шаг 2) После очистки я должен использовать метод сопоставления приблизительных строк, например, agrep(), чтобы сопоставить шаблоны "Карандаш *" или исправить "Pancil" на "Карандаш".

Шаг 3) После исправления шаблона я должен классифицировать. Понятия не имею, как.

Это то, о чем я думал. Я начал с шага 2 и застрял только на шаге 2. Я не нахожу точный метод, чтобы закодировать это. Есть ли способ получить вывод по мере необходимости? Если да, пожалуйста, предложите мне метод, который я могу использовать.

2 ответа

Решение

Вы могли бы использовать stringdist пакет. correct Функция ниже исправит Commodity.Name в файле2 на основе расстояния элемента до различных CName,

Затем 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. Затем вычислите счет, используя 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

Существует функция "Приблизительное совпадение строк" 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.

Другие вопросы по тегам