r - 想要根据列名改变平均列的列,但还要从计算中排除某些列?
问题描述
在数据框中工作,我想使用 mutate 创建一个新列,该列根据列名将每一行中的所有列平均在一起,除了一个。我需要能够在每次使用 mutate 时排除某个列,并且我希望计算也能跳过 NA 值。
我的 DF 的简单版本:
Team stat1 stat2 stat3 stat4
1 ARI 3 NA 4 6
2 BAL NA 2 NA 1
3 CAR 5 4 6 2
NewCol1 通过计算 stat 列的平均值创建,不包括“stat 1”列和 NA 值。对 NewCol2 做了同样的事情,计算的平均值不包括“stat2”列:
Team stat1 stat2 stat3 stat4 NewCol1 NewCol2
1 ARI 3 NA 4 6 5.0 4.33
2 BAL NA 2 NA 1 1.5 1.00
3 CAR 5 4 6 2 4.0 4.33
如果我想创建对每个统计数据执行相同操作的新列,那么最有效的方法是什么?DF 有 10 个统计列,每个列都有相同的名称,每个名称后面都有一个数字。我在想starts_with() 函数可能在这里与rowMeans() 一起使用,但是我在为如何实现它而苦苦挣扎,同时也每次都排除某个列。
解决方案
我们可以rowMeans
在select
取出相关列之后使用
library(dplyr)
df1 %>%
mutate(NewCol1 = rowMeans(select(., -Team, -stat1), na.rm = TRUE),
NewCol2 = rowMeans(select(., -Team, -stat2), na.rm = TRUE))
-输出
# Team stat1 stat2 stat3 stat4 NewCol1 NewCol2
#1 ARI 3 NA 4 6 5.0 4.333333
#2 BAL NA 2 NA 1 1.5 1.000000
#3 CAR 5 4 6 2 4.0 4.333333
或另一种选择c_across
df1 %>%
rowwise %>%
mutate(NewCol1 = mean(c_across(c(where(is.numeric), -stat1)), na.rm = TRUE),
NewCol2 = mean(c_across(c(starts_with('stat'), -stat2)), na.rm = TRUE),
NewCol3 = mean(c_across(c(starts_with('stat'), -stat3)), na.rm = TRUE),
NewCol4 = mean(c_across(c(starts_with('stat'), -stat4)), na.rm = TRUE)) %>%
ungroup
-输出
# A tibble: 3 x 9
# Team stat1 stat2 stat3 stat4 NewCol1 NewCol2 NewCol3 NewCol4
# <chr> <int> <int> <int> <int> <dbl> <dbl> <dbl> <dbl>
#1 ARI 3 NA 4 6 5 4.33 4.5 3.5
#2 BAL NA 2 NA 1 1.5 1 1.5 2
#3 CAR 5 4 6 2 4 4.33 3.67 5
如果我们想自动执行此操作,可以选择
library(purrr)
df1[paste0("NewCol", 1:2)] <- map(c('stat1', 'stat2'),
~ df1 %>%
select(starts_with('stat'), -.x) %>%
rowMeans(., na.rm = TRUE))
或创建第 1 到 4 列
nm1 <- names(df1)[startsWith(names(df1), 'stat')]
df1[paste0("NewCol", seq_along(nm1))] <- map(nm1,
~ df1 %>%
select(starts_with('stat'), -.x) %>%
rowMeans(., na.rm = TRUE))
-输出
df1
# Team stat1 stat2 stat3 stat4 NewCol1 NewCol2 NewCol3 NewCol4
#1 ARI 3 NA 4 6 5.0 4.333333 4.500000 3.5
#2 BAL NA 2 NA 1 1.5 1.000000 1.500000 2.0
#3 CAR 5 4 6 2 4.0 4.333333 3.666667 5.0
或者在 tidyverse 中完全做到这一点
library(stringr)
map_dfc(nm1, ~
df1 %>%
select(starts_with('stat'), -.x) %>%
transmute(!! str_c('NewCol', readr::parse_number(.x)) :=
rowMeans(., na.rm = TRUE))) %>%
bind_cols(df1, .)
# Team stat1 stat2 stat3 stat4 NewCol1 NewCol2 NewCol3 NewCol4
#1 ARI 3 NA 4 6 5.0 4.333333 4.500000 3.5
#2 BAL NA 2 NA 1 1.5 1.000000 1.500000 2.0
#3 CAR 5 4 6 2 4.0 4.333333 3.666667 5.0
或使用rowwise/c_across
map_dfc(nm1, ~
df1 %>%
select(starts_with('stat'), -.x) %>% rowwise %>%
transmute(!! str_c('NewCol', readr::parse_number(.x)) := mean(c_across(everything()), na.rm = TRUE))) %>%
ungroup %>%
bind_cols(df1, .)
-输出
# Team stat1 stat2 stat3 stat4 NewCol1 NewCol2 NewCol3 NewCol4
#1 ARI 3 NA 4 6 5.0 4.333333 4.500000 3.5
#2 BAL NA 2 NA 1 1.5 1.000000 1.500000 2.0
#3 CAR 5 4 6 2 4.0 4.333333 3.666667 5.0
或使用base R
df1[paste0("NewCol", seq_along(nm1))] <- lapply(nm1,
function(x) rowMeans(df1[setdiff(names(df1)[-1], x)], na.rm = TRUE))
数据
df1 <- structure(list(Team = c("ARI", "BAL", "CAR"), stat1 = c(3L, NA,
5L), stat2 = c(NA, 2L, 4L), stat3 = c(4L, NA, 6L), stat4 = c(6L,
1L, 2L)), class = "data.frame", row.names = c("1", "2", "3"))
推荐阅读
- c - 如何从二进制文件中读取反转的数字?
- apache-pig - 如何在 Pig 中比较 BIGINT
- django - Django(PostgreSQL)查询过滤器以排除给定字母
- sql - 如何重置 Sequel Pro 的密码?
- android - 在 Kotlin 中使用片段
- javascript - 根据数组中的对象属性生成带有头部的列表
- wordpress - 如何将超链接放在 wordpress 中复选框消息旁边的联系表单中?
- python - 在 ArcGIS 中使用 Python 时向 Pycharm 添加外部库
- jquery - 使用jQuery上下滚动到div id
- python - 更改 Spark Web UI 的根路径?