在值和 NA 的行顺序序列中寻找中断模式

问题描述 投票:0回答:2

我正在使用一个数据集,其中每一行代表个人使用服务的位置。这还隐式地跟踪某人是否使用服务,因为如果他们没有使用服务,则该月的列值为

NA
。我想根据连续月份列之间的转换来识别个人服务中存在中断(缺勤然后返回)的情况。

换句话说,我特别感兴趣的是确定某人何时从使用服务(一个月的列中有值)转变为不使用服务(随后 1+ 个月的值是

NA
),然后又回到使用服务( 1+ 个后续月份列中的值,前面带有
NA
s)。我希望有一个二进制
TRUE/FALSE
列(“Breaks_in_Service”)。当有人开始提供服务时并不重要(也就是说,
NA
仅在第一个月列包含值之后才重要)。

这是我的数据集的简化版本:

# Sample Data
simp_2021 <- data.frame(
  ID = c(1, 2, 3, 4, 5),
  jan21_ORG_NAME = c("Org A", NA, NA, "Org B", "Org B"),
  feb21_ORG_NAME = c(NA, "Org A", "Org B", NA, "Org B"),
  mar21_ORG_NAME = c(NA, NA, "Org B", "Org D", NA),
  apr21_ORG_NAME = c("Org B", NA, "Org C", NA, "Org E")
)

# Initialize Breaks_in_Service column as FALSE
simp_2021$Breaks_in_Service <- FALSE

# View
print(simp_2021)

预期输出: 在示例数据中,对于 ID 1、4 和 5,Breaks_in_Service 应为

TRUE
,对于 ID 2 和 3,则 Breaks_in_Service 应为
FALSE

我尝试构建一个

for
循环,但它变得混乱并且不起作用:

# Loop over each row to check for breaks in service
for (i in 1:nrow(simp_2021)) {
  row_values <- simp_2021[i, 2:ncol(simp_2021)]  # Extract service columns for the current row
  
  # Initialize flags to track service usage
  in_service <- FALSE
  found_break <- FALSE
  
  # Check transitions within the row
  for (j in 1:(length(row_values) - 1)) {
    current_value <- row_values[[j]]
    next_value <- row_values[[j + 1]]
    
    if (is.na(current_value) && !is.na(next_value)) {
      # Transition from not using service to using service
      in_service <- TRUE
    } else if (!is.na(current_value) && is.na(next_value)) {
      # Transition from using service to not using service
      if (in_service) {
        found_break <- TRUE
        break  # Found a break, no need to check further
      }
    }
  }
  
  # Set Breaks_in_Service based on found breaks
  if (found_break) {
    simp_2021$Breaks_in_Service[i] <- TRUE
  }
}

# View the updated dataframe with the new 'Breaks_in_Service' column
print(simp_2021)
r data-cleaning sequential
2个回答
0
投票

对于某些向量

x

x <- c("Org A", NA, NA, "Org B")

可以计算非 NA 值的“行程编码”

> rle(!is.na(x))
Run Length Encoding
  lengths: int [1:3] 1 2 1
  values : logi [1:3] TRUE FALSE TRUE

如果服务出现中断,则会有超过 1 个 TRUE 值。所以这是一个测试服务中断的函数

break_in_service <- function(x)
    sum(rle(!is.na(x))$values) > 1

您希望为每个 ID 执行此操作。一种方法是在每一行上使用

apply()
,不包括第一列

> apply(simp_2021[,-1], 1, break_in_service)
[1]  TRUE FALSE FALSE  TRUE  TRUE

我喜欢使用 dplyr / tidyr 的“整洁”方法

library(tidyr); library(dplyr)
simp_2021 |>
    ## convert to 'long' format, where each row is an ID, name, value tuple
    pivot_longer(ends_with("ORG_NAME")) |>
    ## identify the groups in your data
    group_by(ID) |>
    ## summarize each group
    summarize(has_break_in_service = break_in_service(value))

结果是

> simp_2021 |>
+     ## convert to 'long' format
+     pivot_longer(ends_with("ORG_NAME")) |>
+     ## identify the groups in your data
+     group_by(ID) |>
+     ## summarize each group
+     summarize(has_break_in_service = break_in_service(value))
# A tibble: 5 × 2
     ID has_break_in_service
  <dbl> <lgl>
1     1 TRUE
2     2 FALSE
3     3 FALSE
4     4 TRUE
5     5 TRUE

0
投票

首先,您可以使用

NA
将月份列等于
is.na()
并创建二进制字符串,接下来
sub
去掉所有起始
1
,最后
grepl
用于模式
10

> (tmp <- apply(+is.na(simp_2021[-1]), 1, paste, collapse=''))
[1] "01100" "10110" "10000" "01010" "00100"
> (tmp <- sub(tmp, pat='^1+', rep=0))
[1] "01100" "00110" "00000" "01010" "00100"
> (tmp <- grepl(tmp, pat='10'))
[1]  TRUE  TRUE FALSE  TRUE  TRUE

完全在一个漂亮的管道中。

> transform(simp_2021, 
+           Breaks_in_Service=apply(+is.na(simp_2021[-1]), 1, paste, collapse='') |> 
+             sub(pat='^1+', rep=0) |> 
+             grepl(pat='10'))
  ID jan21_ORG_NAME feb21_ORG_NAME mar21_ORG_NAME apr21_ORG_NAME Breaks_in_Service
1  1          Org A           <NA>           <NA>          Org B              TRUE
2  2           <NA>          Org A           <NA>           <NA>              TRUE
3  3           <NA>          Org B          Org B          Org C             FALSE
4  4          Org B           <NA>          Org D           <NA>              TRUE
5  5          Org B          Org B           <NA>          Org E              TRUE

注意: 这种方法也使用行方式

apply
,但是在
"matrix"
上,它是专为它设计的,因此非常高效。

> is.matrix(+is.na(simp_2021[-1]))
[1] TRUE

数据:

> dput(simp_2021)
structure(list(ID = c(1, 2, 3, 4, 5), jan21_ORG_NAME = c("Org A", 
NA, NA, "Org B", "Org B"), feb21_ORG_NAME = c(NA, "Org A", "Org B", 
NA, "Org B"), mar21_ORG_NAME = c(NA, NA, "Org B", "Org D", NA
), apr21_ORG_NAME = c("Org B", NA, "Org C", NA, "Org E")), class = "data.frame", row.names = c(NA, 
-5L))
© www.soinside.com 2019 - 2024. All rights reserved.