如何通过 group_by 中的 group-number 对数据表进行编号/标记?
Posted
技术标签:
【中文标题】如何通过 group_by 中的 group-number 对数据表进行编号/标记?【英文标题】:How to number/label data-table by group-number from group_by? 【发布时间】:2014-05-26 09:49:07 【问题描述】:我有一个 tbl_df,我想在其中 group_by(u, v)
为使用 (u, v)
观察到的每个不同的整数组合。
编辑:随后通过在 dplyr 0.4.0 中添加(现已弃用)group_indices()
解决了这个问题
a) 然后我想为每个不同的组分配一些任意不同的数字 label=1,2,3...
例如组合 (u,v)==(2,3) 可以得到标签 1,(1,3) 可以得到 2,依此类推。
如何使用 mutate()
完成此操作,而无需三步汇总和自加入?
dplyr 有一个简洁的函数n()
,但它给出了组内的元素数量,而不是组的总数量。 In data.table
this would simply be called .GRP
.
b) 实际上我真正想要分配一个字符串/字符标签('A','B',...)。
但是按整数对组进行编号就足够了,因为我可以使用integer_to_label(i)
,如下所示。除非有一个聪明的方法来合并这两者?但不要为这部分出汗。
set.seed(1234)
# Helper fn for mapping integer 1..26 to character label
integer_to_label <- function(i) substr("ABCDEFGHIJKLMNOPQRSTUVWXYZ",i,i)
df <- tibble::as_tibble(data.frame(u=sample.int(3,10,replace=T), v=sample.int(4,10,replace=T)))
# Want to label/number each distinct group of unique (u,v) combinations
df %>% group_by(u,v) %>% mutate(label = n()) # WRONG: n() is number of element within its group, not overall number of group
u v
1 2 3
2 1 3
3 1 2
4 2 3
5 1 2
6 3 3
7 1 3
8 1 2
9 3 1
10 3 4
KLUDGE 1: could do df %>% group_by(u,v) %>% summarize(label = n()) , then self-join
【问题讨论】:
@Randy-Lai 和我都分别解决了它。 Randy's 是一个更简洁的习惯用法,适用于多个mutate/summarize(...)
操作。我找到了interaction(u,v, drop=T)
你需要这个做什么?
@hadley:我的特殊原因如问题所述:我想为每个不同的(u,v)组分配一些任意(有序)编号=1,2,3 ...所以我最终可以为它们分配字符串标签'A','B','C'......(我的目的是随后在建模和绘图中通过速记来引用它们)
@hadley:但总的来说这是一个有用的功能,data.table 包为此实现了.GRP
。有没有机会我们可以在 dplyr 中找到一些东西? :)
下一个版本将有group_indices()
【参考方案1】:
dplyr 有一个 group_indices()
函数,您可以像这样使用它:
df %>%
mutate(label = group_indices(., u, v)) %>%
group_by(label) ...
【讨论】:
group_indices() 使用分组变量的(按字母顺序)排序,有没有办法使用它来保留表中的顺序,或应用您自己的顺序?【参考方案2】:使用data.table
的另一种方法是
require(data.table)
setDT(df)[,label:=.GRP, by = c("u", "v")]
导致:
u v label
1: 2 1 1
2: 1 3 2
3: 2 1 1
4: 3 4 3
5: 3 1 4
6: 1 1 5
7: 3 2 6
8: 2 3 7
9: 3 2 6
10: 3 4 3
【讨论】:
【参考方案3】:更新答案
get_group_number = function()
i = 0
function()
i <<- i+1
i
group_number = get_group_number()
df %>% group_by(u,v) %>% mutate(label = group_number())
你也可以考虑以下稍微不可读的版本
group_number = (function()i = 0; function() i <<- i+1 )()
df %>% group_by(u,v) %>% mutate(label = group_number())
使用iterators
包
library(iterators)
counter = icount()
df %>% group_by(u,v) %>% mutate(label = nextElem(counter))
【讨论】:
不,这是错误的。我不是在组中寻找行号。我正在寻找 group-number(相当于data.table .GRP
)。由于在这个例子中我们有 7 个独特的 (u,v) 组合,输出标签应该是 1:7(以任意顺序)
抱歉,没太注意你的问题。我已经用肮脏的解决方案更新了答案......
不错,但它本质上只是一个返回递增整数的生成器函数......我们当然可以避免它吗?
^ R 不做生成器功能吗? (比如 Python yield
?)无需在 fn 中手动保存状态?
你让我想起了iterators
包。我以前从未使用过它。 (并查看更新的解决方案)。但本质上和我原来的方法是等价的。【参考方案4】:
从 dplyr 版本 1.0.4 开始,函数 cur_group_id()
已替换旧函数 group_indices
。
在分组的 data.frame 上调用它:
df %>%
group_by(u, v) %>%
mutate(label = cur_group_id())
# A tibble: 10 x 3
# Groups: u, v [6]
u v label
<int> <int> <int>
1 2 2 4
2 2 2 4
3 1 3 2
4 3 2 6
5 1 4 3
6 1 2 1
7 2 2 4
8 2 4 5
9 3 2 6
10 2 4 5
【讨论】:
【参考方案5】:用三种不同的方式更新我的答案:
A) 使用 interaction(u,v)
的简洁非 dplyr 解决方案:
> df$label <- factor(interaction(df$u,df$v, drop=T))
[1] 1.3 2.3 2.2 2.4 3.2 2.4 1.2 1.2 2.1 2.1
Levels: 2.1 1.2 2.2 3.2 1.3 2.3 2.4
> match(df$label, levels(df$label)[ rank(unique(df$label)) ] )
[1] 1 2 3 4 5 4 6 6 7 7
B) 使 Randy 简洁的又快又脏的生成器函数答案更紧凑:
get_next_integer = function()
i = 0
function(u,v) i <<- i+1
get_integer = get_next_integer()
df %>% group_by(u,v) %>% mutate(label = get_integer())
C) 这里还有一个使用生成器函数的单行代码,该函数滥用来自this 的全局变量赋值:
i <- 0
generate_integer <- function() return(assign('i', i+1, envir = .GlobalEnv))
df %>% group_by(u,v) %>% mutate(label = generate_integer())
rm(i)
【讨论】:
我使用get_group_name
的原因是为了避免使用全局变量。我认为在函数内部更改全局变量通常不是一个好主意……但它仍然有效。
我压缩了你的并将它放在我的答案的顶部。赋值计算为其 LHS 值,因此我们可以简单地说 function(u,v) i <<- i+1
我还用interaction(u,v)
找到了一个简洁的三行非dplyr 方式,并在顶部添加了它。
我还通过this subquestion 解决了interaction(... drop=T)
的增量订单问题【参考方案6】:
我没有足够的评论声誉,所以我发布了一个答案。
使用 factor() 的解决方案是一个很好的解决方案,但它的缺点是在 factor() 按字母顺序排列其级别之后分配组编号。 dplyr 的 group_indices() 也会发生同样的行为。也许您希望根据当前的组顺序将组编号从 1 分配到 n。在这种情况下,您可以使用:
my_tibble %>% mutate(group_num = as.integer(factor(group_var, levels = unique(.$group_var))) )
【讨论】:
谢谢。正如我在问题中指出的那样,这一切都通过在 2015 年在 dplyr 0.4.0 中添加group_indices()
解决了以上是关于如何通过 group_by 中的 group-number 对数据表进行编号/标记?的主要内容,如果未能解决你的问题,请参考以下文章
如何在group_by()中使用as_tbl_graph()?
Sparklyr:使用 group_by,然后连接组中行中的字符串