首页 > 解决方案 > 给定多个条件,为分组变量的所有行赋值

问题描述

我有一个带有分组 ID 变量的数据框。对于每个分组 ID 中的每条记录,我们需要根据另一列的条件为新列分配一个值,该值是我们的“最终值”。我通常以循环的方式来做这类事情,虽然效率低下,但对我来说通常影响不大,但这里的数据很大,而且需要的时间太长。如何转换以下逻辑以应用函数族以提高效率?我很难理解这些功能。

library(data.table)
df <- data.frame("Group_ID" = c(1,1,2,2), "Values" = c("A", "B", "B", "C"))

df_list <- list()
for(grp_id in levels(unique(as.factor(df$Group_ID)))){
  grp <- df[df$Group_ID == grp_id, ]
  vals <- droplevels(unique(as.factor(grp$Values)))
  
  if("C" %in% vals){
    final_value <- "C"
  } else if("B" %in% vals){
    final_value <- "B"
  } else{
    final_value <- "A"
  }
  
  grp$Final_Value <- final_value
  df_list[[grp_id]] <- grp
}
new_df <- rbindlist(df_list)

标签: r

解决方案


这是一种可能适合您的基本 R 方法。我将添加进一步的解释,并希望这会有所帮助。

首先,获取您的Values列并转换为有序因子:

df$Values <- ordered(df$Values, levels = c("C", "B", "A"))

有序因子对于有序或有序数据很有用。这里的级别有方向标志(在本例中为<),表明它是有序的。

R> df$Values

[1] A B B C
Levels: C < B < A

这有助于指定“C”、“B”和“A”的优先级值。

然后我们使用ave, 并指定FUN要使用的函数作为min最小值:

df$Final_Value <- ave(df$Values, df$Group_ID, FUN = min)

这是有关如何与ave. 首先,ave函数是这样的:

function (x, ..., FUN = mean) 
{
  if (missing(...)) 
    x[] <- FUN(x)
  else {
    g <- interaction(...)
    split(x, g) <- lapply(split(x, g), FUN)
  }
  x
}

这个函数将首先split按组给定一个向量(所以我们可以对每个组应用一些函数)。在我们的例子中,我们希望每个人Group_ID独立工作。如果我们split使用整个数据框,我们将拥有:

R> split(df, df$Group_ID)

$`1`
  Group_ID Values
1        1      A
2        1      B

$`2`
  Group_ID Values
3        2      B
4        2      C

在我们的例子中,如果split我们df$Values得到:

R> split(df$Values, df$Group_ID)

$`1`
[1] A B
Levels: C < B < A

$`2`
[1] B C
Levels: C < B < A

请注意,即使在按组拆分后,即使仅存在一些值(例如,仅 A 和 B),每个组也会显示因子(A、B 和 C)的所有级别。

然后,ave用于lapplymin函数应用于这两组中的每一个。lapply将遍历每个组,并使用 确定该组中的最小值min

使用我们的因子,每个级别在背景中都有一个相关的整数值。按照顺序,哪些水平低于或高于其他水平(Levels: C < B < A)是很清楚的。在这种情况下,如果任何值为 C,则结果将为 C,因为这是基于我们的有序级别的最低值。如果最小值为 B,则结果为 B。请注意,无论给定组的最低值是多少,都将包含在该组内的所有行中(例如,如果一个值是 C,那么该组中的所有行都将是 C)。

最后,您只需要:

df$Values <- ordered(df$Values, levels = c("C", "B", "A"))
df$Final_Value <- ave(df$Values, df$Group_ID, FUN = min)

我希望这是有帮助的。

输出

  Group_ID Values Final_Value
1        1      A           B
2        1      B           B
3        2      B           C
4        2      C           C

数据

df <- structure(list(Group_ID = c(1, 1, 2, 2), Values = c("A", "B", 
"B", "C")), class = "data.frame", row.names = c(NA, -4L))

推荐阅读