使用dplyr为组内的不同值分配唯一ID

使用dplyr为组内的不同值分配唯一ID,r,dplyr,R,Dplyr,问题:我需要为具有两级分组的数据创建一个唯一的ID字段。在这里的示例代码中,它是Emp和Color。ID的结构需要如下所示: Emp+每个颜色的唯一编号+重复颜色的序列号 这些值由句点分隔。 示例数据: dat <- data.frame(Emp = c("A","A","A","B","B","C"), Color = c("Red","Green","Green","Orange","Yellow","Brown"), stri

问题:我需要为具有两级分组的数据创建一个唯一的ID字段。在这里的示例代码中,它是
Emp
Color
。ID的结构需要如下所示:

Emp
+每个
颜色的唯一编号
+重复
颜色的序列号

这些值由句点分隔。
示例数据:

dat <- data.frame(Emp = c("A","A","A","B","B","C"), 
              Color = c("Red","Green","Green","Orange","Yellow","Brown"),
              stringsAsFactors = FALSE)
但我无法为每个
Emp
组中唯一出现的
Color
分配序列号

我更喜欢dplyr解决方案,但任何方法都将不胜感激。

我们可以试试

dat %>% 
   group_by(Emp) %>%
   mutate(temp = match(Color, unique(Color)),
          temp2 = duplicated(Color)+1,
          ID = sprintf("%s.%02d.%03d", Emp, temp, temp2))%>%
   select(-temp, -temp2)  
#    Emp  Color       ID
#   <chr>  <chr>    <chr>
#1     A    Red A.01.001
#2     A  Green A.02.001
#3     A  Green A.02.002
#4     B Orange B.01.001
#5     B Yellow B.02.001
#6     C  Brown C.01.001
dat%>%
分组依据(Emp)%>%
变异(温度=匹配(颜色、唯一(颜色)),
temp2=复制(颜色)+1,
ID=sprintf(“%s.%02d.%03d”,Emp,temp,temp2))%>%
选择(-temp,-temp2)
#Emp颜色ID
#         
#1 A红色A.01.001
#2 A绿色A.02.001
#3 A绿色A.02.002
#4 B橙色B.01.001
#5B黄色B.02.001
#6 C棕色C.01.001

使用
数据。表
sprintf

library(data.table)
setDT(dat)[, ID := sprintf('%s.%02d.%03d', 
                           Emp, rleid(Color), rowid(rleid(Color))), 
           by = Emp]
你会得到:

> dat
   Emp  Color       ID
1:   A    Red A.01.001
2:   A  Green A.02.001
3:   A  Green A.02.002
4:   B Orange B.01.001
5:   B Yellow B.02.001
6:   C  Brown C.01.001
工作原理:

  • 使用
    setDT()
  • 分组依据
    Emp
  • 并使用
    sprintf
    -函数创建
    ID
    -变量。使用
    sprintf
    可以根据指定的格式轻松地将多个向量粘贴在一起
  • 使用
    :=
    意味着
    数据表
    通过引用更新
  • %s
    表示字符串将用于第一部分(即
    Emp
    )<代码>%02d&
    %03d
    表示一个数字在需要时需要有两个或三个带前导零的数字。中间的点将被照字面理解,从而包含在结果字符串中

处理@jsta的注释时,如果
Color
-列中的值不连续,则可以使用:

setDT(dat)[, r := as.integer(factor(Color, levels = unique(Color))), by = Emp
           ][, ID := sprintf('%s.%02d.%03d', 
                             Emp, r, rowid(r)), 
             by = Emp][, r:= NULL]
这也将保持
颜色
列的显示顺序。您也可以使用
match(Color,unique(Color))
来代替.integer(factor(Color,levels=unique(Color)),如akrun所示

在更大的数据集上实现上述功能,以说明:

dat2 <- rbindlist(list(dat,dat))
dat2[, r := match(Color, unique(Color)), by = Emp
     ][, ID := sprintf('%s.%02d.%03d', 
                     Emp, r, rowid(r)), 
     by = Emp]

如果“绿色”行不是连续的,这会失败吗?也许可以在那里的某个地方添加一个排序?谢谢Jaap和akrun的回答。我最终使用了data.table方法,但这两种方法都很有用,因为akrun的回答中提到了更正。谢谢你们两位!例如,当A组中有3个“绿色”时,第三个ID也将以
002
结尾。使用
dat%%>%groupby(Emp)%%>%mutate(temp=match(Color,unique(Color))%%>%groupby(Color)%%>%mutate(temp2=row_number(),ID=sprintf(“%s.%02d.%03d”,Emp,temp,temp2))%%>%select(-temp,-temp2)
也考虑到了这一点。
setDT(dat)[, r := as.integer(factor(Color, levels = unique(Color))), by = Emp
           ][, ID := sprintf('%s.%02d.%03d', 
                             Emp, r, rowid(r)), 
             by = Emp][, r:= NULL]
dat2 <- rbindlist(list(dat,dat))
dat2[, r := match(Color, unique(Color)), by = Emp
     ][, ID := sprintf('%s.%02d.%03d', 
                     Emp, r, rowid(r)), 
     by = Emp]
> dat2
    Emp  Color r       ID
 1:   A    Red 1 A.01.001
 2:   A  Green 2 A.02.001
 3:   A  Green 2 A.02.002
 4:   B Orange 1 B.01.001
 5:   B Yellow 2 B.02.001
 6:   C  Brown 1 C.01.001
 7:   A    Red 1 A.01.002
 8:   A  Green 2 A.02.003
 9:   A  Green 2 A.02.004
10:   B Orange 1 B.01.002
11:   B Yellow 2 B.02.002
12:   C  Brown 1 C.01.002