根据 R 或 python 中的条件将一个列列表中的值替换为另一个列列表中的值

Replace values from one list of columns from another list of columns based on conditions in R or python

(对于 pythonistas,在我得到一些#hatehard 之前,下面的代码是 R 的格式)

这个让我沮丧的时间太长了。

我有 2 个数据集

df1 <- data.frame(ID = c("Person.A", "Person.B", "Person.C", "Person.D", "Person.E", "Person.F"),
                  Aa = c(0,1,2,NA,1,1),
                  Ab = c(0,NA,2,1,1,1),
                  Ac = c(NA,NA,2,2,1,1),
                  no.match = c(0,1,2,2,1,2))

df2 <- data.frame(ID = c("Person.A", "Person.B", "Person.C", "Person.D", "Person.E"),
                  Ba = c(0,NA,2,1,1),
                  Bb = c(NA,1,2,2,1),
                  Bc = c(0,1,2,2,1))

然后我使用 merge(df1, df2, all.x = T, by = "ID" 合并这两个数据集得到:

         ID Aa Ab Ac no.match Ba Bb Bc
1 Person.A  0  0 NA        0  0 NA  0
2 Person.B  1 NA NA        1 NA  1  1
3 Person.C  2  2  2        2  2  2  2
4 Person.D NA  1  2        2  1  2  2
5 Person.E  1  1  1        1  1  1  1
6 Person.F  1  1  1        2 NA NA NA

实际的数据集要复杂得多,有很多列在其他列中没有匹配项。所以我不认为我可以做一些取决于列的排列的事情。

AaBa 包含相同的信息; AbBb 列也是如此,依此类推,但 no.match 列不包含匹配的列。

我想"map" BaAa 同一行的值 if Aa 是 NA并对 AbBbAcBc 等执行相同的操作

本例中的结果 DF 如下所示:

        ID Aa Ab Ac no.match Ba Bb Bc
1 Person.A  0  0  0      0    0 NA  0
2 Person.B  1  1  1      1    NA  1  1
3 Person.C  2  2  2      2    2  2  2
4 Person.D  1  1  2      2    1  2 NA
5 Person.E  1  1  1      1    1  1  1
6 Person.F  1  1  1      2    NA NA NA

其中元素 [4,2] 被元素 [4,6] 替换 行和列需要匹配。

我已经尝试了多得令人尴尬的事情:applyifelse、遍历列列表 l1 = c('Aa','Ab','Ac'), l2 = c('Ba', 'Bb', 'Bc')

我可以做一次性的:which(is.na(mdf$Aa)) <- mdf[which(is.na(mdf$Aa)), c("Ba")]

但是我怎样才能迭代地做到这一点?

谢谢! (啰嗦抱歉)

这是一个使用 data.table v1.9.5 - 安装说明 here

require(data.table) # v1.9.5+
cols1 = names(df1)[2:4]
cols2 = names(df2)[2:4]

foo <- function(x, y) {
    nas = is.na(x)
    x[nas] = y[nas]
    x
}
setDT(df1)[df2, c(cols1, cols2) := c(Map(foo, mget(cols1), 
                   mget(cols2)), mget(cols2)), on = "ID"]

> df1
#          ID Aa Ab Ac no.match Ba Bb Bc
# 1: Person.A  0  0  0        0  0 NA  0
# 2: Person.B  1  1  1        1 NA  1  1
# 3: Person.C  2  2  2        2  2  2  2
# 4: Person.D  1  1  2        2  1  2  2
# 5: Person.E  1  1  1        1  1  1  1
# 6: Person.F  1  1  1        2 NA NA NA
  • setDT() 通过引用将 df1 转换为 data.table

  • setDT(df1)[df2, on = "ID"] 执行连接。对于 df2 的每一行,我们在 df1 中找到匹配的行并提取匹配行对应的列..

  • 在匹配的行上,我们更新列在cols1添加新列cols2 通过引用 使用 := 运算符。为了更新列,我们提取了 cols1cols2 中指定的列,并将 NAs 替换为函数 foo()。要添加列,我们只需使用 mget() 拉取列 cols2。我们使用 c().

  • 连接两个列表

如果您有兴趣,请查看 HTML vignettes 以了解更多信息。