如何在R中基于列单元格内的多值创建虚拟变量
解决方案:为食谱食材生成虚拟变量并保留原数据列
原代码存在的问题
- 变量名错误:
unlist(t)中的t未定义,实际应为你创建的final;names(final2) <- item中的item应为大写的Item(R语言区分大小写) - 未将生成的虚拟变量与原数据集合并,导致丢失原有列
- 使用
grepl匹配食材可能出现误判(例如grepl("cream", "cream cheese")会返回TRUE,导致"cream"和"cream cheese"的虚拟变量被错误标记) - 未处理食材字符串前后的空格,导致拆分后食材名不一致(比如
" vinegar"和"vinegar"会被视为不同食材)
方案一:使用tidyverse工具链(简洁直观)
依赖dplyr和tidyr包,通过拆分-转宽的方式生成虚拟变量,同时保留所有原列:
library(dplyr) library(tidyr) library(stringr) # 处理数据并生成结果 cookbooks_result <- cookbooks4 %>% # 添加行号用于后续合并匹配 mutate(row_id = row_number()) %>% # 将逗号分隔的食材拆分为单独行 separate_rows(Item, sep = ",") %>% # 去除食材名称前后的空格 mutate(Item = str_trim(Item)) %>% # 标记当前行的食材存在(值为1) mutate(has_ingredient = 1) %>% # 转换为宽表,每个食材作为列,不存在的食材填0 pivot_wider( id_cols = row_id, names_from = Item, values_from = has_ingredient, values_fill = 0 ) %>% # 与原数据集合并 left_join(cookbooks4 %>% mutate(row_id = row_number()), by = "row_id") %>% # 移除临时行号,调整列顺序(原列在前,虚拟变量列在后) select(-row_id) %>% select(names(cookbooks4), everything())
方案二:基础R实现(高效轻量)
无需额外复杂依赖,适合处理大规模数据集:
library(stringr) # 1. 拆分食材列并清理空格 item_split <- strsplit(cookbooks4$Item, split = ",") item_split <- lapply(item_split, str_trim) # 2. 获取所有唯一食材名称 unique_ingredients <- unique(unlist(item_split)) # 3. 生成虚拟变量矩阵:检查每行是否包含对应食材 dummy_matrix <- sapply(unique_ingredients, function(ing) { sapply(item_split, function(row_ings) as.integer(ing %in% row_ings)) }) # 4. 合并原数据与虚拟变量矩阵 cookbooks_result <- cbind(cookbooks4, dummy_matrix)
关键说明
- 两种方案都处理了食材名称的空格问题,避免因空格导致的食材识别错误
- 使用
%in%替代grepl进行匹配,确保只有完全匹配的食材才会被标记为1,避免子串误判 - 最终结果会保留原数据集的所有列,并在后方添加每个唯一食材对应的虚拟变量列
内容的提问来源于stack exchange,提问作者Marco Lecci
相关产品推荐
相关产品推荐

