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" 并且没有检查其他条件.
对于一组列,我想检测哪一列具有最大值。如果列之间的值相等,那么我想用一个权重来决定哪一列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" 并且没有检查其他条件.