如何通过循环拆分mtcars数据集为对应车型命名的子数据框?
问题描述
我正在使用mtcars数据集,其结构如下:
structure(list(index = 1:32, car = c("Mazda RX4", "Mazda RX4 Wag", "Datsun 710", "Hornet 4 Drive", "Hornet Sportabout", "Valiant", "Duster 360", "Merc 240D", "Merc 230", "Merc 280", "Merc 280C", "Merc 450SE", "Merc 450SL", "Merc 450SLC", "Cadillac Fleetwood", "Lincoln Continental", "Chrysler Imperial", "Fiat 128", "Honda Civic", "Toyota Corolla", "Toyota Corona", "Dodge Challenger", "AMC Javelin", "Camaro Z28", "Pontiac Firebird", "Fiat X1-9", "Porsche 914-2", "Lotus Europa", "Ford Pantera L", "Ferrari Dino", "Maserati Bora", "Volvo 142E"), mpg = c(21, 21, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.8, 19.2, 17.8, 16.4, 17.3, 15.2, 10.4, 10.4, 14.7, 32.4, 30.4, 33.9, 21.5, 15.5, 15.2, 13.3, 19.2, 27.3, 26, 30.4, 15.8, 19.7, 15, 21.4), cyl = c(6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, 4, 4, 4, 8, 6, 8, 4), disp = c(160, 160, 108, 258, 360, 225, 360, 146.7, 140.8, 167.6, 167.6, 275.8, 275.8, 275.8, 472, 460, 440, 78.7, 75.7, 71.1, 120.1, 318, 304, 350, 400, 79, 120.3, 95.1, 351, 145, 301, 121), hp = c(110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123, 180, 180, 180, 205, 215, 230, 66, 52, 65, 97, 150, 150, 245, 175, 66, 91, 113, 264, 175, 335, 109), drat = c(3.9, 3.9, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.92, 3.92, 3.92, 3.07, 3.07, 3.07, 2.93, 3, 3.23, 4.08, 4.93, 4.22, 3.7, 2.76, 3.15, 3.73, 3.08, 4.08, 4.43, 3.77, 4.22, 3.62, 3.54, 4.11 ), wt = c(2.62, 2.875, 2.32, 3.215, 3.44, 3.46, 3.57, 3.19, 3.15, 3.44, 3.44, 4.07, 3.73, 3.78, 5.25, 5.424, 5.345, 2.2, 1.615, 1.835, 2.465, 3.52, 3.435, 3.84, 3.845, 1.935, 2.14, 1.513, 3.17, 2.77, 3.57, 2.78), qsec = c(16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20, 22.9, 18.3, 18.9, 17.4, 17.6, 18, 17.98, 17.82, 17.42, 19.47, 18.52, 19.9, 20.01, 16.87, 17.3, 15.41, 17.05, 18.9, 16.7, 16.9, 14.5, 15.5, 14.6, 18.6 ), vs = c(0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1), am = c(1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1), gear = c(4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 4), carb = c(4, 4, 1, 1, 2, 1, 4, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 1, 2, 1, 1, 2, 2, 4, 2, 1, 2, 2, 4, 6, 8, 2)), row.names = c(NA, -32L), class = c("tbl_df", "tbl", "data.frame"))
我希望创建32个不同的数据集,以对应车型名称作为标签命名(如mtcars_mazda_rx4、mtcars_hornet_sportabout等),每个子数据框仅包含对应车型的单条记录,即mtcars[car == "Mazda RX4",]这样的形式。我已写出如下伪代码:
for (i in 1:length(car)) { mtcars %>% filter(car == car[i]) %>% mtcars_i <- mtcars }
但不确定如何推进,请问是否可以通过循环实现按指定变量筛选并生成对应命名的新数据框?
解决方案
当然可以通过循环实现,你的伪代码存在几个核心问题:
- 未处理动态变量名的生成逻辑,无法创建
mtcars_mazda_rx4这类符合要求的对象名 - 管道操作的筛选结果没有被正确赋值,逻辑链断裂
- 循环中直接使用
car[i]可能因环境冲突导致错误(需明确指定为mtcars的car列)
下面提供两种可行的实现方式:
方法1:基础R循环
# 遍历每个车型名称 for (car_name in mtcars$car) { # 生成规范变量名:小写、空格替换为下划线、添加前缀mtcars_ var_name <- paste0("mtcars_", tolower(gsub(" ", "_", car_name))) # 筛选对应车型的单条记录 subset_data <- mtcars[mtcars$car == car_name, ] # 将数据框赋值到全局环境 assign(var_name, subset_data, envir = .GlobalEnv) }
方法2:tidyverse风格实现
如果你习惯使用tidyverse工具链,可以结合purrr包简化代码:
library(tidyverse) # 按车型拆分数据,得到以车型名为键的列表 car_data_list <- mtcars %>% split(.$car) # 将列表元素逐一转换为全局环境中的数据框,并规范命名 walk(names(car_data_list), function(car_name) { var_name <- paste0("mtcars_", tolower(gsub(" ", "_", car_name))) assign(var_name, car_data_list[[car_name]], envir = .GlobalEnv) })
结果验证
运行代码后,可通过以下命令确认生成结果:
# 查看所有以mtcars_开头的对象 ls(pattern = "^mtcars_") # 查看其中一个数据框的内容 mtcars_mazda_rx4
注意:虽然生成独立数据框可以满足需求,但保留为列表形式(如方法2中的car_data_list)通常更便于后续批量操作,避免全局环境中出现大量零散对象。
内容的提问来源于stack exchange,提问作者hachiko
相关产品推荐
相关产品推荐

