Какую функцию 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.