【问题标题】:Assigning NAs to rows with conditional statement in r在 r 中使用条件语句将 NA 分配给行
【发布时间】:2020-08-08 20:01:28
【问题描述】:

我正在尝试使用以下条件语句将 NA 分配给每个事件的前两行: 如果每个事件的第一天的值“变量”= 0,请检查前一天。如果前一天(前一个事件的最后一天)的“变量”> 0,则将 NA 分配给第一天“变量”= 0 的事件的前两行。如果前一天有一个“变量”= 0,则什么也不做。

这是一个例子:

day <- c(1:16)
event<- c(1,1,2,3,4,4,4,5,5,5,6,6,6,7,7,7)
variable<- c(0,0,5,0,0,0,10,0,1,1,0,0,0,0,0,0)
A<- data.frame(day, event, variable)
     day  event  variable
1     1     1        0
2     2     1        0
3     3     2        5
4     4     3        0
5     5     4        0
6     6     4        0
7     7     4       10
8     8     5        0
9     9     5        1
10   10     5        1
11   11     6        0
12   12     6        0
13   13     6        0
14   14     7        0
15   15     7        0
16   16     7        0

它应该是什么样子

     day  event  variable
1     1     1        0
2     2     1        0
3     3     2        5
4     4     3       NA
5     5     4        0
6     6     4        0
7     7     4       10
8     8     5       NA
9     9     5       NA
10   10     5        1
11   11     6       NA
12   12     6       NA
13   13     6        0
14   14     7        0
15   15     7        0
16   16     7        0

注意:事件 1 是否必须分配 NA 并不重要 我尝试在 if 条件下执行此操作,但效果不佳。任何想法?并提前感谢!

【问题讨论】:

    标签: r if-statement dplyr conditional-statements na


    【解决方案1】:

    编辑:来自 OP 的新示例数据

    library(data.table)
    event2<- c(1,2,2,3,4,4,4,4,4,5,5) 
    variable2<- c(140, 0, 69, 569, 28, 0,0,0,100,0,0) 
    desire_output<- c(140, NA, NA, 569, 28, 0,0,0,100, NA,NA) 
    A2<- data.frame(event2, variable2, desire_output) 
    
    setDT(A2)
    
    A2[,first_days_event:=fifelse(.I==min(.I),1,fifelse(.I==min(.I)+1,2,NA_integer_)),by=.(event2)]
    
    A2[,result:={v <- variable2
    for (i in 2:.N) {
      if (is.na(first_days_event[i])) {
        v[i] <- variable2[i]
      } else if (first_days_event[i]==1 & variable2[i]==0){
        if (variable2[i-1]>0) {
          v[i] <- NA_integer_
          if (first_days_event[i+1]==2) {
            v[i+1] <- NA_integer_
          }
        }
      }
    }
    v}]
    A2
    #>     event2 variable2 desire_output first_days_event result
    #>  1:      1       140           140                1    140
    #>  2:      2         0            NA                1     NA
    #>  3:      2        69            NA                2     NA
    #>  4:      3       569           569                1    569
    #>  5:      4        28            28                1     28
    #>  6:      4         0             0                2      0
    #>  7:      4         0             0               NA      0
    #>  8:      4         0             0               NA      0
    #>  9:      4       100           100               NA    100
    #> 10:      5         0            NA                1     NA
    #> 11:      5         0            NA                2     NA
    

    我将使用这个简单的loop 解决方案。只需要创建一个标志来指示每个事件的前两天。

    library(data.table)
    
    day <- c(1:16)
    event<- c(1,1,2,3,4,4,4,5,5,5,6,6,6,7,7,7)
    variable<- c(0,0,5,0,0,0,10,0,1,1,0,0,0,0,0,0)
    A<- data.frame(day, event, variable)
    
    setDT(A)
    
    
    A[,first_days_event:=fifelse(.I==min(.I),1,fifelse(.I==min(.I)+1,2,NA_integer_)),by=.(event)]
    
    A[,result:={v <- numeric(.N)
      for (i in 2:.N) {
        if (is.na(first_days_event[i])) {
          v[i] <- variable[i]
        } else if (first_days_event[i]==1){
          if (variable[i-1]>0) {
            v[i] <- NA_integer_
            if (first_days_event[i+1]==2) {
              v[i+1] <- NA_integer_
            }
          } else {
            v[i] <- variable[i]
          }
        }
      }
    v}]
    
    A
    #>     day event variable first_days_event result
    #>  1:   1     1        0                1      0
    #>  2:   2     1        0                2      0
    #>  3:   3     2        5                1      5
    #>  4:   4     3        0                1     NA
    #>  5:   5     4        0                1      0
    #>  6:   6     4        0                2      0
    #>  7:   7     4       10               NA     10
    #>  8:   8     5        0                1     NA
    #>  9:   9     5        1                2     NA
    #> 10:  10     5        1               NA      1
    #> 11:  11     6        0                1     NA
    #> 12:  12     6        0                2     NA
    #> 13:  13     6        0               NA      0
    #> 14:  14     7        0                1      0
    #> 15:  15     7        0                2      0
    #> 16:  16     7        0               NA      0
    

    【讨论】:

    • 嘿@Frank 谢谢你的回答。它确实适用于该示例,但不适用于所有可能的场景。你能看一下这个例子吗:
    • 事件2
    • 其中的desire_output是我期望的解决方案
    【解决方案2】:

    这是一个潜在的tidyverse 方法。

    您可以将组的最后一个值存储在临时列last_var 中,并使用lag 移动到下一组的第一行进行比较。

    注意lag 中的默认值将决定event 1 中的variable 是0 还是NA

    最后的 mutate 将评估该行是否在组的前 2 行内,并检查 last_var 以确定是否应设置为 NA 或不理会。​​p>

    编辑:对于ifelse,还需要检查该事件的第一天variable是否为0。

    library(tidyverse)
    
    A %>%
      group_by(event) %>%
      mutate(last_var = ifelse(row_number() == n(), last(variable), 0)) %>%
      ungroup %>%
      mutate(last_var = lag(last_var, default = 0)) %>%
      group_by(event) %>%
      mutate(variable = ifelse(row_number() <= 2 & first(last_var) > 0 & first(variable) == 0, NA, variable)) %>%
      select(-last_var)
    

    输出

    # A tibble: 16 x 3
    # Groups:   event [7]
         day event variable
       <int> <dbl>    <dbl>
     1     1     1        0
     2     2     1        0
     3     3     2        5
     4     4     3       NA
     5     5     4        0
     6     6     4        0
     7     7     4       10
     8     8     5       NA
     9     9     5       NA
    10    10     5        1
    11    11     6       NA
    12    12     6       NA
    13    13     6        0
    14    14     7        0
    15    15     7        0
    16    16     7        0
    

    第二个数据框包含在 cmets 中:

    输出

    # A tibble: 11 x 3
    # Groups:   event [5]
       event variable desire_output
       <dbl>    <dbl>         <dbl>
     1     1      140           140
     2     2       NA            NA
     3     2       NA            NA
     4     3      569           569
     5     4       28            28
     6     4        0             0
     7     4        0             0
     8     4        0             0
     9     4      100           100
    10     5       NA            NA
    11     5       NA            NA
    

    【讨论】:

    • 嘿@Ben,感谢您的回答。它确实适用于该示例,但不适用于所有可能的情况。您能否看一下这个示例,并尝试以相同的问题想法运行它。这是示例: event2
    • @Noel 尝试将 mutate 更改为:mutate(variable = ifelse(row_number() &lt;= 2 &amp; first(last_var) &gt; 0 &amp; first(variable) == 0, NA, variable)) ...我编辑了上面的答案,请告诉我...
    猜你喜欢
    • 2021-04-16
    • 2021-09-10
    • 2020-11-06
    • 1970-01-01
    • 2014-10-23
    • 2017-04-17
    • 2020-07-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多