如何在R语言中按组将大于0的唯一值替换为从1开始的序号?
问题:分组内将非零唯一值替换为连续序号
原始数据
df <- data.frame( group = c("A","A","B","B","C"), value1 = c(55, 0, 92, 93, 173), value2 = c(55, 0, 92, 93, 174), value3 = c(66, 77, 92, 0, 175) ) print(df)
输出:
group value1 value2 value3 1 A 55 55 66 2 A 0 0 77 3 B 92 92 92 4 B 93 93 0 5 C 173 174 175
期望结果
group value1 value2 value3 1 A 1 1 2 2 A 0 0 3 3 B 1 1 1 4 B 2 2 0 5 C 1 2 3
尝试的代码及错误
尝试用mutate+across+dense_rank实现,但代码报错:
df <- df %>% group_by(group) %>% mutate(across(-group, ~ifelse(. > 0, dense_rank(.), .))) %>% ungroup()
错误信息:
Error: Problem with `mutate()` input `..1`. x Can't subset columns that don't exist. x Column `group` doesn't exist. i Input `..1` is `across(-group, ~ifelse(. > 0, dense_rank(.), .))`. i The error occurred in group 1: group = "A".
问题分析与解决方案
问题点
- 报错原因:
group_by后,across中用-group无法正确排除分组列,改用指定目标列(如starts_with("value"))更稳妥。 - 逻辑错误:原代码的
dense_rank(.)是对每一列单独排名,而非整个组内所有非零值统一分配序号,无法得到期望结果。
正确代码
我们需要先提取每个组内所有非零的唯一值,建立“原始值→序号”的映射,再批量替换各value列的非零值:
library(dplyr) df <- df %>% group_by(group) %>% mutate( across(starts_with("value"), ~{ # 提取当前组所有非零的唯一值,按出现顺序生成序号 group_nonzero_vals <- unique(c_across(starts_with("value"))[c_across(starts_with("value")) > 0]) # 匹配当前值对应的序号,0保持不变 ifelse(. > 0, match(., group_nonzero_vals), 0) }) ) %>% ungroup() print(df)
运行后即可得到期望结果:
# A tibble: 5 × 4 group value1 value2 value3 <chr> <int> <int> <int> 1 A 1 1 2 2 A 0 0 3 3 B 1 1 1 4 B 2 2 0 5 C 1 2 3
内容的提问来源于stack exchange,提问作者Ilya Egorov
相关产品推荐
相关产品推荐

