【问题标题】:How to do a conditional NA fill in R dataframe如何在 R 数据框中进行条件 NA 填充
【发布时间】:2021-04-23 07:36:19
【问题描述】:

这可能很简单,但无法弄清楚。 如何在数据框dt中使用如下条件填充feature列中的NA

填写NA的条件是:

  1. 如果Date的差值是1,则用上一行的值填充NA(很容易通过tidyverse的填充功能完成)
dt_fl<-dt%>%
  fill(feature, .direction = "down")
dt_fl
  1. 如果Date中的差值是&gt;1,则用之前的特征值+1填充NA,并将后面的行(特征值)替换为1增量,使特征值连续。 dt_output 显示了我在填充 NA 值并相应地替换了功能编号后对 dt 的期望。
dt<-structure(list(Date = structure(c(15126, 15127, 15128, 15129, 
                    15130, 15131, 15132, 15133, 15134, 15138, 15139, 15140, 15141, 
                    15142, 15143, 15144, 15145, 15146, 15147, 15148, 15149), class = "Date"), 
                    feature = c(1, 1, 1, 1, 1, 1, 1, 1, NA, NA, NA, NA, NA, NA, 
                    2, 2, 2, 2, 2, 2, NA)), row.names = c(NA, -21L), class = c("tbl_df", 
                    "tbl", "data.frame"))
 dt

dt_output<-structure(list(Date = structure(c(15126, 15127, 15128, 15129, 
          15130, 15131, 15132, 15133, 15134, 15138, 15139, 15140, 15141, 
          15142, 15143, 15144, 15145, 15146, 15147, 15148, 15149), class = "Date"), 
          feature = c(1, 1, 1, 1, 1, 1, 1, 1, NA, NA, NA, NA, NA, NA, 
          2, 2, 2, 2, 2, 2, NA), finaloutput = c(1, 1, 1, 1, 1, 1, 
          1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3)), row.names = c(NA, 
           -21L), spec = structure(list(cols = list(Date = structure(list(), class = c("collector_character", 
          "collector")), feature = structure(list(), class = c("collector_double", 
            "collector")), finaloutput = structure(list(), class = c("collector_double", 
          "collector"))), default = structure(list(), class = c("collector_guess", 
          "collector")), skip = 1L), class = "col_spec"), class = c("spec_tbl_df", 
          "tbl_df", "tbl", "data.frame"))
dt_output

另外,按照 Ben 的建议,如果数据框以 NA 中的 dt2 功能开头,如何解决? dt2 的预期输出在 dt2_output

  dt2<-structure(list(Date = structure(c(13675, 13676, 13677, 13678, 
      13679, 13689, 13690, 13691, 13692, 13693, 13694, 13695), class = "Date"), 
    feature = c(NA, NA, NA, NA, NA, 1, 1, 1, 1, 1, NA, 2)), row.names = c(NA, 
    -12L), class = c("tbl_df", "tbl", "data.frame"))
dt2_output<-structure(list(Date = structure(c(13675, 13676, 13677, 13678, 
              13679, 13689, 13690, 13691, 13692, 13693, 13694, 13695), class = "Date"), 
              feature = c(NA, NA, NA, NA, NA, 1, 1, 1, 1, 1, NA, 2), output_feature = c(1, 
              1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3)), row.names = c(NA, -12L
              ), spec = structure(list(cols = list(Date = structure(list(), class = c("collector_character", 
              "collector")), feature = structure(list(), class = c("collector_double", 
              "collector")), output_feature = structure(list(), class = c("collector_double", 
              "collector"))), default = structure(list(), class = c("collector_guess", 
              "collector")), skip = 1L), class = "col_spec"), class = c("spec_tbl_df", 
              "tbl_df", "tbl", "data.frame"))

Ben 提供的解决方案适用于所有条件,除了dt3(下)中的 1 个条件,只是想知道为什么会这样。我的假设是第二种解决方案应该为dt3 提供dt3_expected

dt3<-structure(list(Date = structure(c(10063, 10064, 10065, 10066, 
     10067, 10068, 10069, 10070, 10079, 10080, 10081, 10082, 10083, 
     10084, 10085, 10086, 10087, 10088, 10089), class = "Date"), feature = c(1, 
     1, 1, 1, 1, 1, 1, NA, NA, 2, 2, 2, 2, 2, 2, 2, 2, 2, NA)), row.names = c(NA, 
    -19L), class = c("tbl_df", "tbl", "data.frame"))

dt3

dt3_expected<-structure(list(Date = structure(c(10063, 10064, 10065, 10066, 
10067, 10068, 10069, 10070, 10079, 10080, 10081, 10082, 10083, 
10084, 10085, 10086, 10087, 10088, 10089), class = "Date"), feature = c(1, 
1, 1, 1, 1, 1, 1, NA, NA, 2, 2, 2, 2, 2, 2, 2, 2, 2, NA), output_feature = c(1, 
 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2)), row.names = c(NA, 
-19L), spec = structure(list(cols = list(Date = structure(list(), class = c("collector_character", 
 "collector")), feature = structure(list(), class = c("collector_double", 
"collector")), output_feature = structure(list(), class = c("collector_double", 
  "collector"))), default = structure(list(), class = c("collector_guess", 
  "collector")), skip = 1L), class = "col_spec"), class = c("spec_tbl_df", 
  "tbl_df", "tbl", "data.frame"))

非常感谢您的帮助,谢谢。

【问题讨论】:

  • 还添加了 dt2 的预期输出。
  • 谢谢 - 请查看编辑后的答案,如果这对你有用,请告诉我。
  • 很棒的解决方案 Ben,但是,它在其中一种情况下不开心,我不知道为什么。我已经修改了输出与我预期不同的第 3 个条件的问题。
  • 我想我可能对确定feature 值的逻辑有点困惑。在第一个 dt 中,NA 在 2011 年 6 月 17 日变成了 2,然后在 2011 年 6 月 18 日变成了 3(即使没有日期差异)。但是,在dt3 中,NA 于 97 年 8 月 6 日与 97 年 8 月 7 日共享相同的 output_feature 2。为什么output_featuredt3 中的 8/6/97 和 8/7/97 相同,但在 2011 年 6 月 17 日和 2011 年 6 月 18 日的 dt 中却不相同?
  • 这些是空间特征,因此日期间隔不起作用。每个功能都应该 >=5 天。在 dt 中有 >5 NA 但在 dt3 填充第一个值后只有 1 NA,因此它是以下功能的一部分。所以条件是:(I)如果 Date 的差异是 1,用上一行的值填充 NA(ii)如果 Date 的差异 >1 并且只有 2NA,用最后一个前一个特征和第二个填充第一个 NA首先通过以下特征和(iii)如果Date中的差异> 1,并且有超过2个NA,则用先前的特征值+1填充NA

标签: r dataframe tidyverse na


【解决方案1】:

您可以尝试创建一个“偏移量”,只要您有缺失值且日期差异大于 1 天,就会添加该偏移量。可以将此累积偏移量添加到您的feature 值以确定finaloutput

dt %>%
  mutate(offset = cumsum(is.na(feature) & Date - lag(Date) > 1)) %>%
  fill(feature, .direction = "down") %>%
  mutate(finaloutput = feature + offset)

输出

# A tibble: 21 x 4
   Date       feature offset finaloutput
   <date>       <dbl>  <int>       <dbl>
 1 2011-06-01       1      0           1
 2 2011-06-02       1      0           1
 3 2011-06-03       1      0           1
 4 2011-06-04       1      0           1
 5 2011-06-05       1      0           1
 6 2011-06-06       1      0           1
 7 2011-06-07       1      0           1
 8 2011-06-08       1      0           1
 9 2011-06-09       1      0           1
10 2011-06-13       1      1           2
11 2011-06-14       1      1           2
12 2011-06-15       1      1           2
13 2011-06-16       1      1           2
14 2011-06-17       1      1           2
15 2011-06-18       2      1           3
16 2011-06-19       2      1           3
17 2011-06-20       2      1           3
18 2011-06-21       2      1           3
19 2011-06-22       2      1           3
20 2011-06-23       2      1           3
21 2011-06-24       2      1           3

编辑:对于以NA 开头的第二个示例dt2,您可以尝试以下操作。

首先,您可以为lag 添加default。如果第一行是NA,它将评估Date 的差异。由于没有之前的 Date 可比较,您可以使用超过 1 天的默认值,以便添加偏移量,这些初始 NA 将被视为“第一个”feature

第二个问题是当你不能在向下方向fill 时填写NA(当它以NA 开头时没有先前的feature 值)。您可以将这些替换为 0。给定 offset,这将变为 0 + 1 = 1 的 finaloutput

dt2 %>%
  mutate(offset = cumsum(is.na(feature) & Date - lag(Date, default = first(Date) - 2) > 1)) %>%
  fill(feature, .direction = "down") %>%
  replace_na(list(feature = 0)) %>%
  mutate(finaloutput = feature + offset)

输出

   Date       feature offset finaloutput
   <date>       <dbl>  <int>       <dbl>
 1 2007-06-11       0      1           1
 2 2007-06-12       0      1           1
 3 2007-06-13       0      1           1
 4 2007-06-14       0      1           1
 5 2007-06-15       0      1           1
 6 2007-06-25       1      1           2
 7 2007-06-26       1      1           2
 8 2007-06-27       1      1           2
 9 2007-06-28       1      1           2
10 2007-06-29       1      1           2
11 2007-06-30       1      1           2
12 2007-07-01       2      1           3

编辑:有附加评论,需要考虑一个附加标准。

如果Date 的差值> 1 且只有2 个NA,则第一个NA 应由前一个特征填充,第二个由后一个特征填充。尤其是 2 个NA 中的第二个有差距的地方应该以不同的方式处理。

对此的一种方法是计算连续的NA 的数量。然后,可以针对这种特殊情况填写 feature,其中两个 NA 中的第二个用 Date 间隔标识。

dt3 %>%
  mutate(grp = cumsum(c(1, abs(diff(is.na(feature))) == 1))) %>%
  add_count(grp) %>%
  ungroup %>%
  mutate(feature = ifelse(is.na(feature) & n == 2 & is.na(lag(feature)), lead(feature), feature)) %>%
  mutate(offset = cumsum(is.na(feature) & Date - lag(Date, default = first(Date) - 2) > 1)) %>%
  fill(feature, .direction = "down") %>%
  replace_na(list(feature = 0)) %>%
  mutate(finaloutput = feature + offset)

输出

   Date       feature   grp     n offset finaloutput
   <date>       <dbl> <dbl> <int>  <int>       <dbl>
 1 1997-07-21       1     1     7      0           1
 2 1997-07-22       1     1     7      0           1
 3 1997-07-23       1     1     7      0           1
 4 1997-07-24       1     1     7      0           1
 5 1997-07-25       1     1     7      0           1
 6 1997-07-26       1     1     7      0           1
 7 1997-07-27       1     1     7      0           1
 8 1997-07-28       1     2     2      0           1
 9 1997-08-06       2     2     2      0           2
10 1997-08-07       2     3     9      0           2
11 1997-08-08       2     3     9      0           2
12 1997-08-09       2     3     9      0           2
13 1997-08-10       2     3     9      0           2
14 1997-08-11       2     3     9      0           2
15 1997-08-12       2     3     9      0           2
16 1997-08-13       2     3     9      0           2
17 1997-08-14       2     3     9      0           2
18 1997-08-15       2     3     9      0           2
19 1997-08-16       2     4     1      0           2

请注意,这可以简化;但在这样做之前,需要确保这符合您的需求。

【讨论】:

  • 您能否使用以NA 开头的功能的示例来编辑您的问题 - 以及在这种情况下所需的结果应该是什么样的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多