基于前置和后续值分配矢量值

时间:2018-04-23 20:23:18

标签: r

我在数据框中有一个矢量/列,其虚拟变量如下所示:

2 2 0 0 0 0 1 1 1 0 0 0 0 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 2 2 2 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 2

但我希望看起来像这样:

2 2 3 3 3 3 1 1 1 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 4 4 4 4 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 1 1 1 4 4 4 4 4 4 2

基本上我想替换2之后和3之前的所有0,并替换1之后但2之前的所有0&#4&# 39; S。我该怎么做呢?

请注意,1&2和2之间的0的数量不是恒定的。这也只是大型数据帧的一小部分(> 13,300次观测),但目前该向量中的每个值都是0,1或2。

可重复输入:

x = c(2L, 2L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 2L, 2L, 
2L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 
1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 2L, 2L, 2L, 0L, 0L, 0L, 
0L, 0L, 0L, 0L, 0L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L, 0L, 
2L)

2 个答案:

答案 0 :(得分:2)

由于您需要按顺序处理事物,Reduce在这里很有用。例如

Reduce(function(a, b) {
  if (b==0) {
    if (a==2) {
      3
    } else if (a==1) {
      4
    } else {
      a
    }
  } else {
    b
  }
}, x, accumulate=TRUE)
# [1] 2 2 3 3 3 3 1 1 1 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1
#[33] 1 4 4 4 4 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 1 1 1 4 4 4 4 4 4 2

这假设原始序列中的唯一数字是0,1或2,并且相同的数字永远不会出现在0字符串的两边。

答案 1 :(得分:2)

使用rleinverse.rle

y <- rle(x)
y$values[y$values == 0] <-  y$values[-1][y$values == 0] +2
inverse.rle(y)
# [1] 2 2 3 3 3 3 1 1 1 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 4 4 4 4 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 1 1 1 4 4 4 4 4 4 2    

使用data.table和滚动连接:

library(data.table)
y <- setkey(data.table(z=x+2)[,id:=1:.N][x!=0],id)
x[x==0] <- y[.(1:max(id)),roll=-Inf][x==0,z]
# [1] 2 2 3 3 3 3 1 1 1 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 4 4 4 4 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 1 1 1 4 4 4 4 4 4 2

tidyverse,有点矫枉过正:

x[x==0] <- NA
library(tidyverse)
tibble(x,y=x) %>%
   fill(x,.direction = "up") %>%
   fill(y,.direction = "down") %>%
   mutate(z = case_when(x < y ~3L, x > y ~ 4L, TRUE ~ x)) %>%
   pull(z)

 # [1] 2 2 3 3 3 3 1 1 1 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 4 4 4 4 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 1 1 1 4 4 4 4 4 4 2

最后,使用正则表达式的解决方案:

y <- paste(x,collapse="")
m <- gregexpr("20*1",y)
regmatches(y,m)[[1]] <- chartr("0","3",regmatches(y,m)[[1]])
y <- chartr("0","4",y)
as.numeric(unlist(strsplit(y,"")))

# [1] 2 2 3 3 3 3 1 1 1 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 1 1 1 4 4 4 4 4 4 4 4 2 2 2 3 3 3 3 3 3 3 3 3 3 1 1 1 4 4 4 4 4 4 2