【问题标题】:Fill with NA's until a number, after that fill with 0填写 NA 直到一个数字,然后填写 0
【发布时间】:2020-02-13 05:24:38
【问题描述】:

我需要在时间序列中出现一个数字后将 NA 转换为 0。这是一个例子:

c1 <- c(1,NA,NA,NA,NA,1,2,NA,NA,NA,5,NA,NA)
c2 <- c(2,NA,NA,10,30,NA,NA,NA,NA,4,1,2,NA)
c3 <- c(3,NA,NA,NA,NA,NA,NA,NA,NA,1,NA,NA,NA)
x <- data.frame(rbind(c1,c2,c3))
colnames(x) <- c("ID","Jan01","Feb01","Mar01","Apr01","May01","Jun01","Jul01","Aug01","Sep01","Oct01","Nov01","Dec01")
x

#    ID Jan01 Feb01 Mar01 Apr01 May01 Jun01 Jul01 Aug01 Sep01 Oct01 Nov01 Dec01
# c1  1    NA    NA    NA    NA     1     2    NA    NA    NA     5    NA    NA
# c2  2    NA    NA    10    30    NA    NA    NA    NA     4     1     2    NA
# c3  3    NA    NA    NA    NA    NA    NA    NA    NA     1     NA   NA    NA

这是我所期望的:

c11 <- c(1,NA,NA,NA,NA,1,2,0,0,0,5,0,0)
c22 <- c(2,NA,NA,10,30,0,0,0,0,4,1,2,0)
c33 <- c(3,NA,NA,NA,NA,NA,NA,NA,NA,1,0,0,0)
y <- data.frame(rbind(c11,c22,c33))
colnames(y) <- c("ID","Jan01","Feb01","Mar01","Apr01","May01","Jun01","Jul01","Aug01","Sep01","Oct01","Nov01","Dec01")
y

#     ID Jan01 Feb01 Mar01 Apr01 May01 Jun01 Jul01 Aug01 Sep01 Oct01 Nov01 Dec01
# c11  1    NA    NA    NA    NA     1     2     0     0     0     5     0     0
# c22  2    NA    NA    10    30     0     0     0     0     4     1     2     0
# c33  3    NA    NA    NA    NA    NA    NA    NA    NA     1     0     0     0

有人知道怎么做吗?谢谢!

【问题讨论】:

  • 那么timeserie中出现一个数字后表示每行有一个数字?第 1 行 2 号,第 2 行 30 号?

标签: r na


【解决方案1】:

base 选项:

t(apply(x[,-1], 1, function(x) ifelse(is.na(x) & cumsum(!is.na(x)) >= 1, 0, x)))

输出:

   Jan01 Feb01 Mar01 Apr01 May01 Jun01 Jul01 Aug01 Sep01 Oct01 Nov01 Dec01
c1    NA    NA    NA    NA     1     2     0     0     0     5     0     0
c2    NA    NA    10    30     0     0     0     0     4     1     2     0
c3    NA    NA    NA    NA    NA    NA    NA    NA     1     0     0     0

正如@markus 指出的那样,为了提高性能,请使用replace 而不是ifelse,例如:

t(apply(x[,-1], 1, function(x) replace(x, is.na(x) & cumsum(!is.na(x)) >= 1, 0)))

【讨论】:

  • 也许效率更高一点的是... function(x) replace(x, is.na(x) &amp; cumsum(!is.na(x)) &gt;= 1, 0)
【解决方案2】:

在替换 NA 以匹配您所需的输出后,我转回“宽”形式,但作为旁注,最好还是以长形式存储它。

library(dplyr)

long <- 
  x %>% 
    pivot_longer(-ID) %>% 
    group_by(ID) %>% 
    mutate(value = ifelse(cummax(!is.na(value)), coalesce(value, 0), value))

long %>% 
  pivot_wider(ID, name)


# # A tibble: 3 x 13
# # Groups:   ID [3]
#      ID Jan01 Feb01 Mar01 Apr01 May01 Jun01 Jul01 Aug01 Sep01 Oct01 Nov01
#   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1     1    NA    NA    NA    NA     1     2     0     0     0     5     0
# 2     2    NA    NA    10    30     0     0     0     0     4     1     2
# 3     3    NA    NA    NA    NA    NA    NA    NA    NA     1     0     0
# # ... with 1 more variable: Dec01 <dbl>

【讨论】:

    【解决方案3】:

    另一个基本 R 解决方案,使用 aggregate + col + replace,即,

    idx <- aggregate(col~row,which(!is.na(x[-1]),arr.ind = T),min)
    xout <- cbind(x[1],replace(x[-1],col(x[-1])>=idx$col & is.na(x[-1]),0))
    

    这样

    > xout
       ID Jan01 Feb01 Mar01 Apr01 May01 Jun01 Jul01 Aug01 Sep01 Oct01 Nov01 Dec01
    c1  1    NA    NA    NA    NA     1     2     0     0     0     5     0     0
    c2  2    NA    NA    10    30     0     0     0     0     4     1     2     0
    c3  3    NA    NA    NA    NA    NA    NA    NA    NA     1     0     0     0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-28
      • 1970-01-01
      • 2018-01-05
      • 1970-01-01
      相关资源
      最近更新 更多