Tidyverse:case_when() 没有返回正确的值

Tidyverse: case_when() not returning correct value

对于一组列,我想检测哪一列具有最大值。如果列之间的值相等,那么我想用一个权重来决定哪一列select。我已经尝试使用 case_when() 来实现它,但是它不起作用。我将在下面使用示例数据集展示这个问题...

假设我有一个数据集,其中包含这三列(A、B、C),对应于 child 每天吃的苹果、香蕉或胡萝卜的数量。

对于行,我想记录消耗最多的食物(即具有最高值的列)。如果任何列之间的值相等(例如,1 个苹果和 1 个香蕉),则应用以下排名。 Apple > Banana > Carrot,如果 child 吃了 1 个 Apple 和 1 个 Banana,日志将显示 Apple。

我尝试在 R 中使用成对的 if_else 语句和 case_when() 来实现它。但是,它并不是 return 正确的结果。例如,最后一行应归类为 Apple,而不是胡萝卜。我不确定我做错了什么。请提供此问题的 Tidyverse 解决方案,如果可能,请解释为什么我的方法不起作用。

library(tidyverse)

A <- c(1,1,3,3)
B <- c(2,3,1,1)
C <- c(1,1,1,2)
df <- data.frame(A,B,C)

top_food <- df %>% 
  mutate(highest = case_when(
    C > B ~ "carrot", # if carrot > banana
    C > A ~ "carrot", # if carrot > apple 
    B > A ~ "banana", # if banana > apple 
    B >= A ~ "banana", # if banana >= carrot
    A >= B ~ "apple", # if apple  >= banana
    A >= C ~ "apple" # if apple >= carrot
  )) 

> | A | B | C | HIGHEST |  |
> | 1 | 2 | 1 | banana  |  |
> | 1 | 3 | 1 | banana  |  |
> | 3 | 1 | 1 | apple   |  |
>   3 | 1 | 2 | carrot  |  |

备注: - 这是一个示例数据集。 - 我对具有不同功能的解决方案持开放态度,但请提供 Tidyverse 答案,因为这是我学习 R 的方式。如果可能,请解释为什么我使用 case_when() 的方法不起作用,以便我可以学习。 - 维护数据集的 shape/layout 很重要,这样它就可以在 R 之外的软件中使用,所以请不要转换为长格式。

你的问题的一个解决方案(我稍微修改了数据以表明如果所有值都相同它就有效):

library(tidyverse)
df %>% 
  rowid_to_column() %>% 
  pivot_longer(-rowid) %>% 
  group_by(rowid) %>% 
  mutate(highest = name[value == max(value)],
         highest = case_when(var(value) == 0 & value == 1 ~ "apple",
                         var(value) == 0 & value == 2 ~ "banana",
                         var(value) == 0 & value == 3 ~ "carrot",
                         highest == "A" ~ "apple",
                         highest == "B"~ "banana",
                         highest == "C" ~ "carrot")) %>% 
  pivot_wider(names_from = name, values_from = value)

# A tibble: 4 x 5
# Groups:   rowid [4]
  rowid highest     A     B     C
  <int> <chr>   <dbl> <dbl> <dbl>
1     1 apple       1     1     1
2     2 banana      1     3     1
3     3 apple       3     1     1
4     4 apple       3     1     2

数据

A <- c(1,1,3,3)
B <- c(1,3,1,1)
C <- c(1,1,1,2)
df <- data.frame(A,B,C)
df

快速修复可以包含 dplyr::rowise 和 which.max()。这种方法的缺点是速度很慢。此外,我假设您的列顺序反映了水果的排名(如果有平局,which.max 将 return 第一个值)。

A <- c(1,1,3,3,1,1)
B <- c(2,3,1,1,1,2)
C <- c(1,1,1,2,1,2)

df <- data.frame(A,B,C)
labels <- c("apple","banana","carrot")

df %>%
    dplyr::rowwise() %>%
    dplyr::mutate(top=labels[which.max(c(A,B,C))]) %>%
    dplyr::ungroup()

另一种(可能更好)方法是使用 max.col()

df <- data.frame(A,B,C)
labels <- c("apple","banana","carrot")
df %>%
    dplyr::mutate(top=labels[max.col(df,ties="first")])

还有另一个独立于您的列顺序的解决方案(现在我退出了 :D):

df <- data.frame(A,B,C)

top_food <- df %>% 
    dplyr::mutate(highest = dplyr::case_when(
        C > A & C > B ~ "carrot",
        B > A & B >= C ~ "banana",
        TRUE ~ "apple"))

您使用 case_when 的方法没有奏效,因为 case_when 在找到真实条件后立即停止检查条件。由于你的第一个条件是 C>B ~ "carriot" 这对你的最后一行 (2>1) 是正确的,case_when returned "carrot" 并且没有检查其他条件.