R:验证对应列值(ID 和名称)的匹配并标记不一致,最好在 dplyr 中

R: Validate matches of coresponding column values (ID and name) and flag inconsistencies, ideally in dplyr

假设您有一个包含数百个产品的数据框和另一个包含数千个销售额的数据框(请参阅下面的简化数据)。每个产品都有一个名称和一个 ID。不幸的是,在销售数据中,产品名称和 id 之间存在一些不一致(见观察 3)。我如何以自动方式识别和标记这些不一致,例如通过添加一个列来突出显示这些不一致(请参见下面的示例)。最好是集成到我的 dplyr 数据操作工作流程中。

请注意,数据有点乱,有些订单合并了多个产品(见obs.4)。我想到了与 grepl.

结合的循环
# products
P_names <- c( 'ProductA', 'ProductB')
P_ID <- c('p1', 'p2')
Product_list <- data.frame(P_names, P_ID)

   P_names P_ID
1 ProductA   p1
2 ProductB   p2

# sales data
P_n_sales <- c('ProductA', 'ProductB', 'ProductB', 'ProductA, ProductB', 'ProductB, ProductA')
P_ID_sales  <- c('p1', 'p2', 'p1', 'p1, p1', 'p1, p2')
sales_data <- data.frame(P_n_sales, P_ID_sales)

          P_n_sales P_ID_sales
1           ProductA         p1
2           ProductB         p2
3           ProductB         p1
4 ProductA, ProductB     p1, p1
5 ProductB, ProductA     p1, p2

期望的输出:

           P_n_sales P_ID_sales Incons.
1           ProductA         p1  corect
2           ProductB         p2  corect
3           ProductB         p1   error
4 ProductA, ProductB     p1, p1   error
5 ProductB, ProductA     p1, p2 correct

您可以执行 left/right 连接并将 Sales_data 中不存在的组合的值更改为 'error'

library(dplyr)

Sales_data %>%
  mutate(rowid = row_number()) %>%
  tidyr::separate_rows(P_n_sales, P_ID_sales, sep = ',\s*') %>%
  left_join(Product_list %>% mutate(Incons = 'correct'), 
            by = c('P_n_sales' = 'P_names', 'P_ID_sales' = 'P_ID')) %>%
  group_by(rowid) %>%
  summarise(across(c(P_n_sales, P_ID_sales), toString),
            Incons = if(any(is.na(Incons))) 'error' else 'correct') %>%
  select(-rowid)

#  P_n_sales          P_ID_sales Incons 
#  <chr>              <chr>      <chr>  
#1 ProductA           p1         correct
#2 ProductB           p2         correct
#3 ProductB           p1         error  
#4 ProductA, ProductB p1, p1     error  

我想 %in% 就可以了

Sales_data %>% mutate(id = row_number()) %>%
  separate_rows(P_n_sales, P_ID_sales) %>%
  mutate(Incons. = paste(P_n_sales, P_ID_sales) %in% paste(Product_list$P_names, Product_list$P_ID)) %>%
  group_by(id) %>%
  summarise(Incons. = ifelse(min(Incons.) == 0, "Incorr", "Corr")) %>%
  left_join(Sales_data %>% mutate(id = row_number()))


# A tibble: 4 x 4
     id Incons. P_n_sales          P_ID_sales
  <int> <chr>   <chr>              <chr>     
1     1 Corr    ProductA           p1        
2     2 Corr    ProductB           p2        
3     3 Incorr  ProductB           p1        
4     4 Incorr  ProductA, ProductB p1, p1

您好,感谢您的回复。然而,尽管上面提供的解决方案似乎 运行 快得多,但他们没有考虑到数据(产品 ID 和名称)可能以错误的顺序输入。

我更想找的是:

library(dplyr)
##
for (n in 1:nrow(Product_list)){
 sales_data<-sales_data%>%
 dplyr::mutate(Incons = ifelse(
                                (grepl(Product_list$P_names[n], sales_data$P_n_sales)
                                &!grepl(Product_list$P_ID[n], sales_data$P_ID_sales))
                                |
                                (!grepl(Product_list$P_names[n], sales_data$P_n_sales)
                                &grepl(Product_list$P_ID[n], sales_data$P_ID_sales))
                               ,paste('error')
                                ,paste('correct')
                                ))
}

根据数据的复杂性,它可能需要在 grepl() 中进行额外的正则表达式规范,例如转义特殊字符、单词绑定、...

有没有人有比遍历数据更有效的方法(大数据需要相当长的时间)?