用数据框中的单词替换确切的字符串并匹配仅包含特定单词的字符串
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”所示,它由一列中的多个产品代码组成)
对于最终的数据框,我想以以下内容结束:
- 匹配完全匹配->添加对应的Product_Category,例如“苹果”
- 匹配包含来自
word_list
的代码但也包含其他代码的列。某些产品是 Packs 且 ID 与其他 ID 混合 -> 如果包含“apple”代码加上其他代码,则结果应为“Apple + Other”。这里还有一个问题是,需要匹配的Code还附带一个计数(例如PACK12包括1x GF123、1xML680等)
- 所有既不包含完全匹配也不包含混合匹配的列都应指定为“其他”
为了更好地理解,我希望得到的最终结果是一个如下所示的数据框:
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 来完成,但我不确定如何。
谢谢!
这是一个使用 dplyr
和 tidyr
的想法。我们将行拆分为长行,清理代码,与 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
我正在使用 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”所示,它由一列中的多个产品代码组成)
对于最终的数据框,我想以以下内容结束:
- 匹配完全匹配->添加对应的Product_Category,例如“苹果”
- 匹配包含来自
word_list
的代码但也包含其他代码的列。某些产品是 Packs 且 ID 与其他 ID 混合 -> 如果包含“apple”代码加上其他代码,则结果应为“Apple + Other”。这里还有一个问题是,需要匹配的Code还附带一个计数(例如PACK12包括1x GF123、1xML680等) - 所有既不包含完全匹配也不包含混合匹配的列都应指定为“其他”
为了更好地理解,我希望得到的最终结果是一个如下所示的数据框:
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 来完成,但我不确定如何。
谢谢!
这是一个使用 dplyr
和 tidyr
的想法。我们将行拆分为长行,清理代码,与 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