通过比较跨行的两个变量的值来创建组 ID:在 R 中

Creating group ids by comparing values of two variables across rows: in R

我有一个包含两个变量的数据框 (start,end)。想创建一个标识符变量,它按 start 的升序增长,最重要的是,如果 start 的值与 任何其他值的 end 一致,则保持不变数据框中的行

下面是一个简单的数据示例

toy_data <- data.frame(start = c(1,5,6,10,16),
                      end = c(10,9,11,15,17))

我要查找的输出如下:

output_data <- data.frame(start = c(1,10,5,6,16),
                   end = c(10,15,9,11,17),
                   NEW_VAR = c(1,1,2,3,4))

下面的函数应该会为您提供所需的标识符变量 NEW_VAR

identifier <- \(df) {
  x <- array(0L, dim = nrow(df))
  count <- 0L
  my_seq <- seq_len(nrow(df))
  for (i in my_seq) {
    if(!df[i,]$start %in% df$end) {
      x[i] <- my_seq[i] + count
    } else {
      x[i] <- my_seq[i]-1L + count
      count <- count - 1L
    }
  }
  x
}

例子

# your example
toy_data <- data.frame(start = c(1,10,5,6,16),
           end = c(10,15,9,11,17))
toy_data$NEW_VAR <- identifier(toy_data)
# ---------------------
> toy_data$NEW_VAR
[1] 1 1 2 3 4

# other example
toy_data <- data.frame(start = c(1, 2, 2, 4, 16, 21, 18, 3),
                       end = c(16, 2, 21, 2, 2, 2, 3, 1))
toy_data$NEW_VAR <- identifier(toy_data)
# ---------------------
> toy_data$NEW_VAR
[1] 0 0 0 1 1 1 2 2

您可以尝试调整 以按彼此相邻的范围进行分组。功劳完全归功于@r2evans。

在这种情况下,您将使用 expand.grid 来获得 startend 的组合。您可以参考行号 rn 而不是标签。

最后,您可以根据列表中同时出现的行对组进行编号。以enframe开头的最后几行使用tibble/tidyverse。为了匹配组号,我也使用了结果。

希望对您有所帮助。

library(tidyverse)

toy_data <- data.frame(start = c(1,5,6,10,16),
                       end = c(10,9,11,15,17))

toy_data$rn = 1:nrow(toy_data)

eg <- expand.grid(a = seq_len(nrow(toy_data)), b = seq_len(nrow(toy_data)))
eg <- eg[eg$a < eg$b,]

together <- cbind(
  setNames(toy_data[eg$a,], paste0(names(toy_data), "1")),
  setNames(toy_data[eg$b,], paste0(names(toy_data), "2"))
)

together <- subset(together, end1 == start2)

groups <- split(together$rn2, together$rn1)

for (i in toy_data$rn) {
  ind <- (i == names(groups)) | sapply(groups, `%in%`, x = i)
  vals <- groups[ind]
  groups <- c(
    setNames(list(unique(c(i, names(vals), unlist(vals)))), i),
    groups[!ind]
  )
}

min_row <- as.numeric(sapply(groups, min))
ctr <- seq_along(groups)

lapply(ctr[order(match(min_row, ctr))], \(x) toy_data[toy_data$rn %in% groups[[x]], ]) %>%
  enframe() %>%
  unnest(col = value) %>%
  select(-rn)

输出

   name start   end
  <int> <dbl> <dbl>
1     1     1    10
2     1    10    15
3     2     5     9
4     3     6    11
5     4    16    17