【问题标题】:R - how to fill NA's between two corresponding ID's in a dataframeR - 如何在数据框中的两个对应 ID 之间填充 NA
【发布时间】:2018-07-28 07:42:59
【问题描述】:

我正在尝试获取以下数据集并将其转换为第二个。基本上,我正在尝试用该 ID 填写每个 ID 之间的 NA。

每个 ID 对应于两个时间戳,我已将其加入到较大的 date_time 列中。出于重现能力的目的,在连接之间执行 sql(date_time 列非常大)甚至获取原始数据集并在每个 id 之间创建时间戳然后将其加入(我有太多ID 来执行此操作)。我已经成功地完成了这两种方法,但我拥有的数据量需要太多时间。我希望用这个数据集来操作数据。看似很简单的事情,却真的让我很为难。任何帮助,将不胜感激。

当前数据集:

             date_time     id
                <dttm>  <dbl>
 1 2017-01-30 08:00:00     NA
 2 2017-01-30 08:00:01     NA
 3 2017-01-30 08:00:02     1
 4 2017-01-30 08:00:03     NA
 5 2017-01-30 08:00:04     NA
 6 2017-01-30 08:00:05     NA
 7 2017-01-30 08:00:06     NA
 8 2017-01-30 08:00:07     1
 9 2017-01-30 08:00:08     NA
10 2017-01-30 08:00:09     NA
11 2017-01-30 08:00:10     2
12 2017-01-30 08:00:11     NA
13 2017-01-30 08:00:12     NA
14 2017-01-30 08:00:13     NA
15 2017-01-30 08:00:14     2
16 2017-01-30 08:00:15     NA
17 2017-01-30 08:00:16     3
18 2017-01-30 08:00:17     NA
19 2017-01-30 08:00:18     3
20 2017-01-30 08:00:19     NA

所需数据集:

            date_time     id
                <dttm>  <dbl>
 1 2017-01-30 08:00:00     NA
 2 2017-01-30 08:00:01     NA
 3 2017-01-30 08:00:02     1
 4 2017-01-30 08:00:03     1
 5 2017-01-30 08:00:04     1
 6 2017-01-30 08:00:05     1
 7 2017-01-30 08:00:06     1
 8 2017-01-30 08:00:07     1
 9 2017-01-30 08:00:08     NA
10 2017-01-30 08:00:09     NA
11 2017-01-30 08:00:10     2
12 2017-01-30 08:00:11     2
13 2017-01-30 08:00:12     2
14 2017-01-30 08:00:13     2
15 2017-01-30 08:00:14     2
16 2017-01-30 08:00:15     NA
17 2017-01-30 08:00:16     3
18 2017-01-30 08:00:17     3
19 2017-01-30 08:00:18     3
20 2017-01-30 08:00:19     NA

dput() 日期:

structure(list(date_time = structure(c(1485781200, 1485781201, 
1485781202, 1485781203, 1485781204, 1485781205, 1485781206, 1485781207, 
1485781208, 1485781209, 1485781210, 1485781211, 1485781212, 1485781213, 
1485781214, 1485781215, 1485781216, 1485781217, 1485781218, 1485781219
), class = c("POSIXct", "POSIXt"), tzone = ""), trx_id = c(NA_real_, 
NA_real_, 1, NA_real_, NA_real_, NA_real_, NA_real_, 1, 
NA_real_, NA_real_, 2, NA_real_, NA_real_, NA_real_, 2, 
NA_real_, 3, NA_real_, 3, NA_real_)), .Names = c("date_time", 
"trx_id"), row.names = c(NA, -20L), class = c("tbl_df", "tbl", 
"data.frame"))

【问题讨论】:

  • 您可以使用dput 以便我们可以复制示例数据框吗?
  • 使用来自包zoo的函数na.locf
  • @Pdubbs 我添加了 dput() 的输出。我不熟悉包含可重复的示例,所以如果我做的不对,请告诉我。
  • @RuiBarradas 我尝试了 na.locf,但它在 ID 之后填充了 NA(因此,如果有 c(3, NA, NA, 3, NA, NA, 4),它会将其转换为 c(3, 3, 3, 3, 3, 3, 4),这是我不想要的)。我希望数据为c(3, 3, 3, 3, NA, NA, 4)

标签: r data-munging


【解决方案1】:

一种解决方案是使用来自tidyrfill 函数。方法很简单。首先为 prevnext 值创建 2 列。使用fill 填充两列中的缺失值。

现在,对于在 prev_valnext_val 中具有相同值的行,应使用 prev_val 更新值(这意味着这些缺失值在相同的数字之间)

df <-  read.table(text = "sl date_time, value
1 '2017-01-30 08:00:00'     NA
2 '2017-01-30 08:00:01'     NA
3 '2017-01-30 08:00:02'     1
4 '2017-01-30 08:00:03'     NA
5 '2017-01-30 08:00:04'     NA
6 '2017-01-30 08:00:05'     NA
7 '2017-01-30 08:00:06'     NA
8 '2017-01-30 08:00:07'     1
9 '2017-01-30 08:00:08'     NA
10 '2017-01-30 08:00:09'     NA
11 '2017-01-30 08:00:10'     2
12 '2017-01-30 08:00:11'     NA
13 '2017-01-30 08:00:12'     NA
14 '2017-01-30 08:00:13'     NA
15 '2017-01-30 08:00:14'     2
16 '2017-01-30 08:00:15'     NA
17 '2017-01-30 08:00:16'     3
18 '2017-01-30 08:00:17'     NA
19 '2017-01-30 08:00:18'     3
20 '2017-01-30 08:00:19'     NA", header = T, stringsAsFactor = F)

#use fill to find missing values
df %>%
  mutate(prev_val = (value), next_val = (value)) %>%
  fill(prev_val, .direction = "down") %>%
  fill(next_val, .direction = "up") %>%
  mutate(value = ifelse(prev_val == next_val, prev_val, value )) %>%
  select(-prev_val, -next_val)

Result:
   sl          date_time. value
1   1 2017-01-30 08:00:00    NA
2   2 2017-01-30 08:00:01    NA
3   3 2017-01-30 08:00:02     1
4   4 2017-01-30 08:00:03     1
5   5 2017-01-30 08:00:04     1
6   6 2017-01-30 08:00:05     1
7   7 2017-01-30 08:00:06     1
8   8 2017-01-30 08:00:07     1
9   9 2017-01-30 08:00:08    NA
10 10 2017-01-30 08:00:09    NA
11 11 2017-01-30 08:00:10     2
12 12 2017-01-30 08:00:11     2
13 13 2017-01-30 08:00:12     2
14 14 2017-01-30 08:00:13     2
15 15 2017-01-30 08:00:14     2
16 16 2017-01-30 08:00:15    NA
17 17 2017-01-30 08:00:16     3
18 18 2017-01-30 08:00:17     3
19 19 2017-01-30 08:00:18     3
20 20 2017-01-30 08:00:19    NA

【讨论】:

  • 这很好用而且效率很高。谢谢!
【解决方案2】:

这是一个base R 选项。我们split带有'trx_id'的数据集的行序列(一个OP显示为输入数据),得到序列(seq),stack它到两列数据集并将'trx_id'分配给' 'd1' 的 ind' 列基于 'values' 作为来自 'd1' 的索引

d1 <- stack(lapply(split(seq_len(nrow(df1)), df1$trx_id), function(x) seq(x[1], x[2])))
df1$trx_id[d1$values] <- d1$ind
df1$trx_id
#[1] NA NA  1  1  1  1  1  1 NA NA  2  2  2  2  2 NA  3  3  3 NA

【讨论】:

  • 在我的完整数据集上尝试此操作时出现错误。它说Error in seq.default(x[1], x[2]) : 'to' must be a finite number。我正在努力解决这个问题,但它确实适用于我给出的示例代码。
  • @jstauss 这很有趣。你能检查split(seq_len(nrow(df1)), df1$trx_id)的输出吗?
【解决方案3】:

一种非 tidyr 方法,其中 x 是您的 id 列:

x <- c(NA,NA, 1,NA,NA,1, NA, NA, 2, NA, NA,2, NA, 3,NA, NA,3,NA)

timestamps <- paste(unique(x)[!is.na(unique(x))], collapse = "|")

timestamps <- grep(timestamps, x)
timestamps <- matrix(timestamps, ncol = 2, byrow=TRUE)

xmatrix <- apply(timestamps, MARGIN = 1, FUN = function(i) {
  y <- x[i[1]:i[2]]
  y[is.na(y)] <- x[i][1]
  x[i[1]:i[2]] <- y 
  return(x)
})

(x <- apply(xmatrix, 1,FUN = function(z) {

  ifelse(all(is.na(z)), NA, max(z, na.rm=TRUE))
  }))

##  [1] NA NA  1  1  1  1 NA NA  2  2  2  2 NA  3  3  3  3 NA

HTH

【讨论】:

  • 谢谢。试图将其保留在 tidyverse 中,但这效果很好。
猜你喜欢
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
  • 1970-01-01
  • 2022-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
相关资源
最近更新 更多