问题:我需要为具有两个分组级别的数据创建一个唯一的 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] "A.01.001" "A.02.001" "A.02.002" "B.01.001" "B.02.001" "C.01.001"
ID的三个字符后缀记录重复可以做到:
group_by(dat, Emp, Color) %>%
mutate(suffix = str_pad(row_number(), width=3, side="left", pad="0"))
但我无法为每个 Emp
组中唯一出现的 Color
分配序列号。
我更喜欢 dplyr 解决方案,但任何方法都会受到赞赏。
最佳答案
使用 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
这是如何工作的:
- 您使用
setDT()
将 - 按
Emp
分组。 - 并使用
sprintf
函数创建ID
变量。使用sprintf
,您可以根据指定的格式轻松地将多个矢量粘贴在一起。 :=
的使用表示data.table
是通过引用更新的。%s
表示要在第一部分使用一个字符串(即Emp
)。%02d
&%03d
表示一个数字在需要时需要有两个或三个数字和前导零。中间的点将按字面意思表示,因此包含在结果字符串中。
dat
转换为 data.table
解决@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
关于r - 使用 dplyr 为 Group 中的不同值分配唯一 ID,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42537689/