数据表聚合中的条件因子水平选择

Conditional Factor Level Selection in Aggregation of Data Table

提问人:Hack-R 提问时间:2/6/2016 最后编辑:Hack-R 更新时间:2/6/2016 访问量:82

问:

我正在尝试将每个 ID 聚合为 1 行。data.table

假设第一列表示 ID,最后一列是感兴趣的因子:

mydt <- data.table(matrix(c(1,2,"Level 1", 1,12,"Level 0", 1,12,"Level 0", 2,12,"Level 3", 2,12,"Level 2"), nrow = 5, ncol = 3, byrow = TRUE))
mydt
   V1 V2      V3
1:  1  2 Level 1
2:  1 12 Level 0
3:  1 12 Level 0
4:  2 12 Level 3
5:  2 12 Level 2

对于如何聚合因子,我有非直观的规则:

  • 如果任何 ID 行存在,则聚合行应具有该 IDLevel 1Level 1
  • 如果没有,则如果该 ID 存在,则使用它Level 2
  • 如果没有,那么如果它存在Level 3
  • 如果没有,那么Level 0

实际值非常大,实际因子水平没有数字分量,它们只是字符串。此脚本每天至少运行一次,因此我试图避免使用循环进行缓慢的预处理。data.table

所需的结果如下所示:

   V1 V2      V3
1:  1  8.67 Level 1
2:  2 12 Level 2

但是,我找不到合适的聚合函数......

mydt[,.(V2 = mean(V2, na.rm = T), V3 = if("Level 1") "Level 1" else if("idk help me out?")), by = "V1"]
r 数据表

评论

1赞 MichaelChirico 2/6/2016
我假设您的数据没有像最初那样存储(您正在使用时没有表明是这种情况)?用于声明您的示例在混合时删除非类型。最好按列指定,例如charactermean(V2)as.numericmatrixcharactermydt <- data.table(V1 = rep(1:2, c(3,2)), V2 = rep(c(2, 12), c(1, 4)), V3 = factor(paste0("Level", c(1,0,0,3,2))))
2赞 Frank 2/6/2016
是的,Michael 说的:不要对混合数据类型(在本例中为字符串和数字)使用矩阵。你也可以做mydt = rbindlist(list( list(1,2,"Level 0"), list(1,12,"Level 0"), list(1,12,"Level 0"), list(2,12,"Level 3"), list(2,12,"Level 2") ))

答:

3赞 akrun 2/6/2016 #1

我们可以将“V3”转换为按指定顺序指定的。factorlevels

mydt[, V3:= factor(V3, levels=c('Level 1', 'Level 2', 'Level 3',
 'Level 0'))][, list(V2= mean(as.numeric(V2)),
                     V3= V3[which.min(V3)]) , V1]
#   V1        V2      V3
#1:  1  8.666667 Level 1
#2:  2 12.000000 Level 2

或者另一种选择是通过与向量匹配(按特定顺序排列)来获取数字索引,获取最小值的索引,获取相应的“V3”值,按“V1”分组。至于“V2”,它只是“V2”的(OP 帖子中显示的示例将“V2”列作为“字符”类 - 所以必须换行)。matchmeanas.numeric

lvls <- paste('Level', c(1:3, 0))
mydt[, list(V2= mean(as.numeric(V2)), 
             V3= V3[which.min(match(V3, lvls))]) , V1]
3赞 MichaelChirico 2/6/2016 #2

我会用您指定的顺序指定为一个因素,然后简单地按顺序完成剩下的工作:V3V3

mydt[ , V3 := factor(V3, paste("Level", c(1:3, 0)))]

mydt[order(V3), V3 := V3[1L], by = V1][]
   V1 V2      V3
1:  1  2 Level 1
2:  1 12 Level 1
3:  1 12 Level 1
4:  2 12 Level 2
5:  2 12 Level 2

如果要聚合到较小的表,则有效:

mydt[order(V3), .(V2 = mean(as.numeric(V2), na.rm = TRUE),
                      V3 = V3[1L]), by = V1]
   V1        V2      V3
1:  1  8.666667 Level 1
2:  2 12.000000 Level 2

请注意,由于 GForce 工作方式的特殊性,以下内容(最初由 @Frank 提出,并且本着 @akrun 方法的精神提出了更多建议)是一个错误(至少在当前版本中):data.table

mydt[, .(V2 = mean(as.numeric(V2), na.rm = TRUE),
         V3 = min(V3)), by = V1]

但事实并非如此:

mydt[, V2 := as.numeric(V2)][, .(V2 = mean(V2, na.rm = TRUE),
                                 V3 = min(V3)), by = V1]

基本上,后一种情况使用 的内部优化函数,该函数适用于 s,而前一种情况,因为至少有一个调用不是直接调用 GForce 函数,因此诉诸于 ,它不适用于 s (cf )。gmindata.tableminfactorbaseminfactormin(factor(1:3))

既然我认为您实际上已经首先存储在您的数据中,那么这种方法可能会更好。V2numericmin

评论

0赞 MichaelChirico 2/6/2016
@akrun是这样(很难看出如何在不设置顺序的情况下有效地做到这一点),但我更喜欢我的。 似乎注定会慢一些。factorwhich.min
0赞 Frank 2/6/2016
不知道阿克伦的评论是什么,但似乎是一种令人费解的到达方式..?我的意思是喜欢(假设 V2 早些时候被转换为数字)。DT[order(x), x[1]]min(x)mydt[, .(V2 = mean(V2), V3 = min(V3)), by=V1]
0赞 Frank 2/6/2016
然而它对我有用......?我会在聊天中显示详细信息。
0赞 Frank 2/6/2016
@akrun 好吧,也许这是一个 1.9.7 的功能。不过,我在新闻中没有看到它。