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

时间:2017-03-01 17:00:38

标签: r dplyr

问题:我需要为具有两级分组的数据创建唯一的ID字段。在此处的示例代码中,它是EmpColor。 ID需要结构为:

Emp +重复Color的每个Colors +序号的唯一编号。

这些值按句号分隔 示例数据:

dat <- data.frame(Emp = c("A","A","A","B","B","C"), 
              Color = c("Red","Green","Green","Orange","Yellow","Brown"),
              stringsAsFactors = FALSE)

ID应该显示为:

ID <- c("A.01.001", "A.02.001", "A.02.002", "B.01.001", "B.02.001", "C.01.001")
  

ID   [1]&#34; A.01.001&#34; &#34; A.02.001&#34; &#34; A.02.002&#34; &#34; B.01.001&#34; &#34; B.02.001&#34; &#34; C.01.001&#34;

记录重复项的ID的三个字符后缀可以完成:

 group_by(dat, Emp, Color) %>%
         mutate(suffix = str_pad(row_number(), width=3, side="left", pad="0"))

但我无法为每个Color组的Emp唯一匹配项分配序号。

我更喜欢dplyr解决方案,但任何方法都会受到赞赏。

2 个答案:

答案 0 :(得分:4)

使用data.tablesprintf

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

这是如何运作的:

  • 您使用dat
  • data.table转换为setDT()
  • Emp分组。
  • 使用ID - 函数创建sprintf - 变量。使用sprintf,您可以根据指定的格式轻松地将多个矢量粘贴在一起。
  • 使用:=表示data.table通过引用更新。
  • %s表示将在第一部分(Emp)中使用字符串。 %02d&amp; %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]

这也将保持Color列的显示顺序。您也可以使用as.integer(factor(Color, levels = unique(Color)))代替match(Color, 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]

得到你:

> 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

答案 1 :(得分:2)

我们可以尝试

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