如何用R的循环或apply生成MARKET与MEAL组合的子数据框?
问题:生成MARKET与MEAL所有组合的独立子数据框
给定如下R语言示例数据框:
df <- data.frame (MARKET = c("US", "US", "UK", "UK", "China", "China", "Brazil", "Brazil", "US", "US", "UK", "UK", "China", "China", "Brazil", "Brazil","US", "US", "UK", "UK", "China", "China", "Brazil", "Brazil","US", "US", "UK", "UK", "China", "China", "Brazil", "Brazil","US", "US", "UK", "UK", "China", "China", "Brazil", "Brazil"), MEAL = c("Breakfast", "Lunch", "Dinner", "Breakfast", "Lunch", "Dinner","Breakfast", "Lunch", "Dinner","Breakfast", "Lunch", "Dinner","Breakfast", "Lunch", "Dinner","Breakfast", "Lunch", "Dinner","Breakfast", "Lunch", "Dinner","Breakfast", "Lunch", "Dinner","Breakfast", "Lunch", "Dinner","Breakfast", "Lunch", "Dinner", "Breakfast", "Lunch", "Dinner", "Breakfast", "Lunch", "Dinner", "Breakfast", "Lunch", "Dinner", "Breakfast") )
需求是生成MARKET与MEAL所有组合对应的独立子数据框(如Brazil_Breakfast、Brazil_Lunch等)。已通过以下代码获取类别向量:
markets <- rownames(table(df$MARKET)) meals <- rownames(table(df$MEAL))
手动子集单个组合的代码可正常运行:
brazil_breakfast <- subset(df, MARKET==markets[1] & MEAL==meals[1])
但编写的嵌套for循环仅生成最后一个组合(US与Lunch)且数据框命名为i_j:
for (i in length(markets)) { for (j in length(meals)) { i_j <- subset(df, MARKET==markets[i] & MEAL==meals[j]) } }
解决方案
一、修复嵌套for循环
原循环的核心问题是for (i in length(markets))仅遍历了最后一个索引(length(markets)返回单个数值),需改为遍历所有索引;同时要动态生成变量名,使用assign()函数将子数据框存入全局环境。
markets <- rownames(table(df$MARKET)) meals <- rownames(table(df$MEAL)) # 修复后的循环 for (i in seq_along(markets)) { for (j in seq_along(meals)) { # 生成规范的变量名(小写+下划线) var_name <- tolower(paste0(markets[i], "_", meals[j])) # 子集数据并赋值到全局环境 assign(var_name, subset(df, MARKET == markets[i] & MEAL == meals[j])) } }
seq_along(markets)生成从1到length(markets)的序列,比1:length(markets)更安全(避免空向量场景出错);tolower()统一变量名风格,可根据需求调整为其他格式。
二、使用apply系列函数实现
通过expand.grid生成所有组合,结合lapply批量处理,最后用list2env转为独立数据框,代码更简洁:
# 生成MARKET与MEAL的所有组合 combos <- expand.grid(MARKET = markets, MEAL = meals, stringsAsFactors = FALSE) # 批量生成子数据框列表 df_list <- lapply(1:nrow(combos), function(k) { subset(df, MARKET == combos$MARKET[k] & MEAL == combos$MEAL[k]) }) # 给列表元素命名 names(df_list) <- tolower(paste0(combos$MARKET, "_", combos$MEAL)) # 将列表转为全局环境中的独立变量 list2env(df_list, envir = .GlobalEnv)
三、更推荐的做法:用列表统一管理
实际R项目中,不建议生成大量独立变量污染全局环境,更推荐用列表存储所有子数据框,方便后续批量操作:
# 一行代码生成带命名的子数据框列表 df_list <- split(df, interaction(df$MARKET, df$MEAL, sep = "_")) # 统一变量名为小写 names(df_list) <- tolower(names(df_list)) # 调用单个子数据框示例 df_list$brazil_breakfast
split()结合interaction()可快速按组合分组;- 列表形式便于批量分析、导出等后续操作,代码更简洁易维护。
内容的提问来源于stack exchange,提问作者BDuff
相关产品推荐
相关产品推荐

