优化R代码:基于Interval分箱高效计算两变量均值
R语言高效分组分箱计算均值优化方案
我是R语言新手,一直在想办法优化代码提升效率。我的需求是:针对每个受试者,把30个Interval划分为6个各含5个区间的分箱,计算每个分箱内XDistance和YDistance的均值并生成新表。目前靠重复代码实现了,但尝试用for循环或lapply优化失败,求高效方案。
数据子集
mydata <- structure(list(Subject = c("1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2", "2"), Interval = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 29L, 30L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L), XDistance = c(240, 252.5, 125, 107.5, 170, 77.5, 105, 157.5, 187.5, 125, 62.5, 187.5, 15, 130, 45, 0, 80, 205, 97.5, 85, 160, 152.5, 12.5, 107.5, 157.5, 112.5, 102.5, 82.5, 55, 57.5, 217.5, 235, 142.5, 215, 127.5, 120, 115, 167.5, 182.5, 147.5, 207.5, 90, 165, 155, 222.5, 140, 175, 72.5, 112.5, 172.5 ), YDistance = c(235, 190, 145, 132.5, 210, 92.5, 160, 150, 192.5, 170, 105, 162.5, 87.5, 170, 80, 12.5, 145, 182.5, 170, 87.5, 102.5, 122.5, 0, 117.5, 247.5, 195, 145, 167.5, 97.5, 75, 395, 277.5, 245, 260, 270, 237.5, 235, 275, 245, 210, 200, 92.5, 217.5, 195, 225, 247.5, 212.5, 135, 187.5, 192.5)), row.names = c(NA, -50L), class = c("data.table", "data.frame"), .internal.selfref = <pointer: 0x0000022000ea9850>)
当前使用的繁琐代码
mydata <- read.csv("DSR_Practice.csv") par(mfrow = c(2,2)) library(dplyr) mydata <- mydata[!(mydata$Subject == "Not Used"), ] library(data.table) setDT(mydata) cuts <- list(c(1,5), c(6,10), c(11,15), c(16, 20), c(21, 25), c(26, 30)) data <- lapply(X = cuts, function(i) { mydata[between(x = mydata[ , Interval], lower = i[1], upper = i[2])] }) Bin1 <- as.data.frame(data[[1]]) Bin1 <- Bin1 %>% group_by(Subject) %>% summarise(across(XDistance:YDistance, mean, X = "{XDistance}.{mean}", Y = "{YDistance}. {mean}")) %>% as.data.frame() Bin2 <- as.data.frame(data[[2]]) Bin2 <- Bin2 %>% group_by(Subject) %>% summarise(across(XDistance:YDistance, mean, X = "{XDistance}.{mean}", Y = "{YDistance}. {mean}")) %>% as.data.frame() Bin3 <- as.data.frame(data[[3]]) Bin3 <- Bin3 %>% group_by(Subject) %>% summarise(across(XDistance:YDistance, mean, X = "{XDistance}.{mean}", Y = "{YDistance}. {mean}")) %>% as.data.frame() Bin4 <- as.data.frame(data[[4]]) Bin4 <- Bin4 %>% group_by(Subject) %>% summarise(across(XDistance:YDistance, mean, X = "{XDistance}.{mean}", Y = "{YDistance}. {mean}")) %>% as.data.frame() Bin5 <- as.data.frame(data[[5]]) Bin5 <- Bin5 %>% group_by(Subject) %>% summarise(across(XDistance:YDistance, mean, X = "{XDistance}.{mean}", Y = "{YDistance}. {mean}")) %>% as.data.frame() Bin6 <- as.data.frame(data[[6]]) Bin6 <- Bin6 %>% group_by(Subject) %>% summarise(across(XDistance:YDistance, mean, X = "{XDistance}.{mean}", Y = "{YDistance}. {mean}")) %>% as.data.frame() df.list <- list(Bin1, Bin2, Bin3, Bin4, Bin5, Bin6) df.list <- Reduce(function(x, y) merge(x, y, all = TRUE), df.list)
优化方案
方法1:使用dplyr一步完成分箱与计算
核心思路是先给每个Interval分配对应的分箱编号,再按受试者+分箱分组计算均值,最后转成目标宽表格式:
library(dplyr) library(tidyr) # 读取数据并预处理 mydata <- read.csv("DSR_Practice.csv") mydata <- mydata[!(mydata$Subject == "Not Used"), ] # 自动分箱、计算均值并转宽表 result <- mydata %>% group_by(Subject) %>% mutate(Bin = paste0("Bin", ceiling(Interval / 5))) %>% group_by(Subject, Bin) %>% summarise(across(XDistance:YDistance, mean, .names = "{.col}_mean")) %>% pivot_wider(names_from = Bin, values_from = c(XDistance_mean, YDistance_mean)) %>% ungroup() print(result)
方法2:使用data.table高效处理
如果数据量较大,data.table的速度优势更明显,同样通过自动分箱、分组计算完成需求:
library(data.table) # 读取数据并转成data.table格式 mydata <- fread("DSR_Practice.csv") mydata <- mydata[Subject != "Not Used"] # 分箱、计算均值、转宽表 mydata[, Bin := paste0("Bin", ceiling(Interval / 5)), by = Subject] result <- mydata[, lapply(.SD, mean), by = .(Subject, Bin), .SDcols = c("XDistance", "YDistance")] result <- dcast(result, Subject ~ Bin, value.var = c("XDistance", "YDistance")) print(result)
以上两种方法均避免了重复代码,直接一步完成分箱、均值计算与格式转换,效率和可读性远高于原有写法。
内容的提问来源于stack exchange,提问作者Miguel De Leon
相关产品推荐
相关产品推荐

