【问题标题】:Replace NAs in dataframe with values from second dataframe based on multiple criteria根据多个标准将数据框中的 NA 替换为第二个数据框中的值
【发布时间】:2021-11-01 20:26:51
【问题描述】:

我有两个 data.frames,每个都有数千行和数十列,它们都是通过合并几个 csv 文件创建的。 data.frames 正是我想要的。我还要补充一点,df1 和 df2 有几个共同的列。唯一的问题是其中一个,比如说 df1 ,对于某些列,有一些 NA(这是预期的/正常的)。好消息是我有 NA 的相同列也出现在第二个 data.frame 中,比如 df2,但没有 NA。我想做的是用 df1 的同一列中的值填充 df2 给定列中的 NA,其中每个值是根据 df1 和 df2 之间其他列值的匹配来选择的。

使用一些随机数据:

A<- format(seq(as.Date("2021/09/01"), by = "day", length.out = 26), format="%Y%m%d")
B<- format(seq(as.POSIXct("2021-1-1 15:00"), as.POSIXct("2021-1-02 16:00"), by = "hour"), format = "%H:%M")
C<- sample(1:100, 26, replace=FALSE)
D<- LETTERS
E<- paste(D, C)

df1<- cbind(A, B, C, D)
df2<- cbind(A, B, C, E)
df2[c(7:10, 13, 18:21), 3] <- NA #replace some of the values with NAs
df2<- df2[-c(2,5,11,17,23,26),] #delete some columns so df1 and df2 are of different size

我希望对于 df2$C,当找到 NA 值时,对应的 df2$A 和 df2$B 值都与所有 df1$A 和 df2$B 匹配。当且仅当在 df1 中找到匹配 df1$A 和 df1$B 的行时,将 df1$C 的相应值复制到 df2$C NA 值中。换句话说,对于上面的示例数据,如果 df2$C 中有一个 NA 值,则该特定行的日期和时间的相应组合应该与来自 d​​f1 的所有结果串联的日期和时间相匹配,并且当匹配找到后,用df1$C对应的值代替df2$C中的NA。

# as an instance, a case of my df2 where a NA occurs is
df2[17,3] 

#This should be replaced with the value from
df1[21,3] 

# because the time and date of 
df2[17,] 

A          B          C          E 
"20210921"    "11:00"         NA     "U 46" 

#is the same than 
df1[21,] 

A          B          C          D 
"20210921"    "11:00"       "46"        "U" 

我 100% 确定每个 data.frame 中的 A 列和 B 列的串联会在每个 data.frame 中给出唯一的结果,因此 df1$A 和 df1$B 的串联将是唯一的,同样适用到df2。此外,可以肯定的是,df2$A 和 df2$B 的串联将产生一个且唯一的值,该值与 df1 中列 A 和 B 的串联相匹配。出于这个原因,我尝试将每个 data.frames 列 A 和 B 连接到一个新列中,以在 Base R 的 elseif 循环中使用 match(paste(...,...)) 查找匹配值,或者使用其他论坛中提出的 dplyr 库的其他解决方案,但我找不到适合我的解决方案。我认为这类似于具有多个条件的 Excel 查找/vlookup 函数,但我无法在 R 中弄清楚这一点。

关于如何进行的任何建议?谢谢。

【问题讨论】:

  • 首先,您缺少“A”的代码。第二件事,如果您将所需的输出作为代码发布,那么帮助您会容易得多。换句话说,向我们展示您想要的输出应该是什么样子。
  • 我已经编辑了问题和代码。

标签: r dataframe replace na


【解决方案1】:

您可以创建一个唯一的密钥来更新df2

unique_key1 <- paste(df1$A, df1$B)
unique_key2 <- paste(df2$A, df2$B)
inds <- is.na(df2$C)
df2$C[inds] <- df1$C[match(unique_key2[inds], unique_key1)]
df2

#         A     B  C    E
#1  20210901 15:00 74 A 74
#2  20210903 17:00 27 C 27
#3  20210904 18:00 60 D 60
#4  20210906 20:00  7  F 7
#5  20210907 21:00 96 G 96
#6  20210908 22:00 98 H 98
#7  20210909 23:00 38 I 38
#8  20210910 00:00 89 J 89
#9  20210912 02:00 69 L 69
#10 20210913 03:00 72 M 72
#11 20210914 04:00 76 N 76
#12 20210915 05:00 63 O 63
#13 20210916 06:00 13 P 13
#14 20210918 08:00 25 R 25
#15 20210919 09:00 92 S 92
#16 20210920 10:00 21 T 21
#17 20210921 11:00 79 U 79
#18 20210922 12:00 41 V 41
#19 20210924 14:00 97 X 97
#20 20210925 15:00 16 Y 16

数据

cbind 创建矩阵,使用data.frame 创建数据框。

df1 <- data.frame(A, B, C, D)
df2 <- data.frame(A, B, C, E)

【讨论】:

  • 感谢 Ronak 提供的这个解决方案对我来说非常有效。该解决方案与我最初尝试使用elseif() 函数所做的非常相似,但由于某些原因,生成的df2$C 留下了几个NAs,尽管df1$C 中有值可供替换。这是我的df2$C &lt;- ifelse(is.na(df2$C), match(paste(df1$A, df1$B), paste(df2$A, df2$B)), df2$C),但我不知道为什么它不起作用。
【解决方案2】:

既然你已经提到了dplyr;它为这项工作提供了工具。只需在您希望匹配的列上left_join,然后coalesce 将结果中的“C”缺失值替换为第二个表中的匹配值。

library(dplyr)
df1 <- as.data.frame(df1)
df2 <- as.data.frame(df2)

concatenate <- df2 %>%
    left_join(df1, by = c('A', 'B'), suffix = c('', '.y')) %>%
    mutate(C = coalesce(C, C.y)) %>%
    select(-c(C.y))

【讨论】:

  • 感谢 Colin 提供的这个解决方案对我来说非常好用。在我上面提供的示例数据中,我忘记了 as.data.frame(),因为我的真实数据已经属于 "data.frame" 类,并且我忽略了问题中的代码。如果我真的要挑剔的话,我会把你代码的最后一行修改为select(-c(C.y, D)),以去掉原来在df2中没有的额外concatenate$D
猜你喜欢
  • 2015-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-23
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 2014-11-04
相关资源
最近更新 更多