【问题标题】:Fill missing values from another dataframe with the same columns用相同的列填充另一个数据框中的缺失值
【发布时间】:2018-07-25 07:41:45
【问题描述】:

我搜索了各种加入问题,但似乎没有一个能完全回答这个问题。我有两个数据框,每个数据框都有一个 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 中的缺失值?

我找到了推荐使用合并的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,然后删除不完整的案例。问题是在我的真实数据集中,虽然有共享列,但也有非共享列,所以我必须创建共享列的中间对象,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 等分别列出每一列。

【问题讨论】:

    标签: r


    【解决方案1】:

    如果您只想通过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)]
    

    数据:

    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))
    

    编辑:基于问题中发布的新数据

    数据:

    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))
    

    代码:

    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
    

    【讨论】:

    • 这很好用,谢谢。我之前没有使用过 data.table 包,所以我必须花一些时间来熟悉它。
    • 有没有一种方法可以替换多个列而不逐个列出它们?在我的真实数据集中,我想要填充大约 15 个水质列,我宁愿避免单独输入它们。理想的解决方案是告诉它从给定数据框中获取所有列,或者能够按数字列出一组列。
    • 抱歉,已修复。我曾考虑将其添加,但认为它与我所问的问题无关。它已被删除。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 2022-01-17
    • 1970-01-01
    • 2020-03-24
    • 2019-06-16
    • 1970-01-01
    • 2021-12-10
    相关资源
    最近更新 更多