如何在R语言for循环中利用增量子集计算分舍日平均体重?
问题描述
我有一个包含约40000条数据的数据集,记录了不同鸡舍(house)中鸡只养殖周期内的体重。核心变量包括:
- House Number:1-4号鸡舍
- Days in the Crop:连续数值,范围从0.000001天到约39天,部分鸡舍提前结束养殖
- Weight:体重(单位:克),前0.5-0.8天无读数为NA,需要保留这些NA以展示从第0天开始的生长过程
我尝试用循环计算每个鸡舍每天的平均体重并存储到新数据框中。单鸡舍(House 1)的代码可以正常运行:
house_1 <- subset(df,house==1) daily_averages <- data.frame(Day = 1:39, Average=NA) for (i in 1:1){ lower = 0 upper = 1 weight = house_1$weight days = house_1$days_in_crop for (meanroll in 1:39) { meanroll_val = mean(weight[days > lower & days < upper],na.rm=TRUE) daily_averages$Average[meanroll] <- meanroll_val lower=lower+1 upper=upper+1 } }
这里的逻辑是:lower为每日起始值(从0开始),upper为每日结束值(例如0到1之间的天数属于第1天),计算该区间内的平均体重。
但扩展到多鸡舍的双层循环时,结果无法正确存储,输出大量NaN:
house_ID <- unique(df$house) daily_data <- data.frame(HouseNumber=NA, Day = rep(1:39,length(house_ID), Average= NA) for (house_no in 1:length(house_ID)){ lower= 0 upper = 1 weight = df$weight days= df$days_in_crop house_N <- subset(df,house==house_no) with(house_N, for(meanroll in 1:39){ meanroll_val = mean(weight[days > lower & days < upper],na.rm=TRUE) daily_data$Average[meanroll] <- meanroll_val lower=lower+1 upper=upper+1 }) }
即使替换为print(meanroll_val),输出的156个结果(4*39)中也有大量NaN。我需要批量处理的方案,因为未来鸡舍数量会增加,复制单鸡舍代码不现实。
补充数据样例:
前20条数据:
structure(list(house = c(3L, 1L, 4L, 2L, 3L, 2L, 4L, 1L, 3L, 1L, 4L, 2L, 2L, 3L, 4L, 1L, 3L, 1L, 4L, 2L), days_in_crop = c(0.000856481, 0.001435185, 0.002025463, 0.003252315, 0.003657407, 0.003738426, 0.004479167, 0.005451389, 0.007766204, 0.008333333, 0.008912037, 0.010138889, 0.010497685, 0.010555556, 0.011365741, 0.012361111, 0.01462963, 0.015231481, 0.015798611, 0.017025463), weight = c(NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_, NA_integer_)), row.names = c(NA, 20L), class = "data.frame")
日龄超过9.1天的前20条数据:
days_9_39 <- subset(df,days_in_crop > 9.1) dput(head(days_9_39, 20)) structure(list(house = c(4L, 3L, 3L, 1L, 4L, 1L, 2L, 2L, 3L, 3L, 1L, 4L, 1L, 2L, 2L, 3L, 4L, 1L, 4L, 1L), days_in_crop = c(9.101712963, 9.101944444, 9.102847222, 9.10318287, 9.103229167, 9.106064815, 9.106145833, 9.1065625, 9.10837963, 9.108900463, 9.109849537, 9.110162037, 9.112581019, 9.113032407, 9.113159722, 9.114247685, 9.11462963, 9.116435185, 9.117118056, 9.119236111), weight = c(244L, 255L, 249L, 260L, 259L, 276L, NA, 260L, 254L, 254L, 244L, 265L, 268L, NA, 300L, 250L, 239L, 255L, 251L, 258L)), row.names = 10262:10281, class = "data.frame")
解决方案
一、修复原循环代码
你的双层循环有两个核心问题:
- 没有正确定位
daily_data的行索引,每次循环都覆盖了前39行的Average值,而非对应鸡舍的行 - 在
with(house_N)中使用了全局的weight和days,而非鸡舍子集的数据
修改后的代码:
house_ID <- unique(df$house) # 初始化完整数据框:每个鸡舍对应39天 daily_data <- expand.grid(HouseNumber = house_ID, Day = 1:39) daily_data$Average <- NA for (house_no in house_ID){ lower <- 0 upper <- 1 # 取当前鸡舍的子集数据 house_N <- subset(df, house == house_no) weight <- house_N$weight days <- house_N$days_in_crop for(meanroll in 1:39){ # 计算当前区间的平均体重 meanroll_val <- mean(weight[days > lower & days < upper], na.rm = TRUE) # 定位当前鸡舍+当前天数的行,赋值 daily_data$Average[daily_data$HouseNumber == house_no & daily_data$Day == meanroll] <- meanroll_val lower <- lower + 1 upper <- upper + 1 } }
说明:
- 用
expand.grid初始化数据框,确保每个鸡舍的39天都有对应的行 - 每次循环只操作当前鸡舍的子集数据,避免全局变量干扰
- 通过条件索引精准赋值,不会覆盖其他鸡舍的数据
二、更高效的Tidyverse批量处理方案
对于大量数据和未来扩展鸡舍的需求,Tidyverse的向量化操作比循环更高效且易维护:
library(dplyr) library(tidyr) daily_data <- df %>% # 按鸡舍分组 group_by(house) %>% # 生成每个数据点对应的天数区间:days_in_crop在(lower, upper)即对应Day=lower+1 mutate(Day = floor(days_in_crop) + 1) %>% # 过滤到1-39天的区间 filter(Day %in% 1:39) %>% # 按鸡舍和天数分组,计算平均体重 group_by(house, Day) %>% summarise(Average = mean(weight, na.rm = TRUE), .groups = "drop") %>% # 补全所有1-39天的行,缺失的天数填充NA complete(house, Day = 1:39, fill = list(Average = NA)) %>% # 重命名列保持一致 rename(HouseNumber = house)
说明:
floor(days_in_crop)+1直接把连续的天数映射到对应的Day(比如0<days<1对应Day=1,1<days<2对应Day=2,以此类推)complete函数自动补全每个鸡舍缺失的天数,确保每个鸡舍都有39天的数据- 全程向量化操作,无需手动循环,代码更简洁且性能更优
内容的提问来源于stack exchange,提问作者coghlan
相关产品推荐
相关产品推荐

