#r #dplyr #data.table
#r #дплыр #данные.таблица
Вопрос:
Я ищу способ создания «неявного» фильтра, который в dplyr выполняет то же самое, что и приведенный ниже код, используя data.table.
library(data.table)
df_test = data.frame(Idx = c(1, 2, 3, 4, 5, 6, 7, 9),
Cond = c(T, T, F, T, T,F, F, T),
Val = c(T, T, F, T, T, F, T, T))
setDT(df_test)
df_test[Cond == TRUE, Res := cumsum(Val)]
Спасибо за вашу помощь
Лучший Александр
Комментарии:
1. Вы имеете в виду, что скользящая функция будет применена к определенному столбцу после применения фильтра в другом столбце
2.
library(tidyverse) df_test %>% filter(Cond == T) %>% mutate(res = cumsum(Val))
Ответ №1:
Вопрос используется data.table
для условного вычисления совокупной суммы на основе значений Cond
столбца.
Приведенный минимальный пример генерирует следующий результат:
> df_test[Cond == TRUE, Res := cumsum(Val)]
> df_test
Idx Cond Val Res
1: 1 TRUE TRUE 1
2: 2 TRUE TRUE 2
3: 3 FALSE FALSE NA
4: 4 TRUE TRUE 3
5: 5 TRUE TRUE 4
6: 6 FALSE FALSE NA
7: 7 FALSE TRUE NA
8: 9 TRUE TRUE 5
Обратите внимание, что значение Res
в строке 8 равно 5.
К сожалению, это нелегко воспроизвести, dplyr
потому cumsum()
что функция не работает условно внутри if_else()
функции.
library(dplyr)
df_test = data.frame(Idx = c(1, 2, 3, 4, 5, 6, 7, 9),
Cond = c(T, T, F, T, T,F, F, T),
Val = c(T, T, F, T, T, F, T, T))
df_test %>% mutate(Res = if_else(Cond, cumsum(Val), NA_integer_))
…выдает значение 6 в строке 8 фрейма выходных данных.
> df_test %>% mutate(Res = if_else(Cond, cumsum(Val), NA_integer_))
Idx Cond Val Res
1 1 TRUE TRUE 1
2 2 TRUE TRUE 2
3 3 FALSE FALSE NA
4 4 TRUE TRUE 3
5 5 TRUE TRUE 4
6 6 FALSE FALSE NA
7 7 FALSE TRUE NA
8 9 TRUE TRUE 6
Чтобы исправить это, необходимо отфильтровать ИСТИННЫЕ значения от FALSE, вычислить совокупную сумму только для истинных строк и объединить ложные значения обратно в результат.
df_test %>%
filter(Cond == TRUE) %>%
mutate(Res = cumsum(Val)) -> df_true
df_test %>% filter(Cond == FALSE) %>%
bind_rows(.,df_true) %>% arrange(Idx)
… и вывод:
Idx Cond Val Res
1 1 TRUE TRUE 1
2 2 TRUE TRUE 2
3 3 FALSE FALSE NA
4 4 TRUE TRUE 3
5 5 TRUE TRUE 4
6 6 FALSE FALSE NA
7 7 FALSE TRUE NA
8 9 TRUE TRUE 5
Ответ №2:
В dplyr
семантике:
df_test %>% mutate(Res = if_else(!Cond, NA_integer_, cumsum(if_else(Cond, as.integer(Val), 0L))))
Комментарии:
1. Этот синтаксис не дает совпадающих результатов
data.table
. Последняя строка вdata.table
выходных данных имеет значение Res = 5, тогда как вdplyr
нем равно 6. Следовательно,cumsum()
функция в dplyr не применяется условно на основе входных данных.2. привет, к сожалению, результаты не совпадают. ваше последнее значение равно 6, тогда как оно должно быть 5
3. @LenGreski Спасибо, что указали на это. Я исправил свой ответ
Ответ №3:
Отвечает ли это на ваш запрос:
> df_test = data.frame(Idx = c(1, 2, 3, 4, 5, 6, 7, 9),
Cond = c(T, T, F, T, T,F, F, T),
Val = c(T, T, F, T, T, F, T, T))
> df_test
Idx Cond Val
1 1 TRUE TRUE
2 2 TRUE TRUE
3 3 FALSE FALSE
4 4 TRUE TRUE
5 5 TRUE TRUE
6 6 FALSE FALSE
7 7 FALSE TRUE
8 9 TRUE TRUE
> df_test %>% mutate(Res = if_else(Cond, cumsum(Cond), NA_integer_))
Idx Cond Val Res
1 1 TRUE TRUE 1
2 2 TRUE TRUE 2
3 3 FALSE FALSE NA
4 4 TRUE TRUE 3
5 5 TRUE TRUE 4
6 6 FALSE FALSE NA
7 7 FALSE TRUE NA
8 9 TRUE TRUE 5
>
или
> df_test %>% filter(Cond == TRUE) %>% mutate(Res = cumsum(Val)) %>% right_join(df_test) %>% arrange(Idx)
Joining, by = c("Idx", "Cond", "Val")
Idx Cond Val Res
1 1 TRUE TRUE 1
2 2 TRUE TRUE 2
3 3 FALSE FALSE NA
4 4 TRUE TRUE 3
5 5 TRUE TRUE 4
6 6 FALSE FALSE NA
7 7 FALSE TRUE NA
8 9 TRUE TRUE 5
>
Комментарии:
1. К сожалению, нет. Вы подводите итог Cond. По совпадению это дает правильный результат. Но на основе Cond столбцы Val должны суммироваться при значении TRUE
2. Как насчет моего второго кода? Я суммирую, используя столбец Val.
Ответ №4:
Кажется, я сам нашел решение. Комментарии приветствуются, если вы обнаружите какие-либо недостатки…
library(dplyr)
df_test %>%
group_by(Cond) %>%
mutate(Res = ifelse(Cond == 1, cumsum(Val), NA)) %>%
ungroup()