【问题标题】:Applying mutate_at conditionally to specific rows in a dataframe in R将 mutate_at 有条件地应用于 R 中数据帧中的特定行
【发布时间】:2019-01-27 04:07:04
【问题描述】:

我在 R 中有一个如下所示的数据框:

a  b  c  condition
1  4  2  acap
2  3  1  acap
2  4  3  acap
5  6  8  ncap
5  7  6  ncap
8  7  6  ncap

我正在尝试重新编码 a、b 和 c 列中条件 ncap 的值(以及此处未显示的其他 2 个条件),同时单独保留 acap 的值。

以下代码在应用于前 3 列时有效。我试图弄清楚如何将其仅应用于我按条件指定的行,同时将所有内容保存在同一个数据框中。

df = df %>%
     mutate_at(vars(a:c), function(x) 
     case_when x == 5 ~ 1, x == 6 ~ 2, x == 7 ~ 3, x == 8 ~ 4)

这是预期的输出。

a  b  c  condition
1  4  2  acap
2  3  1  acap
2  4  3  acap
1  2  4  ncap
1  3  2  ncap
4  3  2  ncap

我四处寻找这个问题的答案,但找不到。如果有人知道已经存在的答案,我将不胜感激。

【问题讨论】:

  • 尝试在row_number() 上使用ifelse 你能显示预期的输出吗?
  • 管道中的哪个位置?我尝试使用 ifelse 函数,但不知道该放在哪里。为什么在 row_number() 上而不是使用“条件”列的特定值?
  • 也可以是df %>% mutate_at(vars(a:c), funs(case_when(row_number() %in% 4:6 ~ . - 4L, TRUE ~ .)))
  • 这部分是什么意思:4:6 ~ . - 4L,真的~。我知道 4:6 是行号,但我对其余部分感到困惑。
  • 如果我查看该模式,您将通过将 4:6 行的值与 4 的差来替换值。即 5-4 = 1、6-4 =2、7 -4 =3 和 8-4=4

标签: r if-statement dplyr conditional-statements tidyverse


【解决方案1】:

我们可以在使用row_number 创建的条件上使用case_when,即如果行号是 4 到 6,则从值中减去 4,否则返回值

df %>% 
   mutate_at(vars(a:c), funs(case_when(row_number() %in% 4:6 ~ . - 4L, 
                                       TRUE ~ .)))
#  a b c condition
#1 1 4 2      acap
#2 2 3 1      acap
#3 2 4 3      acap
#4 1 2 4      ncap
#5 1 3 2      ncap
#6 4 3 2      ncap

如果这是基于值而不是行,则根据值创建条件

df %>% 
   mutate_at(vars(a:c), funs(case_when(. %in% 5:8 ~ . - 4L, 
                                       TRUE ~ .)))
#  a b c condition
#1 1 4 2      acap
#2 2 3 1      acap
#3 2 4 3      acap
#4 1 2 4      ncap
#5 1 3 2      ncap
#6 4 3 2      ncap

或者如果它基于'条件'中的值

df %>% 
   mutate_at(vars(a:c), funs(case_when(condition == 'ncap' ~ . - 4L, 
                                       TRUE ~ .)))

或者不使用任何case_when

df %>% 
  mutate_at(vars(a:c), funs( . - c(0, 4)[(condition == 'ncap')+1]))
#  a b c condition
#1 1 4 2      acap
#2 2 3 1      acap
#3 2 4 3      acap
#4 1 2 4      ncap
#5 1 3 2      ncap
#6 4 3 2      ncap

base R中,我们可以通过创建索引来做到这一点

i1 <- df$condition =='ncap'
df[i1, 1:3] <- df[i1, 1:3] - 4

数据

df <- structure(list(a = c(1L, 2L, 2L, 5L, 5L, 8L), b = c(4L, 3L, 4L, 
 6L, 7L, 7L), c = c(2L, 1L, 3L, 8L, 6L, 6L), condition = c("acap", 
 "acap", "acap", "ncap", "ncap", "ncap")), class = "data.frame", 
 row.names = c(NA, -6L))

【讨论】:

  • 在尝试使用第三个选项时,我收到此错误:“评估错误:操作只能用于数字、逻辑或复杂类型。”有什么地方可以放“as.numeric()”让它工作吗?
  • @melbez 请检查列的类别。我有 character 和数字列(如 dput 所示)
  • ~ 是什么意思?在第三个选项中重复两次是什么意思?
  • @melbez . 表示每列中的值。使用mutate_at/mutate_all,它循环遍历列。这里case_when中的条件是if'condition'值是'ncap',然后返回值.减去4,否则返回值TRUE ~ .。你可以在case_when 中有很多条件(就像你展示的那样)。根据模式,我减少了一些步骤以减去 4。
【解决方案2】:

您可以使用filter 将重新编码值仅应用于特定行(此处不等于“acap”)

library(dplyr)
df %>%
  filter(condition != "acap") %>%
  mutate_at(vars(a:c), function(x) 
  case_when(x == 5 ~ 1, x == 6 ~ 2, x == 7 ~ 3, x == 8 ~ 4)) 

#  a b c condition
#1 1 2 4      ncap
#2 1 3 2      ncap
#3 4 3 2      ncap

如果您再次需要整个数据框,我们可以这样做

df %>%
  filter(condition == "acap") %>%
  bind_rows(df %>%
     filter(condition != "acap") %>%
     mutate_at(vars(a:c), function(x) 
    case_when(x == 5 ~ 1, x == 6 ~ 2, x == 7 ~ 3, x == 8 ~ 4)))

#  a b c condition
#1 1 4 2      acap
#2 2 3 1      acap
#3 2 4 3      acap
#4 1 2 4      ncap
#5 1 3 2      ncap
#6 4 3 2      ncap

【讨论】:

  • 有没有办法让我将所有内容都保存在同一个数据框中?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-04
  • 2021-05-20
  • 2019-07-27
  • 2015-11-14
相关资源
最近更新 更多