如何加速DataFrame迭代?R语言实现销售额均分的代码优化求助
问题描述
样本数据
ACCOUNT_KEY SG Total_sales C9240000000000440 1.LOYAL++ 84000.000 C9240000000000067 3.COMMITTED 35723.356 C9240000000000840 7.NEW JOINERS 26492.515 C9240000000000254 11.PROFESSIONAL 21598.651 C9240000000000027 11.PROFESSIONAL 21412.302 C9240000000000008 5.FRESH FOOD 16849.033 C9240000000000662 11.PROFESSIONAL 16005.060 C920000000000479 1.LOYAL++ 15374.671
需要将上述DataFrame划分为TG和CG两个子集,使两者的Total_sales总和尽可能接近。当前使用的R代码因循环逻辑导致耗时过长,请求优化以提升速度。
原实现代码
dataframe2 <- dataframe[order(-dataframe$Total_sales),] dataframe2$ACCOUNT_KEY = as.factor(dataframe2$ACCOUNT_KEY) dataframe2$SG = as.factor(dataframe2$SG) rm(TG) rm(CG) summary(dataframe2) CG = head(dataframe2,1) dataframe2 = dataframe2[-1,] TG = head(dataframe2,1) dataframe2 = dataframe2[-1,] j = 2 k = 2 for (i in 1 : nrow(dataframe2)) { if (sum(TG$Total_sales) < sum(CG$Total_sales)) { TG[j,] = dataframe2[i,] j = j+1 } else { CG[k,] = dataframe2[i,] k = k+1 } }
优化方案
问题根源
原代码效率低的核心原因:
- 每次循环都重新计算整个TG/CG的
Total_sales总和,随着数据量增大,重复计算的开销呈指数级增长 - 逐行手动扩充数据框的操作在R中效率极低,频繁的行绑定会产生大量内存拷贝,拖慢执行速度
优化思路
- 跟踪总和而非重复计算:维护两个变量实时记录TG和CG的当前总和,避免每次循环遍历整个列求和
- 用标记向量替代逐行修改:先创建一个分组标记向量,最后一次性拆分数据框,减少内存操作开销
- 保留贪心策略:原代码的贪心逻辑(每次将下一个元素分配到总和较小的组)是合理的,继续沿用该逻辑但优化执行方式
优化后代码
# 保持原逻辑的数据排序 dataframe2 <- dataframe[order(-dataframe$Total_sales),] dataframe2$ACCOUNT_KEY <- as.factor(dataframe2$ACCOUNT_KEY) dataframe2$SG <- as.factor(dataframe2$SG) # 初始化分组标记向量和总和变量 group_tag <- character(nrow(dataframe2)) group_tag[1] <- "CG" group_tag[2] <- "TG" sum_cg <- dataframe2$Total_sales[1] sum_tg <- dataframe2$Total_sales[2] # 遍历剩余数据行(从第3行开始) for (i in 3:nrow(dataframe2)) { if (sum_tg < sum_cg) { group_tag[i] <- "TG" sum_tg <- sum_tg + dataframe2$Total_sales[i] } else { group_tag[i] <- "CG" sum_cg <- sum_cg + dataframe2$Total_sales[i] } } # 一次性拆分得到TG和CG TG <- dataframe2[group_tag == "TG", ] CG <- dataframe2[group_tag == "CG", ] # 验证结果 cat("TG总销售额:", sum_tg, "\n") cat("CG总销售额:", sum_cg, "\n")
大数据量场景进阶优化
如果数据集规模很大(如十万行以上),可以使用data.table进一步提升效率,它的内存操作和循环性能比基础R更优:
library(data.table) # 转换为data.table格式 dt <- as.data.table(dataframe) # 按销售额降序排序 dt <- dt[order(-Total_sales)] # 转换因子类型 dt[, ACCOUNT_KEY := as.factor(ACCOUNT_KEY)] dt[, SG := as.factor(SG)] # 初始化分组标记和总和 dt[, group := ""] dt[1, group := "CG"] dt[2, group := "TG"] sum_cg <- dt[1, Total_sales] sum_tg <- dt[2, Total_sales] # 遍历分配分组 for (i in 3:nrow(dt)) { if (sum_tg < sum_cg) { dt[i, group := "TG"] sum_tg <- sum_tg + dt[i, Total_sales] } else { dt[i, group := "CG"] sum_cg <- sum_cg + dt[i, Total_sales] } } # 拆分得到结果 TG <- dt[group == "TG"] CG <- dt[group == "CG"]
优化效果说明
- 时间复杂度从原代码的O(n²)降至O(n),避免了重复求和的开销
- 减少了大量内存拷贝操作,向量标记+一次性拆分的方式更符合R的内部优化逻辑
- 代码逻辑更简洁易懂,维护成本更低
内容的提问来源于stack exchange,提问作者Rahul Mundra
相关产品推荐
相关产品推荐

