如何在R中按每n行计算tibble均值并添加对应新列?
外汇报价数据按5行分组计算均值并填充
我有一个存储外汇报价的tibble,每天包含5条买入价和5条卖出价记录(即每日5行2列数据)。需要实现一个迭代方案,遍历数据计算每5行的总和与均值,并将结果重复填充到对应行的新列中。
示例数据:
buyPrice <- c(1:10) sellPrice <- c(11:20) exchange <- tibble(buyPrice, sellPrice)
期望处理后新增averageBuy和averageSell列,前5行均值分别为3和13,后5行分别为8和18。
我尝试用以下循环函数实现,但代码中averageList[(i-4):i] <- rep(average,5)赋值失败,函数返回NULL:
getAverageByDay <- function(dataSet, columnNumber) { temporarySum <- 0 average <- c() dataSetRows <- nrow(dataSet) averageList <- rep(0,dataSetRows) for (i in 1:dataSetRows) { if (i %% 5 == 0) { temporarySum <- temporarySum + dataSet[[i,columnNumber]] average <- temporarySum / 5 averageList[(i-4):i] <- rep(average,5) temporarySum <- 0 average <- 0 } else { temporarySum <- temporarySum + dataSet[[i,columnNumber]] } } return(averageList) }
循环代码问题分析与修复
循环代码的核心问题是数据提取方式错误:dataSet[[i,columnNumber]]是列表元素的提取语法,不适用于tibble的行列位置访问。另外代码存在冗余的变量初始化(比如average <- c())。
修复后的循环函数:
getAverageByDay <- function(dataSet, columnNumber) { temporarySum <- 0 dataSetRows <- nrow(dataSet) averageList <- rep(0, dataSetRows) # 提前提取目标列向量,提升循环效率 target_col <- dplyr::pull(dataSet, columnNumber) for (i in 1:dataSetRows) { temporarySum <- temporarySum + target_col[i] if (i %% 5 == 0) { average <- temporarySum / 5 averageList[(i-4):i] <- rep(average, 5) temporarySum <- 0 } } return(averageList) } # 调用函数生成新列 exchange$averageBuy <- getAverageByDay(exchange, "buyPrice") exchange$averageSell <- getAverageByDay(exchange, "sellPrice")
符合R语言特性的高效实现
R的核心优势是向量化操作,无需循环即可高效完成分组计算,以下是三种常用方案:
1. dplyr分组(语法直观,适合一般场景)
利用dplyr的分组功能,按每5行创建分组标识,计算均值后自动填充到组内所有行:
library(dplyr) exchange <- exchange %>% # 生成分组ID:每5行一组 mutate(group = (row_number() - 1) %/% 5) %>% group_by(group) %>% mutate( averageBuy = mean(buyPrice), averageSell = mean(sellPrice) ) %>% ungroup() %>% # 可选:删除分组标识列 select(-group)
2. Base R 向量化操作(无需额外包)
用base R的ave函数结合分组标识,实现分组均值填充:
# 生成每5行一组的标识 group_id <- (seq(nrow(exchange)) - 1) %/% 5 # 计算并填充均值 exchange$averageBuy <- ave(exchange$buyPrice, group_id, FUN = mean) exchange$averageSell <- ave(exchange$sellPrice, group_id, FUN = mean)
3. data.table(大数据量场景最优)
如果数据量较大,data.table的分组计算性能远优于循环和dplyr:
library(data.table) # 转换为data.table格式 setDT(exchange)[, `:=`( averageBuy = mean(buyPrice), averageSell = mean(sellPrice) ), by = .(group = (seq_len(.N) - 1) %/% 5)]
内容的提问来源于stack exchange,提问作者Tassia Accioly
相关产品推荐
相关产品推荐

