R - Использование data.table для эффективного тестирования условий прокатки по нескольким строкам и столбцам

Я пытаюсь протестировать различные условия в таблице data.table, которая выглядит как этот воспроизводимый пример.

 set.seed(17)
 year <- 1980 + rnbinom(10000,3,0.35)
 event <- rep(LETTERS, length.out=10000)
 z <- as.integer(runif(10000,min = 0, max = 10))
 dt <- data.table(event,year,z)
 setkey(dt, event,year)
 dt <- dt[,sum(z), by=c("event","year")]

V1 (который появляется из последней команды) представляет собой количество произошедших событий.

Итак, таблица данных представляет собой упорядоченный массив, и мне нужно выполнить с ним множество функций. Вот некоторые примеры:

  1. Как рассчитать скользящую сумму (или скользящее среднее) событий за 10 предшествующих лет для каждого события? Таким образом, для A 1990 желаемый результат равен 1,452 (между 1980 и 1989 годами). Для H 2012 выходное значение равно 11, потому что с 2002 по 2011 год произошло только 11 случаев (3 в 2002 году, 3 в 2007 году и 5 в 2010 году). Для A 1983 результат будет: NA.

  2. Как я могу проверить, произошло ли событие как минимум в 12 из 15 предыдущих лет? Таким образом, для A 1997 мы можем видеть, что событие произошло более чем за 12 лет за 15 лет до этого (1982–1996 гг., Оно происходило каждый год, кроме 1996 г.), таким образом, критерий соответствует . Однако для A 2001 мы видим, что событие происходит только в 11 из 15 предшествующих лет (1986–2000), а не в 1996, 1998, 1999 и 2000 годах) критерий не встретил. Здесь желательным результатом будет дискретная 1 (критерий соблюден) или 0 (критерий не соблюден).

В идеале код должен позволять вычислять как 1, так и 2 не только для years, которые встречаются в data.table, но также для отсутствующих между 1980 и 2013 годами. Итак, для K 2005 мы можем рассчитать результат для первого квартала как 25 (13 + 5 + 3 + 3 + 2) (спасибо @Arun за указание на предыдущую ошибку). Для 2-го квартала мы видим, что событие не произошло в 1999,2000,2001,2003 годах, и в 2004 году, следовательно, критерий «по крайней мере через 12 из 15 лет» не выполняется. Кроме того, возможно, что комбинация событие-год существует в таблице data.table, но V1 имеет значение 0 (см. Строку 18, A 2001). В идеале такие нулевые вхождения должны рассматриваться как ненулевые (например, путем удаления всех строк, для которых V1 равен нулю).

Я знаю, что нечасто задавать два вопроса, но я чувствую, что они связаны друг с другом и действительно связаны с похожими проблемами. Надеюсь, кто-то может внести какие-то предложения.

Большое спасибо,

Саймон


person SJDS    schedule 06.05.2014    source источник
comment
Ты прав. Похоже, что мой set.seed () по какой-то причине не работал. Блин, что раздражает. Мне придется обновить каждое значение, которое я упомянул :(   -  person SJDS    schedule 06.05.2014
comment
@ Арун, да, это правильно. Не знаю, откуда у меня 10, это даже не вариант, если бы я забыл первую или последнюю. Извинения   -  person SJDS    schedule 07.05.2014
comment
Привет, причина, по которой я ожидаю, что A, 1983 будет NA, намного проще. У меня нет данных за 10 лет до 1983 года. (Мой полный набор данных начинается с 1980 года. Я намерен использовать это, чтобы определить, какие события часто происходили в прошлом. В фактическом результате я уменьшаю свою панель до 1990 года - 2006. Годы после этого предназначены для прогнозирования вне выборки, а годы до этого (1980-1989) - для создания таких исторических частот.   -  person SJDS    schedule 07.05.2014
comment
Что касается, например, Z, 2012 Я понимаю путаницу. У меня есть набор данных, который на самом деле относится к 2013 году и включает его. Но, как показывают фальшивые данные, частота событий резко снижается ближе к концу. Короче говоря, Z, 2012 год может существовать в моих данных и требует значения, но я не могу вернуться дальше 1980 года, поэтому каждое скользящее среднее до 1989 года не может иметь предшествующую информацию за 10 лет. (В зависимости от результатов я настрою это на 7 или 8 или, может быть, 11) ... Надеюсь, это проясняет ситуацию, и большое спасибо за ваши усилия!   -  person SJDS    schedule 07.05.2014


Ответы (1)


По первому вопросу:

Это даст текущую сумму за годы, которые также не обязательно присутствуют в наборе данных (как вы и просили сразу под двумя точками). Идея состоит в том, чтобы сначала сгенерировать все комбинации event и year - даже те, которых нет в наборе данных. Это можно сделать с помощью функции CJ (для перекрестного соединения). Это будет для каждого event создать все year.

setkey(dt, event, year)
d1 = CJ(event=unique(dt$event), year=min(dt$year):max(dt$year))

Теперь мы join вернемся с dt, чтобы заполнить отсутствующие значения для V1 NA.

d1 = dt[d1]

Теперь у нас есть набор данных со всеми комбинациями event и year. Отсюда мы должны найти способ вычислить скользящую сумму. Для этого мы снова создаем еще один набор данных, который содержит все предыдущие 10 лет для каждого года следующим образом:

window_size = 10L
d2 = d1[, list(window = seq(year-window_size, year-1L, by=1L)), by="event,year"]

Для каждого «события, года» мы создаем новый столбец window, который будет генерировать предыдущие 10 лет.

Теперь все, что нам нужно сделать, это правильно установить key столбцы и выполнить join, чтобы получить соответствующие значения «V1».

setkey(d2, event, window) ## note the join here is on "event, window"
setkey(d1, event, year)

ans = d1[d2]

Теперь у нас есть значения «V1» для каждой комбинации «событие, окно». Все, что нам нужно сделать, это агрегировать по «событию, год.1» («год.1» ранее было «годом», а «год» в ans ранее было «окном»). Здесь мы позаботимся о том, чтобы если какой-либо из лет был <1980, то сумма должна быть NA. Это делается с помощью небольшого хака TRUE | NA = TRUE и FALSE | NA = NA.

q1 = ans[, sum(V1, na.rm=TRUE) * (!any(year < 1980) | NA), by="event,year.1"]

q1[event == "K" & year.1 == "2005"]
#    event year.1 V1
# 1:     K   2005 25

По второму вопросу:

Повторите то же самое с window_size = 15L вместо 10L и вставайте до ans. Затем мы можем:

q2 = ans[!is.na(V1)][, .N, by="event,year.1"]

q2[event == "A" & year.1 == 1997]
#    event year.1  N
# 1:     A   1997 14

Это правильно, потому что dt содержит все годы с 1982 по 1995 год, а 1996 год отсутствует и поэтому не учитывается => N=14, как и должно быть.

person Arun    schedule 06.05.2014
comment
Большое спасибо за ваше решение и очень четкое объяснение. Он отлично работает с моим набором данных! Люблю размер окна и ИСТИННО | Уловки NA. Обязательно буду использовать их в будущем! - person SJDS; 07.05.2014