R: dplyr 和 row_number() 没有按预期枚举
R: dplyr and row_number() does not enumerate as expected
我想枚举分组产生的 dataframe/tibble 的每条记录。该索引是根据定义的顺序。如果我使用 row_number() 它会枚举但在组内。但我希望它在不考虑前一个分组的情况下进行枚举。
这是一个例子。为了简单起见,我使用了最小的数据框:
library(dplyr)
df0 <- data.frame( x1 = rep(LETTERS[1:2],each=2)
, x2 = rep(letters[1:2], 2)
, y = floor(abs(rnorm(4)*10))
)
df0
# x1 x2 y
# 1 A a 12
# 2 A b 24
# 3 B a 0
# 4 B b 12
现在,我将其分组 table:
df1 <- df0 %>% group_by(x1,x2) %>% summarize(y=sum(y))
这给了我一个 class tibble 的对象:
# A tibble: 4 x 3
# Groups: x1 [?]
# x1 x2 y
# <fct> <fct> <dbl>
# 1 A a 12
# 2 A b 24
# 3 B a 0
# 4 B b 12
我想使用 row_numer():
向此 table 添加行号
df2 <- df1 %>% arrange(desc(y)) %>% mutate(index = row_number())
df2
# A tibble: 4 x 4
# Groups: x1 [2]
# x1 x2 y index
# <fct> <fct> <dbl> <int>
# 1 A b 24 1
# 2 A a 12 2
# 3 B b 12 1
# 4 B a 0 2
row_number() 确实在前一个分组中进行了枚举。这不是我的本意。这可以避免首先将 tibble 转换为数据帧:
df2 <- df2 %>% as.data.frame() %>% arrange(desc(y)) %>% mutate(index = row_number())
df2
# x1 x2 y index
# 1 A b 24 1
# 2 A a 12 2
# 3 B b 12 3
# 4 B a 0 4
我的问题是:这种行为是故意的吗?
如果是:将以前的数据处理合并到 tibble 中不是很危险吗?合并了哪种类型的处理?
目前我会把tibble转换成dataframe来避免这种意想不到的结果。
详细说明我的评论:是的,保留分组是有意的,并且在许多情况下很有用。如果您不了解 group_by
的工作原理,那只会很危险——任何函数都是如此。要撤消 group_by
,您调用 ungroup
。
看看 group_by
docs,因为它们非常详尽,并解释了此函数如何与其他函数交互、分组如何分层等。文档还解释了每次调用 summarise
删除了一层分组——它可能会让您对发生的事情感到困惑。
例如,你可以按x1
和x2
分组,汇总y
,然后创建一个行号,它会根据x1
给你行(summarise
去掉一层分组,即去掉x2
分组)。然后取消分组允许您根据整个数据框获取行号。
library(dplyr)
df0 %>%
group_by(x1, x2) %>%
summarise(y = sum(y)) %>%
mutate(group_row = row_number()) %>%
ungroup() %>%
mutate(all_df_row = row_number())
#> # A tibble: 4 x 5
#> x1 x2 y group_row all_df_row
#> <fct> <fct> <dbl> <int> <int>
#> 1 A a 12 1 1
#> 2 A b 2 2 2
#> 3 B a 10 1 3
#> 4 B b 23 2 4
一个用例——我可能每天都这样做是为了工作——是获取多个组内的总和(同样,x1
和 x2
),然后找到这些值在其中的份额他们更大的一组(剥去一层分组后,这是x1
)和mutate
。同样,我在这里取消组合以显示份额而不是整个数据框。
df0 %>%
group_by(x1, x2) %>%
summarise(y = sum(y)) %>%
mutate(share_in_group = y / sum(y)) %>%
ungroup() %>%
mutate(share_all_df = y / sum(y))
#> # A tibble: 4 x 5
#> x1 x2 y share_in_group share_all_df
#> <fct> <fct> <dbl> <dbl> <dbl>
#> 1 A a 12 0.857 0.255
#> 2 A b 2 0.143 0.0426
#> 3 B a 10 0.303 0.213
#> 4 B b 23 0.697 0.489
由 reprex package (v0.2.1)
创建于 2018-10-11
正如 camille 很好地展示的那样,有充分的理由希望 summarize()
的结果保留额外的分组层,这是一种 documented 行为,因此本身并不真正危险或意外。
然而,一个额外的提示是,如果您只是想在 summarize()
之后调用 ungroup()
,您不妨使用 summarize(.groups = "drop")
,这将 return 和 ungroup
ed tibble
并为您节省一行代码。
library(tidyverse)
df0 <- data.frame(
x1 = rep(LETTERS[1:2], each = 2),
x2 = rep(letters[1:2], 2),
y = floor(abs(rnorm(4) * 10))
)
df0 %>%
group_by(x1,x2) %>%
summarize(y=sum(y), .groups = "drop") %>%
arrange(desc(y)) %>%
mutate(index = row_number())
#> # A tibble: 4 x 4
#> x1 x2 y index
#> <chr> <chr> <dbl> <int>
#> 1 A b 8 1
#> 2 A a 2 2
#> 3 B a 2 3
#> 4 B b 1 4
由 reprex package (v2.0.1)
于 2022-02-06 创建
我想枚举分组产生的 dataframe/tibble 的每条记录。该索引是根据定义的顺序。如果我使用 row_number() 它会枚举但在组内。但我希望它在不考虑前一个分组的情况下进行枚举。
这是一个例子。为了简单起见,我使用了最小的数据框:
library(dplyr)
df0 <- data.frame( x1 = rep(LETTERS[1:2],each=2)
, x2 = rep(letters[1:2], 2)
, y = floor(abs(rnorm(4)*10))
)
df0
# x1 x2 y
# 1 A a 12
# 2 A b 24
# 3 B a 0
# 4 B b 12
现在,我将其分组 table:
df1 <- df0 %>% group_by(x1,x2) %>% summarize(y=sum(y))
这给了我一个 class tibble 的对象:
# A tibble: 4 x 3
# Groups: x1 [?]
# x1 x2 y
# <fct> <fct> <dbl>
# 1 A a 12
# 2 A b 24
# 3 B a 0
# 4 B b 12
我想使用 row_numer():
向此 table 添加行号 df2 <- df1 %>% arrange(desc(y)) %>% mutate(index = row_number())
df2
# A tibble: 4 x 4
# Groups: x1 [2]
# x1 x2 y index
# <fct> <fct> <dbl> <int>
# 1 A b 24 1
# 2 A a 12 2
# 3 B b 12 1
# 4 B a 0 2
row_number() 确实在前一个分组中进行了枚举。这不是我的本意。这可以避免首先将 tibble 转换为数据帧:
df2 <- df2 %>% as.data.frame() %>% arrange(desc(y)) %>% mutate(index = row_number())
df2
# x1 x2 y index
# 1 A b 24 1
# 2 A a 12 2
# 3 B b 12 3
# 4 B a 0 4
我的问题是:这种行为是故意的吗? 如果是:将以前的数据处理合并到 tibble 中不是很危险吗?合并了哪种类型的处理? 目前我会把tibble转换成dataframe来避免这种意想不到的结果。
详细说明我的评论:是的,保留分组是有意的,并且在许多情况下很有用。如果您不了解 group_by
的工作原理,那只会很危险——任何函数都是如此。要撤消 group_by
,您调用 ungroup
。
看看 group_by
docs,因为它们非常详尽,并解释了此函数如何与其他函数交互、分组如何分层等。文档还解释了每次调用 summarise
删除了一层分组——它可能会让您对发生的事情感到困惑。
例如,你可以按x1
和x2
分组,汇总y
,然后创建一个行号,它会根据x1
给你行(summarise
去掉一层分组,即去掉x2
分组)。然后取消分组允许您根据整个数据框获取行号。
library(dplyr)
df0 %>%
group_by(x1, x2) %>%
summarise(y = sum(y)) %>%
mutate(group_row = row_number()) %>%
ungroup() %>%
mutate(all_df_row = row_number())
#> # A tibble: 4 x 5
#> x1 x2 y group_row all_df_row
#> <fct> <fct> <dbl> <int> <int>
#> 1 A a 12 1 1
#> 2 A b 2 2 2
#> 3 B a 10 1 3
#> 4 B b 23 2 4
一个用例——我可能每天都这样做是为了工作——是获取多个组内的总和(同样,x1
和 x2
),然后找到这些值在其中的份额他们更大的一组(剥去一层分组后,这是x1
)和mutate
。同样,我在这里取消组合以显示份额而不是整个数据框。
df0 %>%
group_by(x1, x2) %>%
summarise(y = sum(y)) %>%
mutate(share_in_group = y / sum(y)) %>%
ungroup() %>%
mutate(share_all_df = y / sum(y))
#> # A tibble: 4 x 5
#> x1 x2 y share_in_group share_all_df
#> <fct> <fct> <dbl> <dbl> <dbl>
#> 1 A a 12 0.857 0.255
#> 2 A b 2 0.143 0.0426
#> 3 B a 10 0.303 0.213
#> 4 B b 23 0.697 0.489
由 reprex package (v0.2.1)
创建于 2018-10-11正如 camille 很好地展示的那样,有充分的理由希望 summarize()
的结果保留额外的分组层,这是一种 documented 行为,因此本身并不真正危险或意外。
然而,一个额外的提示是,如果您只是想在 summarize()
之后调用 ungroup()
,您不妨使用 summarize(.groups = "drop")
,这将 return 和 ungroup
ed tibble
并为您节省一行代码。
library(tidyverse)
df0 <- data.frame(
x1 = rep(LETTERS[1:2], each = 2),
x2 = rep(letters[1:2], 2),
y = floor(abs(rnorm(4) * 10))
)
df0 %>%
group_by(x1,x2) %>%
summarize(y=sum(y), .groups = "drop") %>%
arrange(desc(y)) %>%
mutate(index = row_number())
#> # A tibble: 4 x 4
#> x1 x2 y index
#> <chr> <chr> <dbl> <int>
#> 1 A b 8 1
#> 2 A a 2 2
#> 3 B a 2 3
#> 4 B b 1 4
由 reprex package (v2.0.1)
于 2022-02-06 创建