Tidyverse: case_when () не возвращает правильное значение - PullRequest
2 голосов
/ 17 июня 2020

Для набора столбцов я использую sh, чтобы определить, какой столбец имеет максимальное значение. Если значения между столбцами равны, я хотел бы использовать вес, чтобы решить, какой столбец выбрать. Я пробовал реализовать это с помощью case_when (), но это не работает. Я покажу эту проблему ниже на примере набора данных ...

Допустим, у меня есть набор данных, который включает эти три столбца (A, B, C), которые соответствуют количеству яблок, бананов или моркови. ребенок ест в день.

Для строки я хочу зарегистрировать наиболее потребляемую пищу (т. е. столбец с наибольшим значением). Если значение в любом столбце равно (например, 1 яблоко и 1 банан), тогда применяется следующий ранг. Apple> Banana> Carrot: если ребенок съест 1 яблоко и 1 банан, в журнале будет указано Apple.

Я пробовал реализовать это в R, используя пары операторов if_else с case_when (). Однако он не возвращает правильный результат. Например, последний ряд следует отнести к категории «яблоко», а не «морковь». Я не уверен, что делаю не так. Пожалуйста, предоставьте решение этой проблемы 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 () не сработал, чтобы я мог учиться. - Важно поддерживать форму / макет набора данных, чтобы его можно было использовать в программном обеспечении за пределами R, поэтому, пожалуйста, не конвертируйте в длинный формат.

Ответы [ 2 ]

2 голосов
/ 17 июня 2020

Быстрое исправление может содержать dplyr :: rowise и which.max (). Обратной стороной этого подхода является то, что он довольно медленный. Кроме того, я предполагаю, что порядок ваших столбцов отражает ранг фруктов (если есть ie, which.max вернет первое значение).

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 вернул "carrot" и не проверил другие условия.

1 голос
/ 17 июня 2020

Одно решение вашей проблемы (я немного изменил данные, чтобы показать, что это работает, если все значения одинаковы):

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

Data

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
...