r 仅用备用 table 中的值替换某些 table 值

r Replace only some table values with values from alternate table

这不是 "vlookup-and-fill-down" 问题。

我的源数据非常适合提供我需要的所有数据,只是没有以可用的形式提供。最近的音量变化意味着手动调整修复不再可行。

我有库存 table 和服务 table。库存报告不包含服务或非库存项目的采购订单数据。服务 table(自然地)会。它们当然是不同的形状。

伪编码会达到 for every inventory$Item in services$Item, replace inventory$onPO with services$onPO.

的效果

示例数据

inv <- structure(list(Item = c("10100200", "10100201", "10100202", "10100203", 
"10100204", "10100205-A", "10100206", "10100207", "10100208", 
"10100209", "10100210"), onHand = c(600L, NA, 39L, 0L, NA, NA, 
40L, 0L, 0L, 0L, 0L), demand = c(3300L, NA, 40L, 40L, NA, NA, 
70L, 126L, 10L, 10L, 250L), onPO = c(2700L, NA, 1L, 40L, NA, 
NA, 30L, 126L, 10L, 10L, 250L)), .Names = c("Item", "onHand", 
"demand", "onPO"), row.names = c(NA, -11L), class = c("data.table", 
"data.frame"))

svc <- structure(list(Item = c("10100201", "10100204", "10100205-A"), 
    `Rcv'd` = c(0L, 0L, 44L), Backordered = c(20L, 100L, 18L)), .Names = c("Item", 
"Rcv'd", "Backordered"), row.names = c(NA, -3L), class = c("data.table", 
"data.frame"))

从表格开始:

  >inv
          Item OnHand Demand OnPO
 1:   10100200    600   3300 2700
 2:   10100201     NA     NA   NA
 3:   10100202     39     40    1
 4:   10100203      0     40   40
 5:   10100204     NA     NA   NA
 6: 10100205-A     NA     NA   NA
 7:   10100206     40     70   30
 8:   10100207      0    126  126
 9:   10100208      0     10   10
10:   10100209      0     10   10
11:   10100210      0    250  250

> svc
         Item Rcv'd Backordered
1:   10100201     0          20
2:   10100204     0         100
3: 10100205-A    44          18

经过比我想承认的更多的诅咒,适用于上述测试数据的简单解决方案以及我的实时数据被证明是:

# Insert OnHand and OnPO data from svc
for (i in 1:nrow(inv)) {
  if(inv$Item[i] %in% svc$Item) {
    x <- which(svc$Item == inv$Item[i])
    inv$OnPO[i] <- svc$Backordered[x]
    inv$OnHand[i] <- svc$`Rcv'd`[x]
  } 
    else{}
}
# cleanup 
inv[is.na(inv)] <- 0

是否有我忽略的更简单或更明显的方法?

假设您想用 Backordered 中的值替换 onPO 中的 NAs,这是使用 dplyr::left_join:

的解决方案
library(dplyr);
left_join(inv, svc) %>%
    mutate(onPO = ifelse(is.na(onPO), Backordered, onPO)) %>%
    select(-Backordered, -`Rcv'd`);
#         Item onHand demand onPO
#1    10100200    600   3300 2700
#2    10100201     NA     NA   20
#3    10100202     39     40    1
#4    10100203      0     40   40
#5    10100204     NA     NA  100
#6  10100205-A     NA     NA   18
#7    10100206     40     70   30
#8    10100207      0    126  126
#9    10100208      0     10   10
#10   10100209      0     10   10
#11   10100210      0    250  250

或者使用 merge 的基础 R 中的解决方案:

inv$onPO <- with(merge(inv, svc, all.x = TRUE), ifelse(is.na(onPO), Backordered, onPO))

或使用 coalesce 而不是 ifelse(感谢@thelatemail):

library(dplyr);
left_join(inv, svc) %>%
    mutate(onPO = coalesce(onPO, Backordered)) %>%
    select(-Backordered, -`Rcv'd`);

data.table的世界里,这是一个"update-join"。加入 "Item",然后用新集合中的值更新原始集合中的值:

library(data.table)
setDT(inv)
setDT(svc)

inv[svc, on="Item", c("onPO","onHand") := .(i.Backordered, `i.Rcv'd`)]

#inv   original table
#svc   update table
#on=   match on specified variable
# :=   overwrite  onPO    with  Backordered
#                 onHand  with  Rcv'd


#          Item onHand demand onPO
# 1:   10100200    600   3300 2700
# 2:   10100201      0     NA   20
# 3:   10100202     39     40    1
# 4:   10100203      0     40   40
# 5:   10100204      0     NA  100
# 6: 10100205-A     44     NA   18
# 7:   10100206     40     70   30
# 8:   10100207      0    126  126
# 9:   10100208      0     10   10
#10:   10100209      0     10   10
#11:   10100210      0    250  250

我们可以使用我的包 safejoin 中的 eat,以及 "patch" 当列冲突时从 rhs 匹配到 lhs。

我们在途中将 Backordered 重命名为 onPO,因此两列会发生冲突。

# devtools::install_github("moodymudskipper/safejoin")
library(safejoin)
library(dplyr)

eat(inv, svc, onPO = Backordered, .conflict = "patch")
#          Item onHand demand onPO
# 1    10100200    600   3300 2700
# 2    10100201     NA     NA   20
# 3    10100202     39     40    1
# 4    10100203      0     40   40
# 5    10100204     NA     NA  100
# 6  10100205-A     NA     NA   18
# 7    10100206     40     70   30
# 8    10100207      0    126  126
# 9    10100208      0     10   10
# 10   10100209      0     10   10
# 11   10100210      0    250  250