无需连接,用R的data.table按组应用百分位数截断过滤
嘿,作为data.table爱好者,我太懂你想要高效无连接方案的心情了!针对你按Zone组对Fiscal.Year做百分位数截断过滤的需求,我整理了几个不用join的实现,包括data.table的最优解法和base R方案,一起来看:
首先先把测试数据和规则表准备好,方便大家复现:
library(data.table) # 输入数据 Input_File <- structure(list(Zone = c("East", "East", "East", "East", "East", "East", "East", "West", "West", "West", "West", "West", "West", "West"), Fiscal.Year = c(2016, 2016, 2016, 2016, 2016, 2016, 2017, 2016, 2016, 2016, 2017, 2017, 2018, 2018), Transaction.ID = c(132, 133, 134, 135, 136, 137, 171, 171, 172, 173, 175, 176, 177, 178 ), L.Qty = c(3, 0, 0, 1, 0, 0, 1, 1, 1, 2, 2, 1, 2, 1), A.Qty = c(0, 0, 0, 2, 2, 3, 0, 0, 0, 0, 0, 3, 0, 0), I.Qty = c(2, 2, 2, 0, 1, 0, 3, 0, 0, 0, 1, 0, 1, 1)), .Names = c("Zone", "Fiscal.Year", "Transaction.ID", "L.Qty", "A.Qty", "I.Qty"), row.names = c(NA, -14L), class = "data.frame") Input_File <- as.data.table(Input_File) # 截断规则表 Q <- data.table(Zone = c("East","West"), Ten_percentile = c(2017,2018))
一、Data.table 无连接方案
方案1:命名向量快速查找(最推荐,大数据量友好)
把规则表转成命名向量,利用data.table的快速索引能力直接匹配阈值,过滤行的同时添加阈值列:
# 把规则转成命名向量:Zone为名称,阈值为值 thresholds <- setNames(Q$Ten_percentile, Q$Zone) # 过滤+添加阈值列,一步到位 result_dt1 <- Input_File[Fiscal.Year >= thresholds[Zone], Ten_percentile := thresholds[Zone]][!is.na(Ten_percentile)]
这个方法完全避开了连接操作,命名向量的索引速度极快,处理百万级数据也毫无压力,而且代码简洁直观。
方案2:按Zone分组过滤
如果喜欢分组处理的逻辑,可以用by=Zone对每个组单独应用过滤规则:
result_dt2 <- Input_File[, { # 拿到当前组的阈值 current_thresh <- Q[Zone == .BY$Zone, Ten_percentile] # 从当前组数据中过滤符合条件的行,同时带上阈值列 .SD[Fiscal.Year >= current_thresh, .(Ten_percentile = current_thresh, Fiscal.Year, Transaction.ID, L.Qty, A.Qty, I.Qty)] }, by = Zone]
分组处理的逻辑更清晰,适合需要对每个组做额外操作的场景,同样不需要连接。
二、Base R 无连接方案
用base R实现的话,核心思路和data.table方案1一致,依赖命名向量的快速匹配:
# 转成命名向量 thresholds_base <- setNames(Q$Ten_percentile, Q$Zone) # 转换为data.frame,添加阈值列,过滤符合条件的行 Input_File_base <- as.data.frame(Input_File) Input_File_base$Ten_percentile <- thresholds_base[Input_File_base$Zone] result_base <- Input_File_base[Input_File_base$Fiscal.Year >= Input_File_base$Ten_percentile, ] # 重置行名(可选) rownames(result_base) <- NULL
这个方案逻辑简单,不需要依赖任何包,适合习惯base R的用户。
验证结果
不管用哪种方案,最终输出都和你预期的一致:
# 查看data.table方案1的结果 result_dt1 # Zone Fiscal.Year Transaction.ID L.Qty A.Qty I.Qty Ten_percentile # 1: East 2017 171 1 0 3 2017 # 2: West 2018 177 2 0 1 2018 # 3: West 2018 178 1 0 1 2018
这些方案都完全避免了连接操作,data.table的两种方法在处理大数据量时的效率会明显高于join实现,希望能帮你熟练掌握data.table和base R的高效用法!
内容的提问来源于stack exchange,提问作者watchtower
相关产品推荐
相关产品推荐

