在R中如何对嵌套列表计算逐元素均值?优化代码方案
简化嵌套列表的逐元素均值计算
我有一个数据集my_data,它是长度为50的列表,每个元素由4个各含2个值的子列表组成(子列表由指定二元正态分布生成)。目标是计算整个数据集中所有子列表对应位置元素的均值,比如所有第1个子列表的第1个元素的均值、第1个子列表的第2个元素的均值,以此类推。目前已经用循环和中间变量实现,但希望找到更简便的方法,比如用dplyr包,避免创建大量中间变量。
原实现代码:
set.seed(4991) mean_list <- list(c(0,0),c(3,3),c(6,6),c(0,0)) #Covariance matrix cov_mat <- matrix(c(1, .8, .8, 1), 2) my_data <- list() #50 iterations for (k in 1:50){ seg_data <- list() for (i in 1:4) { seg_data[[i]] <- abs(mvrnorm(1, mu = mean_list[[i]], Sigma = cov_mat) ) } my_data[[k]] <- seg_data } first_list1 <- c() first_list2 <- c() second_list1 <- c() second_list2<- c() third_list1 <- c() third_list2 <- c() fourth_list1 <- c() fourth_list2 <- c() for (p in 1:length(my_data)) { first_list1[p] <- my_data[[p]][[1]][1] first_list2[p] <- my_data[[p]][[1]][2] second_list1[p] <- my_data[[p]][[2]][1] second_list2[p] <- my_data[[p]][[2]][2] third_list1[p] <- my_data[[p]][[3]][1] third_list2[p] <- my_data[[p]][[3]][2] fourth_list1[p] <- my_data[[p]][[4]][1] fourth_list2[p] <- my_data[[p]][[4]][2] } data.frame(first_elements=c(mean(first_list1,na.rm = T), mean(second_list1,na.rm = T), mean(third_list1,na.rm = T), mean(fourth_list1,na.rm = T)) ,second_elements=c(mean(first_list2,na.rm = T), mean(second_list2,na.rm = T), mean(third_list2,na.rm = T), mean(fourth_list2,na.rm = T)) )
方案1:tidyverse(dplyr + purrr)简洁实现
利用purrr的映射函数替代嵌套循环生成数据,再通过dplyr的分组汇总完成均值计算,全程无需中间变量:
library(tidyverse) library(MASS) set.seed(4991) mean_list <- list(c(0,0),c(3,3),c(6,6),c(0,0)) cov_mat <- matrix(c(1, .8, .8, 1), 2) # 优化数据生成:用map替代双层循环 my_data <- map(1:50, ~map(mean_list, ~abs(mvrnorm(1, mu = .x, Sigma = cov_mat)))) # 计算对应位置均值 my_data %>% map_dfr(~as.data.frame(.x), .id = "subgroup") %>% group_by(subgroup) %>% summarise( first_elements = mean(V1, na.rm = TRUE), second_elements = mean(V2, na.rm = TRUE) ) %>% ungroup()
方案2:Base R 无额外包实现
将嵌套列表转换为三维数组,利用apply函数直接计算指定维度的均值:
# 转换为三维数组:样本数 × 子组数 × 元素数 arr <- simplify2array(my_data) # 调整维度顺序为子组数 × 元素数 × 样本数 arr <- aperm(arr, c(2, 3, 1)) # 对每个子组的每个元素计算均值 result <- apply(arr, 1:2, mean, na.rm = TRUE) # 转换为目标数据框格式 as.data.frame(result) %>% setNames(c("first_elements", "second_elements"))
方案3:dplyr + tidyr 重塑数据实现
通过数据的宽长转换,更直观地分组计算均值:
library(dplyr) library(tidyr) library(purrr) my_data %>% imap_dfr(~as.data.frame(.x) %>% mutate(sample_id = .y)) %>% pivot_longer(cols = starts_with("V"), names_to = "element", values_to = "value") %>% group_by(subgroup, element) %>% summarise(mean_value = mean(value, na.rm = TRUE)) %>% pivot_wider(names_from = element, values_from = mean_value) %>% rename(first_elements = V1, second_elements = V2)
内容的提问来源于stack exchange,提问作者Arnoneel Sinha
相关产品推荐
相关产品推荐

