1

Я пытаюсь получить последовательные подсчеты из столбца Noshow, сгруппированных по столбцу PatientID. Следующий код, который я использую, очень близок к результатам, которые я хочу достичь. Однако использование функции sum возвращает сумму всей группы. Я хотел бы, чтобы функция sum только суммировала текущую строку и только строки с надписью «1». В принципе, я пытаюсь подсчитать последовательное количество раз, когда пациент ловит их назначение на каждую строку, а затем сбрасывается на 0, когда они показывают. Похоже, что нужно лишь внести некоторые изменения в мой код ниже. Тем не менее, я не могу найти ответ нигде на этом сайте.Как выполнить последовательные графы столбца по группам условно на другой столбец

transform(df, ConsecNoshows = ifelse(Noshow == 0, 0, ave(Noshow, PatientID, FUN = sum))) 

Приведенный выше код производит ниже выход:

#Source: local data frame [12 x 3] 
#Groups: ID [2] 
# 
# PatientID Noshow ConsecNoshows 
#  <int> <int>   <int> 
#1   1  0    0 
#2   1  1    4 
#3   1  0    0 
#4   1  1    4 
#5   1  1    4 
#6   1  1    4 
#7   2  0    0 
#8   2  0    0 
#9   2  1    3 
#10   2  1    3 
#11   2  0    0 
#12   2  1    3 

Это то, что Я желаю:

#Source: local data frame [12 x 3] 
#Groups: ID [2] 
# 
# PatientID Noshow ConsecNoshows 
#  <int> <int>   <int> 
#1   1  0    0 
#2   1  1    0 
#3   1  0    1 
#4   1  1    0 
#5   1  1    1 
#6   1  1    2 
#7   2  0    0 
#8   2  0    0 
#9   2  1    0 
#10   2  1    1 
#11   2  0    2 
#12   2  1    0 

[ОБНОВЛЕНИЕ] Я хотел бы последовательное количество будет компенсирована одной строки вниз.

Благодарим за помощь, которую вы можете предложить заранее!

+0

Хотелось бы проверить все ваши решения так, как они были предоставлены в точности так, как я хотел. Большое спасибо за вашу помощь! –

ответ

3

А вот другой (аналогичный) data.table подход

library(data.table) 
setDT(df)[, ConsecNoshows := seq(.N) * Noshow, by = .(PatientID, rleid(Noshow))] 
df 
#  PatientID Noshow ConsecNoshows 
# 1:   1  0    0 
# 2:   1  1    1 
# 3:   1  0    0 
# 4:   1  1    1 
# 5:   1  1    2 
# 6:   1  1    3 
# 7:   2  0    0 
# 8:   2  0    0 
# 9:   2  1    1 
# 10:   2  1    2 
# 11:   2  0    0 
# 12:   2  1    1 

Это в основном группы по PatientID и " кодирование длины строки "Noshow и создает последовательности с использованием размеров групп при умножении на Noshow, чтобы сохранить только значения, когда Noshow == 1

+0

Дэвид, я проверил ваш ответ как правильный, потому что вы предоставили самый короткий код, чтобы выполнить задание. –

+0

Да, все ответы очень приятные в этой теме. –

+0

После выполнения дополнительной работы над моей моделью я обнаружил, что мне действительно нужно, чтобы результат последовательного подсчета был смещен на один. Поэтому, если первые две строки подсчитаны как noshow, третья строка должна иметь 2 в столбце ConsecNoshows. Это возможно? –

2

Самый прямой способ группы последовательных значений является использование rleid из data.table, здесь вариант из data.table пакета, где вы группировать данные со стороны PatientID, а также rleid из Noshow переменной. А также вам нужна функция cumsum, чтобы получить накопленную сумму переменной Noshow вместо sum:

library(data.table) 
setDT(df)[, ConsecNoshows := ifelse(Noshow == 0, 0, cumsum(Noshow)), .(PatientID, rleid(Noshow))] 
df 
# PatientID Noshow ConsecNoshows 
# 1:   1  0    0 
# 2:   1  1    1 
# 3:   1  0    0 
# 4:   1  1    1 
# 5:   1  1    2 
# 6:   1  1    3 
# 7:   2  0    0 
# 8:   2  0    0 
# 9:   2  1    1 
#10:   2  1    2 
#11:   2  0    0 
#12:   2  1    1 
+0

Благодарим вас за то, что вы предложили первое решение, которое работало Psidom. –

3

Мы можем использовать rle от base R (пакетов не используется). Используя ave, мы группируем «PatientID», получаем rle «Noshow», умножаем sequence «длины» на «значения», реплицированные по «длинам», чтобы получить ожидаемый результат.

helperfn <- function(x) with(rle(x), sequence(lengths) * rep(values, lengths)) 
df$ConsecNoshows <- with(df, ave(Noshow, PatientID, FUN = helperfn)) 
df$ConsecNoshows 
#[1] 0 1 0 1 2 3 0 0 1 2 0 1 

Как ОП, похоже, использует «tbl_df», решение в dplyr бы

library(dplyr) 
df %>% 
    group_by(PatientID) %>% 
    mutate(ConsecNoshows = helperfn(Noshow)) 
#  PatientID Noshow ConsecNoshows 
#  <int> <int>   <int> 
#1   1  0    0 
#2   1  1    1 
#3   1  0    0 
#4   1  1    1 
#5   1  1    2 
#6   1  1    3 
#7   2  0    0 
#8   2  0    0 
#9   2  1    1 
#10   2  1    2 
#11   2  0    0 
#12   2  1    1 
+1

Akrun, большое вам спасибо за ваши решения. Все они работали точно так, как предполагалось. Мне особенно нравится базовое решение R, которое вы предоставили. –

3

Я хотел бы создать вспомогательную функцию, чтобы затем использовать все, что реализация вы наиболее комфортно с:

sum0 <- function(x) {x[x == 1]=sequence(with(rle(x), lengths[values == 1]));x} 

#base R 
transform(df1, Consec = ave(Noshow, PatientID, FUN=sum0)) 

#dplyr 
library(dplyr) 
df1 %>% group_by(PatientID) %>% mutate(Consec=sum0(Noshow)) 

#data.table 
library(data.table) 
setDT(df1)[, Consec := sum0(Noshow), by = PatientID] 
    # PatientID Noshow Consec 
    #  <int> <int> <int> 
    # 1   1  0  0 
    # 2   1  1  1 
    # 3   1  0  0 
    # 4   1  1  1 
    # 5   1  1  2 
    # 6   1  1  3 
    # 7   2  0  0 
    # 8   2  0  0 
    # 9   2  1  1 
    # 10   2  1  2 
    # 11   2  0  0 
    # 12   2  1  1 
+0

Пьер, ваше решение действительно полезно, поскольку оно дает мне несколько вариантов использования. Благодарим вас за то, что вы помогли мне создать вспомогательную функцию. –