【问题标题】:Exclude column in `dplyr` `mutate_at` while using data in this column在使用此列中的数据时排除 `dplyr` `mutate_at` 中的列
【发布时间】:2019-04-29 11:48:36
【问题描述】:

我想将df 中的所有变量(但yeargender)重新调整为一个特定的year,按gender 分组:

set.seed(1)
df <- data.frame(gender = c(rep("m", 5), rep("f", 5)), year = rep(1:5, 2), var_a = 1:10, var_b = 0:9)
df

   gender year var_a var_b
1       m    1     1     0
2       m    2     2     1
3       m    3     3     2
4       m    4     4     3
5       m    5     5     4
6       f    1     6     5
7       f    2     7     6
8       f    3     8     7
9       f    4     9     8
10      f    5    10     9

我可以使用以下方法生成我期望的内容:

df %>% group_by(gender) %>% mutate(var_a = ifelse(year == 3, 0, var_a - var_a[year == 3])) %>%
  mutate(var_b = ifelse(year == 3, 0, var_b - var_b[year == 3]))

   gender  year var_a var_b
   <fct>  <int> <dbl> <dbl>
 1 m          1    -2    -2
 2 m          2    -1    -1
 3 m          3     0     0
 4 m          4     1     1
 5 m          5     2     2
 6 f          1    -2    -2
 7 f          2    -1    -1
 8 f          3     0     0
 9 f          4     1     1
10 f          5     2     2

但是,这不是一个选项,因为我的列太多。

所以我尝试了(没有成功):

df %>% group_by(gender) %>% mutate_at(vars(-gender, -year), ifelse(year == 3, 0, var_a - var_a[year == 3]))

ifelse(year == 3, 0, var_a - var_a[year == 3]) 中的错误:对象 未找到“年份”

如何使用vars(-col_name) 排除mutate_at(或替代方法)中的列名,同时仍读取这些列中的数据?

这与this one有关

【问题讨论】:

  • 值得添加sessionInfo() 输出。

标签: r dplyr


【解决方案1】:

如果你在函数前添加~,你应该得到想要的输出。

library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union
set.seed(1)
df <- data.frame(gender = c(rep("m", 5),
                            rep("f", 5)), 
                 year = rep(1:5, 2), var_a = 1:10, var_b = 0:9)
df
#>    gender year var_a var_b
#> 1       m    1     1     0
#> 2       m    2     2     1
#> 3       m    3     3     2
#> 4       m    4     4     3
#> 5       m    5     5     4
#> 6       f    1     6     5
#> 7       f    2     7     6
#> 8       f    3     8     7
#> 9       f    4     9     8
#> 10      f    5    10     9

df %>%
  group_by(gender) %>% 
  mutate_at(vars(-gender, -year),
            ~ifelse(year == 3, 0, . - .[year == 3]))
#> # A tibble: 10 x 4
#> # Groups:   gender [2]
#>    gender  year var_a var_b
#>    <fct>  <int> <dbl> <dbl>
#>  1 m          1    -2    -2
#>  2 m          2    -1    -1
#>  3 m          3     0     0
#>  4 m          4     1     1
#>  5 m          5     2     2
#>  6 f          1    -2    -2
#>  7 f          2    -1    -1
#>  8 f          3     0     0
#>  9 f          4     1     1
#> 10 f          5     2     2

reprex package (v0.2.1) 于 2019 年 4 月 29 日创建

编辑: 在旧版本的 dplyr 中,您将使用 funs(),但从 dplyr 0.8.0 开始,它已被软弃用

df %>%
  group_by(gender) %>% 
  mutate_at(vars(-gender, -year),
            funs(ifelse(year == 3, 0, . - .[year == 3])))

【讨论】:

  • 问题不在于vars(-gender, -year),而在于转换函数。我认为只有这个答案才能指出这一点。更笼统地说:mutate_at(vars(-gender, -year), ~ ifelse(year == 3, 0, . - .[year == 3]))
  • 这可能是由于旧版本的 dplyr,尝试安装新版本。
【解决方案2】:

使用mutate_at中的位置

library(dplyr)

df %>%
  group_by(gender) %>%
  mutate_at(-c(1, 2), ~ifelse(year == 3, 0, . - .[year == 3]))

#  gender  year var_a var_b
#   <fct>  <int> <dbl> <dbl>
# 1 m          1    -2    -2
# 2 m          2    -1    -1
# 3 m          3     0     0
# 4 m          4     1     1
# 5 m          5     2     2
# 6 f          1    -2    -2
# 7 f          2    -1    -1
# 8 f          3     0     0
# 9 f          4     1     1
#10 f          5     2     2

如果事先不知道列的位置,可以先找到

cols <- which(names(df) %in% c("gender", "year"))

df %>%
  group_by(gender) %>%
  mutate_at(-cols, ~ifelse(year == 3, 0, . - .[year == 3]))

或者选择starts_with的列

df %>%
  group_by(gender) %>%
  mutate_at(vars(starts_with("var")), ~ifelse(year == 3, 0, . - .[year == 3]))

【讨论】:

  • @symbolrush 我认为 ifelse 之前的 ~ 是这里的关键。
  • 实际上@symbolrush 的原始解决方案在函数调用转换为公式时工作得很好,即。通过添加~
  • ifelse(year == 3, 0, var_a - var_a[year == 3])ifelse(year == 3, 0, var_a - var_a) 不是相同的指令吗?首先,else子句只会在year == 3时执行。
猜你喜欢
  • 2017-11-15
  • 2017-01-05
  • 1970-01-01
  • 2018-01-19
  • 1970-01-01
  • 2018-07-06
  • 2018-09-14
相关资源
最近更新 更多