首页 文章

使用相同的列填充另一个数据框中的缺失值

提问于
浏览
2

我搜索了各种加入问题,似乎没有人回答这个问题 . 我有两个数据帧,每个数据帧都有一个ID列和几个信息列 .

df1 <- data.frame(id = c(1:100), color = c(rep("blue", 25), rep("red", 25), 
                  rep(NA, 25)), phase = c(rep("liquid", 50), rep("gas", 50)),
                  rand.col = rnorm(100))

df2 <- data.frame(id = c(51:100), color = rep("green", 50), phase = rep("gas", 50))

如您所见,df1缺少df2中存在的一些信息,而df2只是所有ID的子集,但它们都有一些类似的列 . 有没有办法根据DF2的匹配ID填充df1中的缺失值?

我发现了一个推荐使用merge的similar question,但是当我尝试使用它时,它删除了两个数据帧中都不存在的所有id . 此外,它需要手动删除重复的列,在我的真实数据集中,会有大量的这些,使得这样做很麻烦 . 即使忽略了这一点,

两种推荐的解决方案:

df1 <- setNames(merge(df1, df2)[-2], names(df1))

df1[is.na(df1$color), "color"] <- df2[match(df1$id, df2$id), "color"][which(is.na(df1$color))]

没有为我工作,抛出各种错误 .

我想到的另一种解决方案是使用 rbind 然后删除不完整的案例 . 问题是在我的真实数据集中,虽然有共享列,但也有非共享列,所以我必须创建只有共享列的中间对象,然后删除不完整的情况,然后用原始对象 join 重新获得掉落的专栏 . 这似乎是不必要的迂回 .

在这个例子中它看起来像

df2 = rbind(df1[,colnames(df2)], df2)
df2 = df2[complete.cases(df2),]
df2 = merge(df1[,c("id", "rand.col")], df2, by = "id")

并且,如果两个数据帧之间有任何完全重复的行,我需要添加

df2 = unique(df2)

这个解决方案可行,但它很麻烦,随着匹配的列数增加,情况会变得更糟 . 有更好的解决方案吗?

-edit-修正了Sathish指出的示例数据中的问题

-edit2-扩展的示例数据

df1 = data.frame(id = c(1:100),  wq2 = rnorm(50), wq3 = rnorm(50), wq4 = rnorm(50), 
wq5 = rnorm(50))

df2 = data.frame(id = c(51:100), wq2 = rnorm(50), wq3 = rnorm(50), wq4 = rnorm(50), 
wq5 = rnorm(50))

这些数据框表示存在许多具有不完整数据的列和具有所有缺失数据的第二个数据帧的情况 . 理想情况下,我们不需要使用 wq1 := i.wq1 等单独列出每个列 .

1 回答

  • 2

    如果只想通过 id 列加入,可以删除下面代码的 on 子句中的 phase .

    此外,您在问题中的数据也存在差异,这些差异已在此答案中发布的数据中得到纠正 .

    library('data.table')
    setDT(df1)  # make data table by reference
    setDT(df2)  # make data table by reference
    df1[ i = df2, color := i.color, on = .(id, phase)] # join df1 with df2 by id and phase values, and replace color values of df2 with color values of df1
    
    tail(df1)
    #     id color phase   rand.col
    # 1:  95 green   gas  1.5868335
    # 2:  96 green   gas  0.5584864
    # 3:  97 green   gas -1.2765922
    # 4:  98 green   gas -0.5732654
    # 5:  99 green   gas -1.2246126
    # 6: 100 green   gas -0.4734006
    

    一个班轮:

    setDT(df1)[df2, color := i.color, on = .(id, phase)]
    

    Data:

    set.seed(1L)
    df1 <- data.frame(id = c(1:100), color = c(rep("blue", 25), rep("red", 25), 
                                               rep(NA, 50)), phase = c(rep("liquid", 50), rep("gas", 50)),
                      rand.col = rnorm(100))
    
    df2 <- data.frame(id = c(51:100), color = rep("green", 50), phase = rep("gas", 50))
    

    EDIT: based on new data posted in the question

    Data:

    set.seed(1L)
    df1 = data.frame(id = c(1:100),  wq2 = rnorm(50), wq3 = rnorm(50), wq4 = rnorm(50), 
                     wq5 = rnorm(50))
    set.seed(2423L)
    df2 = data.frame(id = c(51:100), wq2 = rnorm(50), wq3 = rnorm(50), wq4 = rnorm(50), 
                     wq5 = rnorm(50))
    

    Code:

    library('data.table')
    setDT(df1)[ id == 52, ]
    #    id       wq2        wq3        wq4         wq5
    # 1: 52 0.1836433 -0.6120264 0.04211587 -0.01855983
    
    setDT(df2)[ id == 52, ]
    #    id       wq2       wq3        wq4       wq5
    # 1: 52 0.3917297 -1.007601 -0.6820783 0.3153687
    
    df1[df2, `:=` ( wq2 = i.wq2,
                    wq3 = i.wq3,
                    wq4 = i.wq4,
                    wq5 = i.wq5), on = .(id)]
    
    setDT(df1)[ id == 52, ]
    #    id       wq2       wq3        wq4       wq5
    # 1: 52 0.3917297 -1.007601 -0.6820783 0.3153687
    

相关问题