Предположим, мы начнем с приведенного ниже кадра данных data, сгенерированного кодом, расположенным непосредственно под ним:
> data
ID Period_1 Period_2 Values State
1 1 1 2020-01 5 X0
2 1 2 2020-02 10 X1
3 1 3 2020-03 15 X0
4 2 1 2020-04 0 X0
5 2 2 2020-05 2 X2
6 2 3 2020-06 4 X0
7 3 1 2020-02 3 X2
8 3 2 2020-03 6 X1
9 3 3 2020-04 9 X0
data <-
data.frame(
ID = c(1,1,1,2,2,2,3,3,3),
Period_1 = c(1, 2, 3, 1, 2, 3, 1, 2, 3),
Period_2 = c("2020-01","2020-02","2020-03","2020-04","2020-05","2020-06","2020-02","2020-03","2020-04"),
Values = c(5, 10, 15, 0, 2, 4, 3, 6, 9),
State = c("X0","X1","X0","X0","X2","X0", "X2","X1","X0")
)
Я пытаюсь научиться использовать пакет R data.table и хотел бы использовать его для подсчета переходов из заданного состояния (состояние «X0» в приведенном ниже примере кода) в другое состояние при перемещении или «переходе» из от одного периода к другому (в данном случае измерение периода — «Период_1»). Я получаю следующие результаты при запуске кода data.table непосредственно под ним:
OutflowState 2 4
1: X0 0 0
2: X1 1 0
3: X2 1 0
Code run:
library(data.table)
dcast(
setDT(data)[, OutflowState := factor(shift(State, type = c("lead"))), by = ID]
[, period_factor := lapply(.SD, factor), .SDcols = "Period_1"]
[, period_factor := as.numeric(period_factor) + 1],
OutflowState ~ period_factor, length,
value.var = "Values", subset = .(State == "X0"), drop = FALSE
)
Этот вывод правильный, но я хотел бы (а) добавить столбцы к выводу для периодов 1 и 3 (период 1 всегда будет состоять из 0, а период 3 должен отображать все 0 в случае этого data фрейма данных, потому что не было состояния = X0 в периодах 2; и (b) удалить из вывода столбец, где Period_1 = 4, потому что нет периода = 4, это просто трюк, используемый в коде выше as.numeric(period_factor) + 1, чтобы пометить следующий переходный период. Я делаю это?
Я получаю следующий промежуточный фрейм данных при запуске сегмента кода, показанного под ним, поэтому одним из решений является удаление любых строк, где OutflowState = NA (удаление всех условных периодов 4), но я не знаю, как это сделать.
ID Period_1 Period_2 Values State OutflowState period_factor
1: 1 1 2020-01 5 X0 X1 2
2: 1 2 2020-02 10 X1 X0 3
3: 1 3 2020-03 15 X0 <NA> 4
4: 2 1 2020-04 0 X0 X2 2
5: 2 2 2020-05 2 X2 X0 3
6: 2 3 2020-06 4 X0 <NA> 4
7: 3 1 2020-02 3 X2 X1 2
8: 3 2 2020-03 6 X1 X0 3
9: 3 3 2020-04 9 X0 <NA> 4
setDT(data)[, OutflowState := factor(shift(State, type = c("lead"))), by = ID][
, period_factor := lapply(.SD, factor), .SDcols = "Period_1"][
, period_factor := as.numeric(period_factor) + 1
]
data
Этот вопрос является следствием Как использовать data.table для создания нового фрейма данных, показывающего притоки в указанное переходное состояние на основе значения элемента в предыдущей строке?, касающегося переходных потоков. Обратите внимание, что приведенный выше код data.table допускает альтернативные варианты определения временного горизонта как Period_2 и суммирования переходов значений вместо подсчета переходов, и он должен поддерживать эти возможности.
Изображение ниже лучше иллюстрирует:





dcast с drop = FALSE создаст столбцы для каждого уровня фактора period_factor, поэтому, если вам нужны столбцы 1 и 3, но не 4 в результате, нам нужно установить уровень period_factor, чтобы включить 1 и 3, но не 4 (и сохранить его класс factor !). Я также упростил создание period_factor, lapply и .SDcols понадобятся только в том случае, если мы применим это к нескольким столбцам:
dcast(
setDT(data)[, OutflowState := factor(shift(State, type = c("lead"))), by = ID]
[, period_factor := factor(Period_1 + 1, levels = seq(1, max(Period_1)))],
OutflowState ~ period_factor, length,
value.var = "Values",
subset = .(State == "X0" ),
drop = FALSE
)
# OutflowState 1 2 3
# 1: X0 0 0 0
# 2: X1 0 1 0
# 3: X2 0 1 0
Мы можем взять функцию state_inflow() от мой ответ к вопросу Как использовать data.table для создания нового фрейма данных, показывающего притоки в указанное переходное состояние на основе значения элемента в предыдущей строке? и превратить ее в функцию state_outflow():
state_inflow <- function(mydat, target_state) {
dcast(
setDT(mydat)[, Previous_State := shift(State, fill = target_state), by = ID],
factor(Previous_State) ~ factor(Period_1), length, value.var = "Values",
subset = .(State == target_state), drop = FALSE
)
}
по обмен ролями из State и Previous_State в dcast():
state_outflow <- function(mydat, target_state) {
dcast(
setDT(mydat)[, Previous_State := shift(State), by = ID],
factor(State) ~ factor(Period_1), length, value.var = "Values",
subset = .(Previous_State == target_state), drop = FALSE
)
}
Кроме того, функции shift() не присваивается значение заполнения. Итак, предыдущее состояние первого периода каждого ID равно NA.
Вызов функции дает ожидаемый результат:
state_outflow(data, "X0")
State 1 2 3 1: X0 0 0 0 2: X1 0 1 0 3: X2 0 1 0
Нет необходимости настраивать уровни факторов.