【问题标题】:Conditional Factor Level Selection in Aggregation of Data Table数据表聚合中的条件因子水平选择
【发布时间】:2016-02-06 05:02:17
【问题描述】:

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

假设第一列代表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

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

  • 如果 Level 1 存在于任何 ID 行,则聚合行应具有该 ID 的 Level 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"]

【问题讨论】:

  • 我假设您的数据最初并未存储为character(您使用mean(V2) 而没有as.numeric 表明是这种情况)?使用matrix 声明您的示例会在混合时删除非character 类型。最好按列指定,例如mydt &lt;- 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))))
  • 是的,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") ))

标签: r data.table


【解决方案1】:

我们可以将'V3'转换为factor,并以指定的顺序指定levels

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

或者另一种选择是match,通过与向量匹配(按特定顺序排列)得到数字索引,得到最小值的索引,得到对应的'V3'值,按'V1'分组。至于“V2”,它只是“V2”的mean(OP 帖子中显示的示例将“V2”列为“字符”类 - 所以必须包装as.numeric)。

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

【讨论】:

    【解决方案2】:

    我会将V3 指定为您指定订单的一个因素,然后只需按V3 订购即可完成其余工作:

    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 在 data.table 中的工作方式的特殊性,以下(最初由 @Frank 建议,并且更多地本着 @akrun 的方法的精神)是一个错误(至少在当前版本中):

    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]
    

    基本上,后一种情况使用gmindata.table内部优化的min函数,它适用于factors,而前者,因为至少有一个调用不是直接 em> 到 GForce 函数,诉诸 base min,这在 factors 上不起作用(cf min(factor(1:3)))。

    因为我认为你实际上在数据中首先将V2 存储为numeric,也许min 方法更好。

    【讨论】:

    • @akrun 它是(很难看到如何在不设置factor 顺序的情况下有效地完成),但我更喜欢我的。 which.min 似乎会更慢。
    • 不知道 akrun 的评论是什么,但DT[order(x), x[1]] 似乎是到达min(x) 的一种复杂方式..?我的意思是mydt[, .(V2 = mean(V2), V3 = min(V3)), by=V1](假设 V2 之前已转换为数字)。
    • 但它对我有用...?我会在聊天中显示详细信息。
    • @akrun 好的,也许这是 1.9.7 的功能。不过,我没有在新闻中看到它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-12
    • 2013-10-01
    • 1970-01-01
    相关资源
    最近更新 更多