在R中按列递增为多列名称重编码为数字(无循环实现)
问题描述
我有50列名称数据,为便于展示仅列出4列:
Name1 Name2 Name3 Name4 Rose,Ali Van,Hall Ghol,Dam Murr,kate Camp,Laura Ka,Klo Dan,Dan Ali,Hoss Rose,Ali Van,Hall Ghol,Dam Kol,Kan Murr,Kate Ismal, Ismal Sian,Rozi Nas,Ami Ghol,Dam Ka,Klo Rose,Ali Nor,Ko Murr,Kate Ismal, Ismal Dan,Dan Nas,Ami
需求:按列依次为每个名称分配递增数字:
- 第一列从1开始,重复名称使用相同数字;
- 第二列从第一列的最大编号+1开始;
- 后续每列均从前一列的最大编号+1开始,最终得到如下结果:
Assign1 Assign2 Assign3 Assign4 1 5 8 12 2 6 9 13 1 5 8 14 3 7 10 15 4 6 11 17 3 7 9 15
要求不使用循环,优先用sapply(示例参考:sapply(dat, function(x) match(x, unique(x)))),或dplyr/tidyverse工具实现。
解决方案
方法1:使用tidyverse(推荐)
利用长格式转换+分组计算,配合累计计算实现列间编号连续递增:
library(tidyverse) # 构造示例数据 dat <- tibble( Name1 = c("Rose,Ali", "Camp,Laura", "Rose,Ali", "Murr,Kate", "Ghol,Dam", "Murr,Kate"), Name2 = c("Van,Hall", "Ka,Klo", "Van,Hall", "Ismal, Ismal", "Ka,Klo", "Ismal, Ismal"), Name3 = c("Ghol,Dam", "Dan,Dan", "Ghol,Dam", "Sian,Rozi", "Rose,Ali", "Dan,Dan"), Name4 = c("Murr,kate", "Ali,Hoss", "Kol,Kan", "Nas,Ami", "Nor,Ko", "Nas,Ami") ) # 处理流程 result <- dat %>% mutate(row_id = row_number()) %>% pivot_longer(-row_id, names_to = "col", values_to = "name") %>% group_by(col) %>% mutate(local_id = match(name, unique(name))) %>% ungroup() %>% arrange(col) %>% mutate(col_order = as.integer(str_extract(col, "\\d+"))) %>% group_by(col) %>% mutate(offset = sum(head(unique(local_id), col_order - 1))) %>% ungroup() %>% mutate(final_id = local_id + offset) %>% pivot_wider(id_cols = row_id, names_from = col, values_from = final_id, names_prefix = "Assign") %>% select(-row_id) # 查看结果 print(result, n = Inf)
方法2:使用sapply + 基础计算
通过sapply生成局部编号,再计算列偏移量并累加:
# 构造示例数据 dat <- data.frame( Name1 = c("Rose,Ali", "Camp,Laura", "Rose,Ali", "Murr,Kate", "Ghol,Dam", "Murr,Kate"), Name2 = c("Van,Hall", "Ka,Klo", "Van,Hall", "Ismal, Ismal", "Ka,Klo", "Ismal, Ismal"), Name3 = c("Ghol,Dam", "Dan,Dan", "Ghol,Dam", "Sian,Rozi", "Rose,Ali", "Dan,Dan"), Name4 = c("Murr,kate", "Ali,Hoss", "Kol,Kan", "Nas,Ami", "Nor,Ko", "Nas,Ami"), stringsAsFactors = FALSE ) # 生成每列的局部编号 local_ids <- sapply(dat, function(x) match(x, unique(x))) # 计算每列的起始偏移量 max_local <- apply(local_ids, 2, max) offsets <- c(0, cumsum(max_local[-length(max_local)])) # 计算最终编号 result <- t(t(local_ids) + offsets) colnames(result) <- paste0("Assign", seq_len(ncol(result))) # 查看结果 print(result)
两种方法均无循环,tidyverse方案更易读扩展,适合多列场景;sapply方案更简洁,适配基础R环境。
内容的提问来源于stack exchange,提问作者user330
相关产品推荐
相关产品推荐

