Вычисление суммы на основе пользовательских правил во фрейме данных

Предпочтительно использовать data.table в R: я хочу рассчитать сумму DIAM по ID, CYCLE # на основе следующих правил:

  1. если какой-либо из DIAM для конкретного предметного цикла представлен как NE, тогда SUM не может быть вычислен (должен возвращать NA)
  2. если какой-либо из DIAM представлен как NA, вычислить сумму, игнорируя NA (т.е. как если бы это было 0)
  3. если ни один из них не является NA, вычислите сумму как обычно

Также я хотел бы заменить номер CYCLE числовым с BASELINE, представляющим 0.

dfin <- 
ID    CYCLE     NUM   DIAM
1     BASELINE  1      8
1     BASLEINE  2      4
1     CYCLE 1   1      6
1     CYCLE 1   2      2
1     CYCLE 2   1      6
1     CYCLE 2   2      NE
1     CYCLE 3   1      6
1     CYCLE 3   2      NA

dfout <- 
ID    CYCLE     SUM
1     0         12
1     1         8
1     2         NA
1     3         6

Это нужно применять ко всем предметам. Циклов много, но это всего лишь пример.

Можете ли вы добавить данные с помощью dput?

pogibas 31.10.2018 06:43
Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
1
56
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

Вот один вариант. Сгруппированные по «ID» и matched индексу «CYCLE» (как показано в ожидаемых выходных данных), измените значения «DIAM» на NA, если any из «DIAM» имеет «NE», затем summarise, взяв sum из « DIAM ', убедившись, что если все значения равны NA, вернуть NA

library(tidyverse)
dfin %>% 
  group_by(ID, CYCLE = match(CYCLE, unique(CYCLE))-1) %>% 
  mutate(DIAM = as.numeric(replace(DIAM, any(DIAM== "NE"), NA))) %>%
  summarise(SUM = NA^all(is.na(DIAM)) * sum(DIAM, na.rm = TRUE))
# A tibble: 4 x 3
# Groups:   ID [?]
#     ID CYCLE   SUM
#  <int> <dbl> <dbl>
#1     1     0    12
#2     1     1     8
#3     1     2    NA
#4     1     3     6

Или используйте условие if/else после шага group_by

dfin %>%
  group_by(ID, CYCLE = match(CYCLE, unique(CYCLE))-1)  %>% 
  summarise(SUM = if ("NE" %in% DIAM) NA else sum(as.numeric(DIAM), na.rm = TRUE))

Или используя ту же логику с data.table

library(data.table)
setDT(dfin)[, .(SUM = if ("NE" %in% DIAM) NA_real_ else 
   sum(as.numeric(DIAM), na.rm = TRUE)), .(ID, CYCLE = rleid(CYCLE)-1)]
#   ID CYCLE SUM
#1:  1     0  12
#2:  1     1   8
#3:  1     2  NA
#4:  1     3   6

данные

dfin <- structure(list(ID = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L), 
  CYCLE = c("BASELINE", 
 "BASELINE", "CYCLE 1", "CYCLE 1", "CYCLE 2", "CYCLE 2", "CYCLE 3", 
 "CYCLE 3"), NUM = c(1L, 2L, 1L, 2L, 1L, 2L, 1L, 2L), DIAM = c("8", 
 "4", "6", "2", "6", "NE", "6", NA)), row.names = c(NA, -8L), 
 class = "data.frame")

есть ли способ сделать то же самое с помощью data.table? так как я работаю на сервере с ограниченным количеством пакетов и нелегко установить новый пакет

Amer 31.10.2018 06:57

это великолепно! Могу я добавить еще одно правило: если какой-либо из БАЗОВЫХ ДИАМЕТРОВ НЕТ, то СУММА НЕТ для всех циклов. если бы вы могли, вы прокомментируете это здесь, а не я задаю отдельный вопрос?

Amer 31.10.2018 07:20

Вы имеете в виду, что если CYCLE = BASELINE & DIAM = NA, SUM для всего CYCLE (а не только BASELINE) должен быть 0?

Rage 31.10.2018 07:27

@ Ярость, да. Coz, если исходный уровень не был оценен, данные использовать нельзя.

Amer 31.10.2018 07:30

Пожалуйста, проверьте, делает ли обновление то, что вы искали.

Rage 31.10.2018 08:02
# Data created
dfin<-data.table("ID" = rep(x = 1,times = 8),"CYCLE" = c("BASELINE","BASELINE","CYCLE 1","CYCLE 1","CYCLE 2","CYCLE 2","CYCLE 3","CYCLE 3"),
                 "NUM" = rep(x = c(1,2),times = 4),"DIAM" = c(8,4,6,2,6,"NE",6,NA))

# CYCLE transformed
dfin[,CYCLE := as.numeric(ifelse(CYCLE == "BASELINE","0",
                     substr(x = CYCLE,start = 7,stop = 7)))]

# SUM computed
dfin2<-dfin[,.(SUM = if (CYCLE == 0){
  NA_real_
} else if ("NE" %in% DIAM){
  NA_real_
} else {
  sum(as.numeric(DIAM),na.rm = T)
}),by = c("ID","CYCLE")]

# IDs with CYCLE = 0 present have SUM updated to NA 
dfin2[ID %in% ID[which(CYCLE == 0)],SUM := NA]

Надеюсь это поможет!

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