在R中的数据框中填充值?

Posted

技术标签:

【中文标题】在R中的数据框中填充值?【英文标题】:Filling in values in a data frame in R? 【发布时间】:2016-09-07 05:25:46 【问题描述】:

假设我有这个数据框:

  times vals
1     1    2
2     3    4
3     7    6

设置

foo <- data.frame(times=c(1,3,7), vals=c(2,4,6))

我想要这个:

  times vals
1     1    2
2     2    2
3     3    4
4     4    4
5     5    4
6     6    4
7     7    6

也就是说,我要填写1到7的所有时间,并且从不大于给定时间的最晚时间开始填写vals。

我有一些代码可以使用 dplyr 来完成,但它很难看。有更好的建议吗?

library(dplyr)

foo <- merge(foo, data.frame(times=1:max(foo$times)), all.y=TRUE)
foo2 <- merge(foo, foo, by=c(), suffixes=c('', '.1'))

foo2 <- foo2 %>% filter(is.na(vals) & !is.na(vals.1) & times.1 <= times) %>%
  group_by(times) %>% arrange(-times.1) %>% mutate(rn = row_number()) %>%
  filter(rn == 1) %>%
  mutate(vals = vals.1,
         rn = NULL,
         vals.1 = NULL,
         times.1 = NULL)

foo <- merge(foo, foo2, by=c('times'), all.x=TRUE, suffixes=c('', '.2'))
foo <- mutate(foo,
              vals = ifelse(is.na(vals), vals.2, vals),
              vals.2 = NULL)

【问题讨论】:

data.frame(time = 1:7, vals = foo$vals[findInterval(1:7, foo$times)]) 将适用于 NA,因为 @eddi 认为这是一个如此重要的问题 【参考方案1】:

这是一个标准的滚动连接问题:

library(data.table)

setDT(foo)[.(1:7), on = 'times', roll = T]
#   times vals
#1:     1    2
#2:     2    2
#3:     3    4
#4:     4    4
#5:     5    4
#6:     6    4
#7:     7    6

以上是针对devel版本(1.9.7+)的,它在连接期间对列匹配更智能。对于 1.9.6,您仍然需要为内部表指定列名:

setDT(foo)[.(times = 1:7), on = 'times', roll = T]

【讨论】:

我感谢您的回答,以及您的 cmets 关于他们在 NA 方面的限制的其他答案。仅供参考,我不喜欢 data.table (我发现语法难以阅读),所以我倾向于“the Hadley-verse”(Hadley Wickham 的软件包,如 tidyr、dplyr 等)的解决方案,即使使用它们的局限性。 @dfrankow 当然,np。 Fwiw,这是阅读data.table 语法的一种非常简单的方法,可以理解90% 的语法。 d[i, j, by = b] 读作“取d,应用i,然后通过b 计算j”。【参考方案2】:

这是一个更长更冗长的基本 R 解决方案:

# calculate the number of repetitions needed for vals variable
reps <- c(with(foo, times[2:length(times)]-times[1:length(times)-1]), 1)

# get result
fooDoneIt <- data.frame(times = min(foo$times):max(foo$times),
              vals = rep(foo$vals, reps))

【讨论】:

【参考方案3】:

approx:

data.frame(times = 1:7, 
           vals = unlist(approx(foo, xout = 1:7, method = "constant", f = 0)[2], use.names = F))

  times vals
1     1    2
2     2    2
3     3    4
4     4    4
5     5    4
6     6    4
7     7    6

【讨论】:

很好,我不知道!您也可以强制转换为 data.frame 并更改名称:setNames(data.frame(approx(foo, xout = 1:7, method = "constant", f = 0)), names(foo)) 这与 alistaire 的解决方案存在相同的问题 - 如果开始有 NA,则会失败 更改 foo[2, 'vals'] = NA 并运行它 无论是否在我最初的问题中,指出限制或细微之处都会很有帮助。【参考方案4】:

dplyrtidyr 选项:

library(dplyr)
library(tidyr)

foo %>%
 right_join(data_frame(times = min(foo$times):max(foo$times))) %>%
 fill(vals)
# Joining by: "times"
#   times vals
# 1     1    2
# 2     2    2
# 3     3    4
# 4     4    4
# 5     5    4
# 6     6    4
# 7     7    6

【讨论】:

如果foo$valsNA 开头,则会给出不正确的结果 不正确,只是不是滚动连接。如果你愿意,你可以这样做:if(any(is.na(foo$vals)))foo %&gt;% slice(which(is.na(vals)):(which(is.na(vals)) + 1)) %&gt;% right_join(data_frame(times = seq(.[seq(1, nrow(.), by = 2), 'times'], .[ifelse(nrow(.) &gt; 1, seq(2, nrow(.), by = 2), 1), 'times']))) %&gt;% bind_rows(anti_join(foo %&gt;% right_join(data_frame(times = min(foo$times):max(foo$times))) %&gt;% fill(vals), ., by = 'times')) %&gt;% arrange(times) else foo %&gt;% right_join(data_frame(times = min(foo$times):max(foo$times))) %&gt;% fill(vals) 虽然可能有更优雅的方式。 From OP: "... 并从不大于给定时间的最近时间填写 vals" - 这基本上是滚动的教科书定义加入。我不确定你会如何解释用以前的非 NA 值填充 NA。 没有给出NAs。鉴于此操作会估算数据,拥有它们会有些奇怪,而离开它们会更奇怪。 此答案替换现有数据(如果有 NA),而不是估算不存在的数据。这就是问题所在。替换 foo[2, 'vals'] = NA,然后运行您的答案并观察您是如何丢失这些信息的。

以上是关于在R中的数据框中填充值?的主要内容,如果未能解决你的问题,请参考以下文章

用向量中的随机值填充数据框中的 NA 值(无需替换)

如何根据 pandas 数据框中的数据类型填充 NaN 值?

用上一列中的值填充熊猫数据框中的“无”值

提取特定单元格的值并将其填充以代替 pyspark 数据框中的 NA 值

Python:如何在比较其他列时将列值填充到另一个数据框中的新列?

合并 Pandas 数据框中的 2 列,用前一个值填充 NaN [重复]