组不为 NA 时的汇总统计
summary statistics when group is not NA
我想计算第 1 组、第 2 组和第 3 组的体重和身高汇总统计数据(均值、范围)。我正在专门寻找一种方法,通过在第 1 组不可用时计算汇总统计数据来实现此目的NA(计算第 1 组)
当列不是 NA 时,第 2 组也是如此。
在下面的示例中,第 1 组的权重为 3,2,第 2 组的权重为 3,5
dt <- tibble(
group1 = c(1, 1, NA, NA, NA, NA),
group2 = c(NA, NA, 2, 2, NA, NA),
group3 = c(NA, NA, NA, NA, 3, 3),
weight = c(3, 2, 3, 5, NA, 7),
height = c(10, NA, 14, 15, 11, 20)
)
您可以找到每个组的摘要统计信息,然后过滤掉 NA。以group1为例
dt %>%
group_by(group1) %>%
summarise(mean_weight = mean(weight, na.rm=T),
mean_height = mean(height, na.rm=T),
.groups = 'drop') %>%
filter(!(is.na(group1)))
你可以试试
library(dplyr)
library(tidyr)
dt %>%
group_by(group = coalesce(group1, group2, group3)) %>%
summarize(
mean_weight = mean(weight, na.rm = TRUE),
mean_height = mean(height, na.rm = TRUE)
)
哪个returns
# A tibble: 3 x 3
group mean_weight mean_height
<dbl> <dbl> <dbl>
1 1 2.5 10
2 2 4 14.5
3 3 7 15.5
如果每行有多个组,您可以使用
dt %>%
pivot_longer(
starts_with("group"),
values_drop_na = TRUE,
values_to = "group"
) %>%
group_by(group) %>%
summarize(
mean_weight = mean(weight, na.rm = TRUE),
mean_height = mean(height, na.rm = TRUE)
)
其中returns基本相同
# A tibble: 3 x 3
group mean_weight mean_height
<dbl> <dbl> <dbl>
1 1 2.5 10
2 2 4 14.5
3 3 7 15.5
这是如何工作的?
- 首先,我们使用
pivot_longer
将数据转换为“长”格式。我们获取以“组”(starts_with("group")
) 开头的每一列。这些列名称进入新列 name
(默认名称,您可以使用 names_to = "YourNewColumnNameHere"
更改它)。这些值使用 values_to = "group"
放入新列 group
。如果不使用此参数,默认情况下,值存储在 value
列中。 values_drop_na = TRUE
处理包含 NA
值的每个单元格。这些被删除。
所以在使用 pivot_longer
之后,转换后的数据看起来像
# A tibble: 6 x 4
weight height name group
<dbl> <dbl> <chr> <dbl>
1 3 10 group1 1
2 2 NA group1 1
3 3 14 group2 2
4 5 15 group2 2
5 NA 11 group3 3
6 7 20 group3 3
- 接下来我们
group_by(group)
因此接下来的转换将应用于每个独立的组并且不会相互影响。
summarize
进行分组并计算每个组的新列。删除所有其他列。 mean()
的 na.rm = TRUE
参数处理 NA
值:那些被忽略。如果没有这个参数,组 3
的 mean_weight
将是 NA
.
编辑
多亏了 akruns 的评论,这可以推广到多列,而无需使用 big-bang-operator:
进行重塑
dt %>%
group_by(group = coalesce(!!! select(., starts_with('group')))) %>%
summarise(across(c(weight, height), mean, na.rm = TRUE))
akrun 使用更高级的方法:
- 核心是复杂的
group_by
语句。
coalesce()
是一个函数,用于按参数顺序获取第一个非 NA
元素。例如:coalesce(NA_real_, 1, 2)
returns 1
因为这是第一个非 NA
值。由于 coalesce()
已矢量化,因此 coalesce(group1, group2, group3)
并且您的组列每行仅包含一个值
dt %>%
group_by(group = coalesce(group1, group2, group3))
returns 一个已经分组的小标题。
# A tibble: 6 x 6
# Groups: group [3]
group1 group2 group3 weight height group
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 NA NA 3 10 1
2 1 NA NA 2 NA 1
3 NA 2 NA 3 14 2
4 NA 2 NA 5 15 2
5 NA NA 3 NA 11 3
6 NA NA 3 7 20 3
- 如果有 many/multiple 列名为
"group"
,我们不想键入 coalesce(group1, ... , group100)
。所以我们正在使用一个函数,它选择所有这些列。这里 !!! select(., starts_with('group'))
是最好的方法:获取 data.frame 的每一列以“组”开头。不幸的是, select
returns a data.frame (这是向量列表的特殊版本)。我们需要提供 coalesce
多个向量作为参数。 矢量列表 无法完成工作:
dt %>%
group_by(group = coalesce(select(., starts_with('group'))))
returns
# Groups: group [3]
group1 group2 group3 weight height group$group1 $group2 $group3
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 NA NA 3 10 1 NA NA
2 1 NA NA 2 NA 1 NA NA
3 NA 2 NA 3 14 NA 2 NA
4 NA 2 NA 5 15 NA 2 NA
5 NA NA 3 NA 11 NA NA 3
6 NA NA 3 7 20 NA NA 3
这不是我们要找的。 big-bang-operator !!!
将这个 向量列表 分成多个单个向量,这些向量作为参数提供给 coalesce
。所以
dt %>%
group_by(group = coalesce(!!! select(., starts_with('group'))))
returns
# A tibble: 6 x 6
# Groups: group [3]
group1 group2 group3 weight height group
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 NA NA 3 10 1
2 1 NA NA 2 NA 1
3 NA 2 NA 3 14 2
4 NA 2 NA 5 15 2
5 NA NA 3 NA 11 3
6 NA NA 3 7 20 3
- 所以现在我们有一个分组数据。frame/tibble 我们可以应用
summarise
函数:summarise(across(c(weight, height), mean, na.rm = TRUE))
。 across()
告诉 summarise
将带有参数 na.rm = TRUE
的函数 mean
应用于列 weight
和 height
。这是 的更优雅的版本
summarize(
mean_weight = mean(weight, na.rm = TRUE),
mean_height = mean(height, na.rm = TRUE)
)
没有重命名(也可以用 across
完成)。
选项data.table
library(data.table)
setDT(dt)[, lapply(.SD, mean, na.rm = TRUE),
.(group = fcoalesce(group1, group2, group3)),
.SDcols = c('weight', 'height')]
group weight height
1: 1 2.5 10.0
2: 2 4.0 14.5
3: 3 7.0 15.5
我想计算第 1 组、第 2 组和第 3 组的体重和身高汇总统计数据(均值、范围)。我正在专门寻找一种方法,通过在第 1 组不可用时计算汇总统计数据来实现此目的NA(计算第 1 组) 当列不是 NA 时,第 2 组也是如此。
在下面的示例中,第 1 组的权重为 3,2,第 2 组的权重为 3,5
dt <- tibble(
group1 = c(1, 1, NA, NA, NA, NA),
group2 = c(NA, NA, 2, 2, NA, NA),
group3 = c(NA, NA, NA, NA, 3, 3),
weight = c(3, 2, 3, 5, NA, 7),
height = c(10, NA, 14, 15, 11, 20)
)
您可以找到每个组的摘要统计信息,然后过滤掉 NA。以group1为例
dt %>%
group_by(group1) %>%
summarise(mean_weight = mean(weight, na.rm=T),
mean_height = mean(height, na.rm=T),
.groups = 'drop') %>%
filter(!(is.na(group1)))
你可以试试
library(dplyr)
library(tidyr)
dt %>%
group_by(group = coalesce(group1, group2, group3)) %>%
summarize(
mean_weight = mean(weight, na.rm = TRUE),
mean_height = mean(height, na.rm = TRUE)
)
哪个returns
# A tibble: 3 x 3
group mean_weight mean_height
<dbl> <dbl> <dbl>
1 1 2.5 10
2 2 4 14.5
3 3 7 15.5
如果每行有多个组,您可以使用
dt %>%
pivot_longer(
starts_with("group"),
values_drop_na = TRUE,
values_to = "group"
) %>%
group_by(group) %>%
summarize(
mean_weight = mean(weight, na.rm = TRUE),
mean_height = mean(height, na.rm = TRUE)
)
其中returns基本相同
# A tibble: 3 x 3
group mean_weight mean_height
<dbl> <dbl> <dbl>
1 1 2.5 10
2 2 4 14.5
3 3 7 15.5
这是如何工作的?
- 首先,我们使用
pivot_longer
将数据转换为“长”格式。我们获取以“组”(starts_with("group")
) 开头的每一列。这些列名称进入新列name
(默认名称,您可以使用names_to = "YourNewColumnNameHere"
更改它)。这些值使用values_to = "group"
放入新列group
。如果不使用此参数,默认情况下,值存储在value
列中。values_drop_na = TRUE
处理包含NA
值的每个单元格。这些被删除。 所以在使用pivot_longer
之后,转换后的数据看起来像
# A tibble: 6 x 4
weight height name group
<dbl> <dbl> <chr> <dbl>
1 3 10 group1 1
2 2 NA group1 1
3 3 14 group2 2
4 5 15 group2 2
5 NA 11 group3 3
6 7 20 group3 3
- 接下来我们
group_by(group)
因此接下来的转换将应用于每个独立的组并且不会相互影响。 summarize
进行分组并计算每个组的新列。删除所有其他列。mean()
的na.rm = TRUE
参数处理NA
值:那些被忽略。如果没有这个参数,组3
的mean_weight
将是NA
.
编辑
多亏了 akruns 的评论,这可以推广到多列,而无需使用 big-bang-operator:
进行重塑dt %>%
group_by(group = coalesce(!!! select(., starts_with('group')))) %>%
summarise(across(c(weight, height), mean, na.rm = TRUE))
akrun 使用更高级的方法:
- 核心是复杂的
group_by
语句。 coalesce()
是一个函数,用于按参数顺序获取第一个非NA
元素。例如:coalesce(NA_real_, 1, 2)
returns1
因为这是第一个非NA
值。由于coalesce()
已矢量化,因此coalesce(group1, group2, group3)
并且您的组列每行仅包含一个值
dt %>%
group_by(group = coalesce(group1, group2, group3))
returns 一个已经分组的小标题。
# A tibble: 6 x 6
# Groups: group [3]
group1 group2 group3 weight height group
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 NA NA 3 10 1
2 1 NA NA 2 NA 1
3 NA 2 NA 3 14 2
4 NA 2 NA 5 15 2
5 NA NA 3 NA 11 3
6 NA NA 3 7 20 3
- 如果有 many/multiple 列名为
"group"
,我们不想键入coalesce(group1, ... , group100)
。所以我们正在使用一个函数,它选择所有这些列。这里!!! select(., starts_with('group'))
是最好的方法:获取 data.frame 的每一列以“组”开头。不幸的是,select
returns a data.frame (这是向量列表的特殊版本)。我们需要提供coalesce
多个向量作为参数。 矢量列表 无法完成工作:
dt %>%
group_by(group = coalesce(select(., starts_with('group'))))
returns
# Groups: group [3]
group1 group2 group3 weight height group$group1 $group2 $group3
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 NA NA 3 10 1 NA NA
2 1 NA NA 2 NA 1 NA NA
3 NA 2 NA 3 14 NA 2 NA
4 NA 2 NA 5 15 NA 2 NA
5 NA NA 3 NA 11 NA NA 3
6 NA NA 3 7 20 NA NA 3
这不是我们要找的。 big-bang-operator !!!
将这个 向量列表 分成多个单个向量,这些向量作为参数提供给 coalesce
。所以
dt %>%
group_by(group = coalesce(!!! select(., starts_with('group'))))
returns
# A tibble: 6 x 6
# Groups: group [3]
group1 group2 group3 weight height group
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 1 NA NA 3 10 1
2 1 NA NA 2 NA 1
3 NA 2 NA 3 14 2
4 NA 2 NA 5 15 2
5 NA NA 3 NA 11 3
6 NA NA 3 7 20 3
- 所以现在我们有一个分组数据。frame/tibble 我们可以应用
summarise
函数:summarise(across(c(weight, height), mean, na.rm = TRUE))
。across()
告诉summarise
将带有参数na.rm = TRUE
的函数mean
应用于列weight
和height
。这是 的更优雅的版本
summarize(
mean_weight = mean(weight, na.rm = TRUE),
mean_height = mean(height, na.rm = TRUE)
)
没有重命名(也可以用 across
完成)。
选项data.table
library(data.table)
setDT(dt)[, lapply(.SD, mean, na.rm = TRUE),
.(group = fcoalesce(group1, group2, group3)),
.SDcols = c('weight', 'height')]
group weight height
1: 1 2.5 10.0
2: 2 4.0 14.5
3: 3 7.0 15.5