用数据框中的单词替换确切的字符串并匹配仅包含特定单词的字符串

Replacing exact string with a word from a dataframe & matching strings just containing a certain word

我正在使用 R,我有两个数据框。一个数据框 my_data 是我的主要数据集,其中包含订单数据,另一个数据框 word_list 包含我想与 my_data.

匹配的单词列表

这是两个数据框的可重现示例:

my_data <- data.frame(
  Order = c("1","2", "3", "4", "5", "6"),
  Product_ID = c("TS678", "AB123", "PACK12, 1xGF123, 1xML680", "AB123", "PACK13, 1xML680, 1x2304TR", "GF123"))

word_list <- data.frame(
  Codes = c("TS678","AB123", "GF123", "CC756"),
  Product_Category = c("Apple", "Apple", "Orange", "Orange"))

我想做的是将 my_data 中的 Product_ID 与 word_list 中的代码相匹配,并向 my_data 添加一个新列,其中匹配 Product_Category 来自 word_list.
但是,我需要实现精确匹配并考虑代码组合(如示例数据中的“PACK”所示,它由一列中的多个产品代码组成)

对于最终的数据框,我想以以下内容结束:

  1. 匹配完全匹配->添加对应的Product_Category,例如“苹果”
  2. 匹配包含来自 word_list 的代码但也包含其他代码的列。某些产品是 Packs 且 ID 与其他 ID 混合 -> 如果包含“apple”代码加上其他代码,则结果应为“Apple + Other”。这里还有一个问题是,需要匹配的Code还附带一个计数(例如PACK12包括1x GF123、1xML680等)
  3. 所有既不包含完全匹配也不包含混合匹配的列都应指定为“其他”

为了更好地理解,我希望得到的最终结果是一个如下所示的数据框:

 my_data_result <- data.frame(
  Order = c("1","2", "3", "4", "5", "6"),
  Product_ID = c("TS678", "AB123", "PACK12, 1xGF123, 1xML680", "AB123", "PACK13, 1xML680, 1x2304TR", "GF123"),
  Product_Category = c("Apple", "Apple", "Orange + Other", "Apple", "Other", "Orange"))

我想这可以用正则表达式和 gsub 来完成,但我不确定如何。

谢谢!

这是一个使用 dplyrtidyr 的想法。我们将行拆分为长行,清理代码,与 word_list 匹配并转换回每个订单的字符串,即

library(dplyr)
library(tidyr)

my_data %>% 
 separate_rows(Product_ID, sep = ', ') %>% 
 mutate(Product_ID = sub('.*x', '', Product_ID), 
        Product_Category = as.character(word_list$Product_Category[match(Product_ID, word_list$Codes)]), 
        Product_Category = replace(Product_Category, is.na(Product_Category), 'Other')) %>%
 group_by(Order) %>% 
 summarise_all(list(~toString(unique(.))))

# A tibble: 6 x 3
#  Order Product_ID            Product_Category
#  <fct> <chr>                 <chr>           
#1 1     TS678                 Apple           
#2 2     AB123                 Apple           
#3 3     PACK12, GF123, ML680  Other, Orange   
#4 4     AB123                 Apple           
#5 5     PACK13, ML680, 2304TR Other           
#6 6     GF123                 Orange

由于您的数据量很大,您可以尝试这种 data.table 方法:

library(data.table)
library(splitstackshape)

#Convert to data.table
setDT(my_data)
setDT(word_list)

#Get the data in long format
df1 <- cSplit(my_data, 'Product_ID', direction = 'long')
#Remove initial characters 
df1[, Product_ID := sub('.*x', '', Product_ID)]

#Join the dataframes
df1 <- merge(df1, word_list, by.x = 'Product_ID', by.y = 'Codes', all.x = TRUE)
#Replace NA with "Other"
df1[, Product_Category := replace(Product_Category, 
                           is.na(Product_Category), 'Other')]

#Combine the values by Order
df1[, .(Product_ID = toString(Product_ID), 
       Product_Category = paste(sort(unique(Product_Category)), 
                          collapse = " + ")), Order]

#   Order            Product_ID Product_Category
#1:     5 2304TR, ML680, PACK13            Other
#2:     2                 AB123            Apple
#3:     4                 AB123            Apple
#4:     3  GF123, ML680, PACK12   Orange + Other
#5:     6                 GF123           Orange
#6:     1                 TS678            Apple