Условное добавление строки в канал

У меня есть тиббл, содержащий события и их вероятности. Количество исходов может быть два (Да/Нет) или больше (A/B/C/...). В последнем случае у меня есть исчерпывающий список событий, поэтому я не хочу ничего делать:

ok <- tibble(
    event = c("A", "B", "C"), 
    prob = c(0.1, 0.5, 0.4)
)

Если есть только два события, у меня есть только одна строка для вероятности возникновения события:

not_ok <- tibble(
    event = "Yes", 
    prob = 0.4
)

Эти тибблы изменяются в цепочке каналов. В какой-то момент я хочу добавить строку «Нет» к тибблам второго типа.

В настоящее время я прерываю трубу, чтобы сделать:

if (nrow(not_ok) == 1) {
    not_ok %<>%
        add_row(event = "No", prob = 1-not_ok$prob)
}

И тогда я возобновляю трубку. Однако делать это медленно, некрасиво и требует большего количества заданий.

Можно ли включить этот условный оператор в цепочку каналов, не создавая отдельно оператор if? Код в конечном итоге должен выглядеть так:

data %>% 
    do something %>% 
    add row with "No" if necessary %>% 
    do something else %>% 
    plot

Если возможно, я бы хотел избежать использования глобальных присваиваний или функций.


Для ясности: данные поступают из запроса к серверу, поэтому я не знаю, вытягивает ли конкретный запрос тиббл типа ok или not_ok. Мне нужна одна операция, которая работает в обоих случаях: в первом случае ничего не делается, а во втором — добавление строки. Например, то, что я делаю сейчас, работает, потому что я использую функцию if для редактирования not_ok только в том случае, если это результат запроса. Например:

fread("...") %>% 
    mutate(...) %>% 
    add row if nrow == one
tidyr::expand() или tidyr::complete должны делать то, что вы хотите, в зависимости от вашего конкретного варианта использования. Все, что вам понадобится, это вектор всех возможных event. Добавьте mutate, чтобы получить оставшуюся вероятность. Если есть вероятность или несколько пропущенных типов event, вам придется определить, как распределить вероятности.
Limey 26.05.2024 13:30

Проблема в том, как сделать это обусловленным количеством строк. Если оно больше единицы, то уже все в порядке. Если есть одна строка, это «Да». поэтому я хочу добавить строку «Нет».

FBr 26.05.2024 13:39

Я что-то упускаю: разве это не именно то, что я сделал? или вы говорите, что порядок важен, поэтому «добавить» означает «добавить в конец»?

Limey 26.05.2024 13:44

Извините, я не увидел вашего ответа. Я отвечу на это.

FBr 26.05.2024 13:50
Стоит ли изучать 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
4
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Вот решение с использованием complete:

not_ok %>% 
  complete(
    event = c("Yes", "No"),
    fill = list(prob = (1 - sum(not_ok$prob)))
  )
# A tibble: 2 × 2
  event  prob
  <chr> <dbl>
1 No      0.6
2 Yes     0.4

тогда как ok остается неизменным:

ok %>% 
  complete(
    event = c("A", "B", "C"),
    fill = list(prob = (1 - sum(not_ok$prob)))
  )
# A tibble: 3 × 2
  event  prob
  <chr> <dbl>
1 A       0.1
2 B       0.5
3 C       0.4

Если ваш тиббл сгруппирован или вам нужно более сложное вменение, небольшого изменения должно быть достаточно.

Редактировать

В ответ на комментарий ОП, вот как инкапсулировать эту функциональность в функцию, удобную для канала.

make_complete <- function(df, event_list) {
  df %>% 
  complete(
    event = event_list,
    fill = list(prob = (1 - sum(df$prob)))
  )
}

После которого

not_ok %>% make_complete(c("Yes", "No"))

и

ok %>% make_complete(c("A", "B", "C"))

Оба дают ожидаемый результат, указанный выше. Функция явно может быть встроена в более длинный канал.

Что касается вашего комментария: «Я бы хотел избежать использования... функций». Я не понимаю, как можно сделать это обобщенным без использования функции...

Это работает, но, возможно, мне не совсем понятны данные. Оно происходит от какой-то функции, поэтому назовите его в общем виде df. Мне нужно сделать операцию, которая работает как для ok, так и для not_ok, потому что я не знаю, какая именно. Внесу правку в исходный пост.

FBr 26.05.2024 13:53

Как я показываю, это работает в обоих случаях. если вы хотите интегрировать его в свой канал, инкапсулируйте его в функцию, первым параметром которой является фрейм данных, а вторым — полный список значений event.

Limey 26.05.2024 14:32

Спасибо за написание функции. Проблема заключалась в том, что, поскольку я не знаю, являются ли мои данные ok или not_ok, у меня нет event_list, который можно было бы предоставить функции. Но работает следующее: df %>% make_complete(event_list = if (nrow(df) == 1) {c("Yes", "No")} else { df$event }). Это работает как df <- ok, добавляя строку, так и df <- not_ok, ничего не делая.

FBr 26.05.2024 14:46

Создайте тиббл events всех событий, eventsdf, присоедините его к not_ok, а затем используйте coalesce, чтобы заполнить NA, если таковой имеется.

library(dplyr)
    
f <- function(df, all_events) {
  eventsdf <- tibble(event = all_events)
  df %>%
    right_join(eventsdf, by = "event") %>%
    mutate(prob = coalesce(prob, 1 - sum(prob, na.rm = TRUE)))
}
    
f(not_ok, c("Yes", "No"))
## # A tibble: 2 × 2
##   event  prob
##   <chr> <dbl>
## 1 Yes     0.4
## 2 No      0.6

f(ok, c("A", "B", "C"))
## # A tibble: 3 × 2
##   event  prob
##   <chr> <dbl>
## 1 A       0.1
## 2 B       0.5
## 3 C       0.4

Спасибо, пожалуйста, посмотрите редактирование исходного сообщения. Это работает для изменения тиббла not_ok, но данные поступают из запроса и могут быть либо ok, либо not_ok, поэтому мне нужен условный оператор, который работает с последним.

FBr 26.05.2024 13:57

Пересмотрели. Теперь должно работать в обоих случаях.

G. Grothendieck 26.05.2024 14:10

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