R语言 如何查找特定值的第一个出现并将所有后续值替换为NA

zd287kbt  于 2023-05-11  发布在  其他
关注(0)|答案(5)|浏览(182)

我在R中有以下df,其中列为二进制值(0,1):

'data.frame':   10 obs. of 7 variables:
     $ Round.1: int  0 0 0 1 1 0 0 0 1 0
     $ Round.2: int  0 0 0 0 1 0 0 0 0 0
     $ Round.3: int  0 0 0 0 1 0 0 0 1 0
     $ Round.4: int  0 0 0 1 0 0 0 0 0 0
     $ Round.5: int  0 0 0 1 1 0 0 0 0 0
     $ Round.6: int  0 0 0 0 0 0 1 0 1 0
     $ Round.7: int  0 0 0 0 1 0 1 0 0 0

我想(1)在每列中找到1的第一个发生率,(2)用NA替换列中的所有后续值。
屈服:

'data.frame':   10 obs. of 7 variables:
     $ Round.1: int  0 0 0 1 1 0 0 0 1 0
     $ Round.2: int  0 0 0 NA NA 0 0 0 NA 0
     $ Round.3: int  0 0 0 NA NA 0 0 0 NA 0
     $ Round.4: int  0 0 0 NA NA 0 0 0 NA 0
     $ Round.5: int  0 0 0 NA NA 0 0 0 NA 0
     $ Round.6: int  0 0 0 NA NA 0 1 0 NA 0
     $ Round.7: int  0 0 0 NA NA 0 NA 0 NA 0

任何帮助都非常感谢。

wfveoks0

wfveoks01#

对于每个二进制向量v,我们可以尝试

NA^(seq_along(v) > match(1,v,length(v))) * v

示例

> set.seed(0)

> (df <- as.data.frame(replicate(3, rbinom(10, 1, 0.5))))
   V1 V2 V3
1   1  0  1
2   0  0  1
3   0  0  0
4   1  1  1
5   1  0  0
6   0  1  0
7   1  0  0
8   1  1  0
9   1  1  0
10  1  0  1

> list2DF(lapply(df, \(v) NA^(seq_along(v) > match(1,v,length(v))) * v))
   V1 V2 V3
1   1  0  1
2  NA  0 NA
3  NA  0 NA
4  NA  1 NA
5  NA NA NA
6  NA NA NA
7  NA NA NA
8  NA NA NA
9  NA NA NA
10 NA NA NA
aiazj4mn

aiazj4mn2#

以下是dplyr解决方案:
1.使用match(1, .),我们得到每列中第一个1的索引,否则NA
1.使用row_number(),我们得到一个与列长度相同的向量,包含行号。
1.对于if_else(row_number() > match(1, .), NA_integer_, .),我们将第一个1之后的所有值替换为NA

df <- structure(list(Round.1 = c(0, 0, 0, 1, NA, NA, NA, NA, NA, NA
), Round.2 = c(0, 0, 0, 0, 1, NA, NA, NA, NA, NA), Round.3 = c(0, 
0, 0, 0, 1, NA, NA, NA, NA, NA), Round.4 = c(0, 0, 0, 1, NA, 
NA, NA, NA, NA, NA), Round.5 = c(0, 0, 0, 1, NA, NA, NA, NA, 
NA, NA), Round.6 = c(0, 0, 0, 0, 0, 0, 1, NA, NA, NA), Round.7 = c(0, 
0, 0, 0, 1, NA, NA, NA, NA, NA)), row.names = c(NA, -10L), class = "data.frame")
library(dplyr)

df %>%
  mutate(across(everything(), ~if_else(row_number() > match(1, .), NA_integer_, .)))
Round.1 Round.2 Round.3 Round.4 Round.5 Round.6 Round.7
1        0       0       0       0       0       0       0
2        0       0       0       0       0       0       0
3        0       0       0       0       0       0       0
4        1       0       0       1       1       0       0
5       NA       1       1      NA      NA       0       1
6       NA      NA      NA      NA      NA       0      NA
7       NA      NA      NA      NA      NA       1      NA
8       NA      NA      NA      NA      NA      NA      NA
9       NA      NA      NA      NA      NA      NA      NA
10      NA      NA      NA      NA      NA      NA      NA
wqlqzqxt

wqlqzqxt3#

碱R溶液:

test <- data.frame(
  a = c(0, 0, 0, 1, 0, 0, 1, 0), 
  b = c(0, 0, 1, 0, 0, 1, 0, 0)
)

apply(X = test, MARGIN = 2, FUN = function(x) {
  idx <- match(1, x)
  
  if (!is.na(idx) & idx < length(x)) {
    x[(idx+1):length(x)] <- NA
  }
  
  x
})

# output
      a  b
[1,]  0  0
[2,]  0  0
[3,]  0  1
[4,]  1 NA
[5,] NA NA
[6,] NA NA
[7,] NA NA
[8,] NA NA
xt0899hw

xt0899hw4#

我们可以使用NA replace累加最大值和滞后累加最大值为1的列的所有值,因为replace中的list参数自动将1和0强制为逻辑索引。

library(dplyr)

test <- data.frame(
  a = c(0, 0, 0, 1, 0, 0, 1, 0), 
  b = c(0, 0, 1, 0, 0, 1, 0, 0)
)

test |>
    mutate(across(everything(),
                  \(x) replace(x,
                               cummax(x) & cummax(lag(x, default = 0)),
                               NA)
                  )
           )

   a  b
1  0  0
2  0  0
3  0  1
4  1 NA
5 NA NA
6 NA NA
7 NA NA
8 NA NA
6za6bjd0

6za6bjd05#

使用rollapplyr,其窗口等于直到当前元素的所有元素,检查在它之前是否有任何1,如果是,则输出NA,否则保持当前值。请注意,any应用于空向量会给出FALSE,head(x, -1)表示x的所有元素,除了最后一个。所用的测试输入见末尾的注解。

library(zoo)

fillna <- function(x) if (any(head(x, -1) == 1)) NA else tail(x, 1)
rollapplyr(df, 1:nrow(df), fillna) |> as.data.frame()

给予

V1 V2 V3 V4 V5 V6 V7
1  1  1  0  0  0  1  0
2 NA NA  0  0  1 NA  0
3 NA NA  0  0 NA NA  0
4 NA NA  0  0 NA NA  0
5 NA NA  0  0 NA NA  0
6 NA NA  0  1 NA NA  0
7 NA NA  0 NA NA NA  0

注意事项

Lines <- "
1  1  0  0  0  1  0
0  1  0  0  1  0  0
0  1  0  0  0  1  0
1  0  0  0  0  0  0
1  1  0  0  0  0  0
0  0  0  1  0  1  0
0  1  0  1  0  0  0"
df <- read.table(text = Lines)

相关问题