Более быстрый способ добавить вычисляемый столбец

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

Это мои входные данные

InputData = data.frame(A = c("", "", "Apple"), B = c("", "", "Orange"), C = c("", "", ""), D = c(0, 1, 1))

Это мой желаемый результат

OutputData = InputData %>%
  mutate(R = case_when(A=='' & B=='' & C=='' & D==0 ~ "Yes", TRUE ~ "No"))

Я пробовал мутировать с помощью функции Case. Он работает нормально, но это занимает больше времени, когда у меня больше строк.

Пожалуйста, помогите мне сделать это быстрее.

Почему вы копируете весь data.frame, когда хотите просто добавить столбец? Насколько велик ваш data.frame? Каковы типы данных/классы столбцов от A до D? Является ли D действительно столбцом символов, как в примере? Почему это не числовое значение с NA для пропущенных значений?

Roland 30.03.2023 09:20

В моем фрейме данных более 1 lac строк, а столбец D является числовым столбцом. Эти входные данные - всего лишь пример моей постановки задачи.

ParthaSarathi 30.03.2023 09:26
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Я удивлен, что ваш код работает медленно с такими небольшими данными (всего 100 тыс. строк). Я бы сделал это так:

InputData$R <- "No"
InputData[InputData$A == '' & InputData$B == '' &
            InputData$C == '' & InputData$D == 0, "R"] <- "Yes"

Однако я настоятельно рекомендую использовать логические значения вместо «Да»/«Нет»:

InputData$S <- InputData$A == '' & InputData$B == '' &
  InputData$C == '' & InputData$D == 0
#      A      B C D   R     S
#1                0 Yes  TRUE
#2                1  No FALSE
#3 Apple Orange   1  No FALSE

Если это все еще слишком медленно, пакет data.table может помочь. Но в этом нет необходимости, если только данные не станут действительно большими.

Я использовал это решение с логическими значениями. Сейчас это быстро. Большое спасибо за решение @Roland

ParthaSarathi 30.03.2023 10:52

Далее следует простой тест. Кажется, что если вы просто хотите разделить столбец на две части, if_else предпочтительнее case_when в dplyr. Если вас волнует скорость, измените рабочий процесс на base, как @Roland answer.

InputData = data.frame(A = sample(c('x', ''), 1e5, TRUE),
                       B = sample(c('x', ''), 1e5, TRUE),
                       C = sample(c('x', ''), 1e5, TRUE),
                       D = sample(0:1, 1e5, TRUE))

library(dplyr)

bench::mark(
  "base::ifelse" = InputData %>% mutate(R = ifelse(A == '' & B == '' & C == '' & D == 0, "Yes", "No")),
  "dplyr::case_when" = InputData %>% mutate(R = case_when(A == '' & B == '' & C == '' & D == 0 ~ "Yes", TRUE ~ "No")),
  "dplyr::if_else" = InputData %>% mutate(R = if_else(A == '' & B == '' & C == '' & D == 0, "Yes", "No")),
  "base::repalce" = InputData %>% mutate(R = "No", R = replace(R, A == '' & B == '' & C == '' & D == 0, "Yes")),
  "base::`[<-`.Roland" = local({
    InputData$R <- "No"
    InputData$R[InputData$A == '' & InputData$B == '' & InputData$C == '' & InputData$D == 0] <- "Yes"
    InputData
  }),
  iterations = 100
)

# # A tibble: 5 × 9
#   expression              min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
#   <bch:expr>         <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
# 1 base::ifelse        24.87ms  25.82ms      38.0    7.63MB     17.1    69    31      1.82s
# 2 dplyr::case_when    15.65ms  16.91ms      57.0     8.4MB     24.4    70    30      1.23s
# 3 dplyr::if_else       6.77ms   7.17ms     133.     6.87MB     39.6    77    23   580.57ms
# 4 base::repalce         5.6ms    5.9ms     166.     5.75MB     36.4    82    18    495.1ms
# 5 base::`[<-`.Roland   3.47ms   3.52ms     269.     3.84MB     33.2    89    11   331.35ms

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