在datatable上还有其他关于行方式运算符的帖子 . 他们是too simple或解决specific scenario
我的问题更通用 . 有一个使用dplyr的解决方案 . 我玩过但未能找到使用data.table语法的等效解决方案 . 您能否建议一个优雅的data.table解决方案,重现与dplyr版本相同的结果?
EDIT 1 :真实数据集建议解决方案的基准测试摘要(10MB,73000行,24个数字列上的统计数据) . 基准测试结果是主观的 . 但是,经过的时间始终可以再现 .
| Solution By | Speed compared to dplyr |
|-------------|-----------------------------|
| Metrics v1 | 4.3 times SLOWER (use .SD) |
| Metrics v2 | 5.6 times FASTER |
| ExperimenteR| 15 times FASTER |
| Arun v1 | 3 times FASTER (Map func)|
| Arun v2 | 3 times FASTER (foo func)|
| Ista | 4.5 times FASTER |
EDIT 2 :我在第二天添加了NACount列 . 这就是为什么在各个贡献者建议的解决方案中找不到该列的原因 .
Data Setup
library(data.table)
dt <- data.table(ProductName = c("Lettuce", "Beetroot", "Spinach", "Kale", "Carrot"),
Country = c("CA", "FR", "FR", "CA", "CA"),
Q1 = c(NA, 61, 40, 54, NA), Q2 = c(22, 8, NA, 5, NA),
Q3 = c(51, NA, NA, 16, NA), Q4 = c(79, 10, 49, NA, NA))
# ProductName Country Q1 Q2 Q3 Q4
# 1: Lettuce CA NA 22 51 79
# 2: Beetroot FR 61 8 NA 10
# 3: Spinach FR 40 NA NA 49
# 4: Kale CA 54 5 16 NA
# 5: Carrot CA NA NA NA NA
SOLUTION using dplyr + rowwise()
library(dplyr) ; library(magrittr)
dt %>% rowwise() %>%
transmute(ProductName, Country, Q1, Q2, Q3, Q4,
AVG = mean(c(Q1, Q2, Q3, Q4), na.rm=TRUE),
MIN = min (c(Q1, Q2, Q3, Q4), na.rm=TRUE),
MAX = max (c(Q1, Q2, Q3, Q4), na.rm=TRUE),
SUM = sum (c(Q1, Q2, Q3, Q4), na.rm=TRUE),
NAcnt= sum(is.na(c(Q1, Q2, Q3, Q4))))
# ProductName Country Q1 Q2 Q3 Q4 AVG MIN MAX SUM NAcnt
# 1 Lettuce CA NA 22 51 79 50.66667 22 79 152 1
# 2 Beetroot FR 61 8 NA 10 26.33333 8 61 79 1
# 3 Spinach FR 40 NA NA 49 44.50000 40 49 89 2
# 4 Kale CA 54 5 16 NA 25.00000 5 54 75 1
# 5 Carrot CA NA NA NA NA NaN Inf -Inf 0 4
ERROR with data.table (compute entire column instead of per-row)
dt[, .(ProductName, Country, Q1, Q2, Q3, Q4,
AVG = mean(c(Q1, Q2, Q3, Q4), na.rm=TRUE),
MIN = min (c(Q1, Q2, Q3, Q4), na.rm=TRUE),
MAX = max (c(Q1, Q2, Q3, Q4), na.rm=TRUE),
SUM = sum (c(Q1, Q2, Q3, Q4), na.rm=TRUE),
NAcnt= sum(is.na(c(Q1, Q2, Q3, Q4))))]
# ProductName Country Q1 Q2 Q3 Q4 AVG MIN MAX SUM NAcnt
# 1: Lettuce CA NA 22 51 79 35.90909 5 79 395 9
# 2: Beetroot FR 61 8 NA 10 35.90909 5 79 395 9
# 3: Spinach FR 40 NA NA 49 35.90909 5 79 395 9
# 4: Kale CA 54 5 16 NA 35.90909 5 79 395 9
# 5: Carrot CA NA NA NA NA 35.90909 5 79 395 9
ALMOST solution but more complex and missing Q1,Q2,Q3,Q4 output columns
dtmelt <- reshape2::melt(dt, id=c("ProductName", "Country"),
variable.name="Quarter", value.name="Qty")
dtmelt[, .(AVG = mean(Qty, na.rm=TRUE),
MIN = min (Qty, na.rm=TRUE),
MAX = max (Qty, na.rm=TRUE),
SUM = sum (Qty, na.rm=TRUE),
NAcnt= sum(is.na(Qty))), by = list(ProductName, Country)]
# ProductName Country AVG MIN MAX SUM NAcnt
# 1: Lettuce CA 50.66667 22 79 152 1
# 2: Beetroot FR 26.33333 8 61 79 1
# 3: Spinach FR 44.50000 40 49 89 2
# 4: Kale CA 25.00000 5 54 75 1
# 5: Carrot CA NaN Inf -Inf 0 4
4 回答
您可以使用
matrixStats
包中的高效行方式函数 .对于具有500000行的数据集(使用来自CRAN的
data.table
)rowwise
(或by=1:nrow(dt)
)对于for loop
是"euphemism",例如使用
by=1:nrow(dt)
,在data.table
中执行rowwise操作您收到了警告消息,因为在第5行中,您正在计算最大值,总和,最小值和最大值 . 例如,见下文:
apply
函数可用于执行逐行计算 . 分别定义功能可以保持清洁:该函数现在可以应用于data.table的行 .
请注意,使用
[.data.table
执行此操作的唯一优点是它允许使用:=
通过引用快速添加 .这比_325859解决方案更慢但更灵活,并且比@ExperimenteR的
dplyr
解决方案更快,在36秒时钟(我的其他方法的时间与@ ExperimenteR的答案相似) .只是另一种方式(虽然效率不高,因为每次调用
na.omit()
,以及许多内存分配):但正如我所提到的,一旦
colwise()
和rowwise()
被实现,这将变得更加简单 . 在这种情况下的语法可能类似于:对于这种情况甚至更直接:
Edit:
另一种变化: