提问人:Hack-R 提问时间:2/6/2016 最后编辑:Hack-R 更新时间:2/6/2016 访问量:82
数据表聚合中的条件因子水平选择
Conditional Factor Level Selection in Aggregation of Data Table
问:
我正在尝试将每个 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 行存在,则聚合行应具有该 ID
Level 1
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"]
答:
3赞
akrun
2/6/2016
#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
或者另一种选择是通过与向量匹配(按特定顺序排列)来获取数字索引,获取最小值的索引,获取相应的“V3”值,按“V1”分组。至于“V2”,它只是“V2”的(OP 帖子中显示的示例将“V2”列作为“字符”类 - 所以必须换行)。match
mean
as.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
我会用您指定的顺序指定为一个因素,然后简单地按顺序完成剩下的工作: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 工作方式的特殊性,以下内容(最初由 @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 )。gmin
data.table
min
factor
base
min
factor
min(factor(1:3))
既然我认为您实际上已经首先存储在您的数据中,那么这种方法可能会更好。V2
numeric
min
评论
0赞
MichaelChirico
2/6/2016
@akrun是这样(很难看出如何在不设置顺序的情况下有效地做到这一点),但我更喜欢我的。 似乎注定会慢一些。factor
which.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 的功能。不过,我在新闻中没有看到它。
评论
character
mean(V2)
as.numeric
matrix
character
mydt <- 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))))
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") ))