Предпочтительно использовать data.table
в R: я хочу рассчитать сумму DIAM
по ID
, CYCLE #
на основе следующих правил:
DIAM
для конкретного предметного цикла представлен как NE
, тогда SUM
не может быть вычислен (должен возвращать NA
)DIAM
представлен как NA
, вычислить сумму, игнорируя NA
(т.е. как если бы это было 0)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
Это нужно применять ко всем предметам. Циклов много, но это всего лишь пример.
Вот один вариант. Сгруппированные по «ID» и match
ed индексу «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? так как я работаю на сервере с ограниченным количеством пакетов и нелегко установить новый пакет
это великолепно! Могу я добавить еще одно правило: если какой-либо из БАЗОВЫХ ДИАМЕТРОВ НЕТ, то СУММА НЕТ для всех циклов. если бы вы могли, вы прокомментируете это здесь, а не я задаю отдельный вопрос?
Вы имеете в виду, что если CYCLE = BASELINE & DIAM = NA, SUM для всего CYCLE (а не только BASELINE) должен быть 0?
@ Ярость, да. Coz, если исходный уровень не был оценен, данные использовать нельзя.
Пожалуйста, проверьте, делает ли обновление то, что вы искали.
# 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]
Надеюсь это поможет!
Можете ли вы добавить данные с помощью
dput
?