问题:我需要为具有两级分组的数据创建唯一的ID字段。在此处的示例代码中,它是Emp
和Color
。 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解决方案,但任何方法都会受到赞赏。
答案 0 :(得分:4)
使用data.table
和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
这是如何运作的:
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