You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在R中高效将长格式data.frame转为含0/1的独立data.frame

问题描述

首先定义原始数据集:

mydata <- data.frame(id = c(1,1,1,2,2,3,4),
                     hobby = c("music", "sports", "science", "science", "lifestyle", 
                               "party", "sports"),
                     x = c(10, 10, 10, 23, 23, 11, 0),
                     y = c(78, 78, 78, 55, 55, 22, 9))

查看数据结构:

> mydata
  id     hobby  x  y
1  1     music 10 78
2  1    sports 10 78
3  1   science 10 78
4  2   science 23 55
5  2 lifestyle 23 55
6  3     party 11 22
7  4    sports  0  9

需求说明:

  • 数据集为长格式,包含5种独特爱好:music、sports、science、lifestyle、party
  • 需要为每个爱好生成独立数据集,其中hobby列以0/1标记(1表示该id拥有此爱好),且每个数据集每行对应唯一id
  • 最终针对每个数据集运行Poisson回归:glm(y ~ hobby + offset(x), family = "poisson", data = dat_xxx)
  • 实际场景存在5万个独特爱好,需高效实现
高效解决方案

针对5万个爱好的大规模场景,绝对不建议生成5万个独立的data.frame——这会造成严重的内存浪费且运行效率极低。推荐以下两种高效思路:

思路1:构建宽格式数据集,批量运行模型

先将数据转换为宽格式(每个爱好对应一列0/1值),同时保留每个id的唯一x、y值(同一id的x、y值一致):

library(dplyr)
library(tidyr)

# 获取每个id的唯一x、y基准数据
id_base <- mydata %>%
  distinct(id, x, y)

# 生成每个id的爱好标记,转换为宽格式
hobby_wide <- mydata %>%
  distinct(id, hobby) %>%
  mutate(hobby_flag = 1) %>%
  pivot_wider(names_from = hobby, values_from = hobby_flag, values_fill = 0)

# 合并得到宽格式数据集
wide_data <- id_base %>% left_join(hobby_wide, by = "id")

生成的wide_data结构如下:

id  x  y music sports science lifestyle party
1  1 10 78     1      1       1         0     0
2  2 23 55     0      0       1         1     0
3  3 11 22     0      0       0         0     1
4  4  0  9     0      1       0         0     0

接下来批量遍历所有爱好列,运行模型并将结果存储在列表中:

# 提取所有爱好名称
hobby_names <- setdiff(colnames(wide_data), c("id", "x", "y"))

# 批量拟合模型
model_list <- lapply(hobby_names, function(hobby) {
  formula <- as.formula(paste0("y ~ ", hobby, " + offset(x)"))
  glm(formula, family = "poisson", data = wide_data)
})

# 为模型列表命名,方便索引
names(model_list) <- hobby_names

之后可通过model_list$music、model_list$sports直接调用对应爱好的模型结果,无需生成大量独立数据集。

思路2:分组操作直接拟合模型

如果不需要保留每个爱好的独立数据集,可通过笛卡尔积生成全量标记数据,再按爱好分组拟合模型:

# 生成id与爱好的笛卡尔积,标记是否拥有该爱好
full_data <- expand.grid(id = unique(mydata$id), hobby = unique(mydata$hobby)) %>%
  left_join(mydata %>% distinct(id, hobby), by = c("id", "hobby")) %>%
  mutate(hobby_flag = ifelse(!is.na(hobby.y), 1, 0)) %>%
  left_join(id_base, by = "id") %>%
  select(id, hobby = hobby.x, hobby_flag, x, y)

# 按爱好分组拟合模型
model_list2 <- full_data %>%
  group_by(hobby) %>%
  group_map(~ glm(y ~ hobby_flag + offset(x), family = "poisson", data = .x))

# 为模型列表命名
names(model_list2) <- unique(full_data$hobby)

这种方法全程无需生成多个独立数据集,内存占用远低于生成5万个data.frame的方案。

小数据场景可选:生成数据集列表

若爱好数量较少,可将各爱好数据集存储在列表中(而非全局环境中的独立对象):

# 获取id基准数据
id_base <- mydata %>% distinct(id, x, y)

# 生成每个爱好的数据集列表
dat_list <- lapply(unique(mydata$hobby), function(hobby) {
  id_base %>%
    mutate(hobby = as.integer(id %in% mydata$id[mydata$hobby == hobby]))
})

# 命名列表元素
names(dat_list) <- paste0("dat_", unique(mydata$hobby))

此时可通过dat_list$dat_music获取对应数据集,但该方案在5万爱好的场景下会引发内存溢出,不推荐使用。

内容的提问来源于stack exchange,提问作者Adrian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 08:00:58