【问题标题】:Replace 0's with previous non-zero value per ID (lag)用每个 ID 之前的非零值替换 0(滞后)
【发布时间】:2018-11-30 16:11:48
【问题描述】:

如何将所有 0 替换为 R 中每个 ID 的最后一个非零值?

例子:

输入:

df <- data.frame(ID = c(1,1,1,1,1,1,1,2,2,2,2),
         Var1 = c(0,10, 30, 0, 0,50,80,0, 0, 57, 0)) 

输出:

df <- data.frame(ID = c(1,1,1,1,1,1,1,2,2,2,2),
         Var1 = c(0,10, 30, 0, 0,50,80,0, 0, 57, 0),
         res = c(0,10,30,30,30,50,80,0,0,57,57))

有没有简单的滞后功能方法?

【问题讨论】:

  • library(zoo); na.locf(replace(df$Var1, df$Var1 == 0, NA))
  • @RonakShah 当第一个值为 0 时,我得到了一个短向量:10 30 30 30 50 80 80 80 57 57 我怎样才能省略这个,并保持每个 id 的第一个 0
  • @RonakShah 您是否删除了您的答案: library(zoo) df$res
  • 是的,我这样做是因为我没有考虑到每个 ID 的事情。您可以通过@docendo discimus df %&gt;% group_by(ID) %&gt;% mutate(x = na.locf(replace(Var1, cumsum(Var1 !=0) &gt; 0 &amp; Var1 == 0, NA))) 修改答案,这应该会给您预期的输出。
  • 你从哪里得到这些有趣的问题?

标签: r replace lag zero


【解决方案1】:

这是一个 tidyverse 方法:

library(tidyverse)
df %>% 
  group_by(ID) %>% 
  mutate(x = replace(Var1, cumsum(Var1 !=0) > 0 & Var1 == 0, NA)) %>% 
  fill(x)
# # A tibble: 11 x 4
# # Groups:   ID [2]
# ID  Var1   res     x
# <dbl> <dbl> <dbl> <dbl>
# 1    1.    0.    0.    0.
# 2    1.   10.   10.   10.
# 3    1.   30.   30.   30.
# 4    1.    0.   30.   30.
# 5    1.    0.   30.   30.
# 6    1.   50.   50.   50.
# 7    1.   80.   80.   80.
# 8    2.    0.    0.    0.
# 9    2.    0.    0.    0.
# 10    2.   57.   57.   57.
# 11    2.    0.   57.   57.

在变异步骤中,我们将 0 替换为 NA,除了在每个 ID 运行开始时的那些,因为在这些情况下,我们没有值可以在之后替换 NA。


如果要调整多列,可以使用:

df %>% 
  group_by(ID) %>% 
  mutate_at(vars(starts_with("Var")), 
            funs(replace(., cumsum(. !=0) > 0 & . == 0, NA))) %>% 
  fill(starts_with("Var"))

df 可能在哪里:

df <- data.frame(ID = c(1,1,1,1,1,1,1,2,2,2,2),
                 Var1 = c(0,10, 30, 0, 0,50,80,0, 0, 57, 0),
                 Var2 = c(4,0, 30, 0, 0,50,0,16, 0, 57, 0)) 

【讨论】:

  • 您也可以在答案中添加na.locf 选项。
  • @docendodiscimus 成功了!如何为多列案例调整代码?这是:许多“Var”
【解决方案2】:

不使用任何包,只使用loops

df <- data.frame(ID = c(1,1,1,1,1,1,1,2,2,2,2),
                 Var1 = c(0,10, 30, 0, 0,50,80,0, 0, 57, 0)) 

for(i in 1:nrow(df)){
  if(i!=1){    
    if(df$ID[i-1]==df$ID[i] && df$Var1[i]==0){  # if value is zero and value of current and previous rows ID are same
      if(df$Var1[i-1]!=0){           # If previous value is not zero then store it 
        df$res[i]=df$Var1[i-1]       # Use previous value of var1
        a=0
        a=df$Var1[i-1]
      }else{
        df$res[i]=a     # Use previous value var1
        a=0
      }
    }else{
      df$res[i]=df$Var1[i]  # Use the current value of var1
    }

  }else{
    df$res[i]=df$Var1[i]    # Set the first point as it is
  }
}

输出:

> df
      ID Var1 res
   1   1    0   0
   2   1   10  10
   3   1   30  30
   4   1    0  30
   5   1    0  30
   6   1   50  50
   7   1   80  80
   8   2    0   0
   9   2    0   0
   10  2   57  57
   11  2    0  57

【讨论】:

  • @AM.Garcia:您能否检查一下答案并让我知道您的建议?
  • 在测试 df 下试过并且可以工作。但是我的数据集太大了,循环可能会延迟执行,谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-24
  • 2016-01-20
  • 2016-03-06
  • 2021-10-07
  • 2020-04-05
  • 1970-01-01
相关资源
最近更新 更多