Case_when терпит неудачу, когда условие проверяет несуществующие строки

Рассмотрим эти данные:

df <- data.frame(group  = c(1, 2, 2, 2),
                 start  = c(2, 7, 7, 7),
                 stop   = c(8, 7, 8, 9),
                 unstop = c(10, 7, 9, 10))

Теперь я хочу настроить более или менее простой case_when для каждой группы в виде «если первая строка сделает это, если вторая строка сделает то». Однако я получаю сообщение об ошибке. Я предполагаю, что это потому, что в группе 1 есть только одна строка, поэтому условие не может быть проверено:

df |>
  group_by(group) |> 
  mutate(n_rows = n(),
         split_weeks = case_when(n_rows == 1 ~ str_c(start:stop, collapse = ","),
                                 n_rows  > 1 & row_number() == 1 ~ str_c(c(start:stop, unstop:lead(stop)), collapse = ","),
                                 TRUE ~ "fail"))

Error in `mutate()`:
! Problem while computing `split_weeks = case_when(...)`.
ℹ The error occurred in group 1: group = 1.
Caused by error in `unstop:lead(stop)`:
! NA/NaN argument
Run `rlang::last_error()` to see where the error occurred.

Есть идеи, что здесь происходит?

Я предполагаю, что это связано с функцией lead, потому что, если я удалю эту часть, я «получу только предупреждения, но, по крайней мере, я получу результат.

Ожидаемый результат:

# A tibble: 4 × 6
# Groups:   group [2]
  group start  stop unstop n_rows split_weeks  
  <dbl> <dbl> <dbl>  <dbl>  <int> <chr>        
1     1     2     8     10      1 2,3,4,5,6,7,8
2     2     7     7      7      3 7,8          
3     2     7     8      9      3 fail         
4     2     7     9     10      3 fail         
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
39
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я думаю, что ошибки возникают, когда вы просите R найти lead либо а) за концом строк таблицы, либо б) за пределами группы. Вы можете передать ему значение по умолчанию, равное 0, которое никогда не используется и подавляет ошибку, но выполняется только на полпути, поскольку функция пытается объединить каждое значение start:stop и unstop:lead(stop) во всех строках в группе:

library(tidyverse)

df <- data.frame(group  = c(1, 2, 2, 2),
                 start  = c(2, 7, 7, 7),
                 stop   = c(8, 7, 8, 9),
                 unstop = c(10, 7, 9, 10))


df |>
  group_by(group) |>
  mutate(
    n_rows = n(),
    split_weeks = case_when(
      n_rows == 1 ~ str_c(start:stop, collapse = ","),
      n_rows  > 1 &
        row_number() == 1 ~ str_c(c(start:stop, unstop:lead(stop, default = 0)), collapse = ","),
      TRUE ~ "fail"
    )
  )
#> Warning in start:stop: numerical expression has 3 elements: only the first used

#> Warning in start:stop: numerical expression has 3 elements: only the first used

#> Warning in start:stop: numerical expression has 3 elements: only the first used

#> Warning in start:stop: numerical expression has 3 elements: only the first used
#> Warning in unstop:lead(stop, 0): numerical expression has 3 elements: only the
#> first used

#> Warning in unstop:lead(stop, 0): numerical expression has 3 elements: only the
#> first used
#> # A tibble: 4 × 6
#> # Groups:   group [2]
#>   group start  stop unstop n_rows split_weeks  
#>   <dbl> <dbl> <dbl>  <dbl>  <int> <chr>        
#> 1     1     2     8     10      1 2,3,4,5,6,7,8
#> 2     2     7     7      7      3 7,7          
#> 3     2     7     8      9      3 fail         
#> 4     2     7     9     10      3 fail

Способ уборки будет следующим:

  • поиск значений потенциальных клиентов вне групп (по умолчанию, чтобы избежать ошибки в последней строке)
  • найти количество строк и номера строк в группах
  • снова разгруппировать!
  • выполнять вычисления по строкам, чтобы R фокусировался только на значениях в этой строке
  • выполнить конкатенацию

Что заканчивается так, хотя не уверен, почему 7,7,8 помещается в эту ячейку (имеет смысл, поскольку он объединяет 7 с 7 и 7 с 8):

df |> 
  mutate(lead_stop = lead(stop, default = 0)) |>
  group_by(group) |>
  mutate(
    n_rows = n(),
    rownum = row_number()) |>
  ungroup() |>
  rowwise() |>
  mutate(
    split_weeks = case_when(
      rownum > 1 ~ "fail",
      n_rows == 1 ~ str_c(start:stop, collapse = ","),
      n_rows  > 1 & rownum == 1 ~ str_c(c(start:stop, unstop:lead_stop), collapse = ","),
      TRUE ~ "fail"
    )
  )
#> # A tibble: 4 × 8
#> # Rowwise: 
#>   group start  stop unstop lead_stop n_rows rownum split_weeks  
#>   <dbl> <dbl> <dbl>  <dbl>     <dbl>  <int>  <int> <chr>        
#> 1     1     2     8     10         7      1      1 2,3,4,5,6,7,8
#> 2     2     7     7      7         8      3      1 7,7,8        
#> 3     2     7     8      9         9      3      2 fail         
#> 4     2     7     9     10         0      3      3 fail

Created on 2022-05-07 by the reprex package (v2.0.1)

У меня тоже было такое подозрение. Спасибо за решение. Я действительно удивлен, что lead не придерживается группировки, применяемой к моим данным.

deschen 07.05.2022 01:23

Вот альтернатива, которая дает желаемый результат (по крайней мере, в этом случае). @Энди Бакстер дал хорошее объяснение того, почему оригинал терпит неудачу; несмотря на то, что case_when использует результат первого случая, второй случай выдает ошибку, поэтому операция завершается неудачно. Вы можете обойти это, используя lead(stop, default = 0) или, возможно, coalesce(lead(stop), SOMETHING), любой из которых даст вычисляемый (если бессмысленный/ненужный) результат, когда нет «следующего» значения.

df |>
  group_by(group) |> 
  mutate(n_rows = n()) %>%
  mutate(split_weeks = case_when(
    n_rows == 1 ~ str_c(start:stop, collapse = ","),
    n_rows  > 1 & row_number() == 1 ~ str_c(unstop:(lead(stop, default = 0)), collapse = ","),
    # n_rows  > 1 & row_number() == 1 ~ str_c(unstop:(coalesce(lead(stop), unstop)), collapse = ","), # Alternative
    TRUE ~ "fail"))

Результат

# A tibble: 4 × 6
# Groups:   group [2]
  group start  stop unstop n_rows split_weeks  
  <dbl> <dbl> <dbl>  <dbl>  <int> <chr>        
1     1     2     8     10      1 2,3,4,5,6,7,8
2     2     7     7      7      3 7,8          
3     2     7     8      9      3 fail         
4     2     7     9     10      3 fail   

Спасибо Джон - это более аккуратный способ выразить это! Я был заинтригован, обнаружив, что case_when, похоже, не выполняет ленивую оценку — он вычисляет значение при каждом ИСТИННОМ условии, а затем возвращается к первому. Ошибки, возникающие там, где они не имеют значения, являются интересным побочным эффектом!

Andy Baxter 07.05.2022 01:38

Чтобы добавить к этому выше, кажется, что даже Хэдли отказался от попыток найти способ обойти это! github.com/tidyverse/dplyr/issues/6158

Andy Baxter 07.05.2022 01:41

Интересно узнать об этих ограничениях case_when.

deschen 07.05.2022 15:06

Другие вопросы по теме