R: условный агрегат на основе уровня фактора и года.

У меня есть набор данных в R, который я пытаюсь агрегировать по уровню столбца и году, который выглядит так:

    City  State   Year   Status      Year_repealed   PolicyNo
    Pitt   PA     2001   InForce                        6
    Phil.  PA     2001   Repealed        2004           9
    Pitt   PA     2002   InForce                        7
    Pitt   PA     2005   InForce                        2

Что я хотел бы создать, так это то, где для каждого года я агрегирую PolicyNo по штатам с учетом даты отмены политики. Результаты, которые я получил бы, следующие:

    Year    State PolicyNo
    2001     PA     15  
    2002     PA     22
    2003     PA     22
    2004     PA     12 
    2005     PA     14

Я не уверен, как разделить и агрегировать данные, зависящие от данных отмены, и мне было интересно, есть ли способ легко добиться этого в R.


person Tobi Adekanye    schedule 03.12.2016    source источник


Ответы (2)


Это может помочь вам разбить это на две отдельные проблемы.

  1. Получите таблицу, которая показывает изменение PolicyNo в каждом году города-штата.
  2. Обобщите эту таблицу, чтобы показать номер полиса в каждом штате-год.

Для выполнения (1) мы добавляем недостающие годы с NA PolicyNo и добавляем отмену как отрицательные PolicyNo наблюдения.

library(dplyr)

df = structure(list(City = c("Pitt", "Phil.", "Pitt", "Pitt"), State = c("PA", "PA", "PA", "PA"), Year = c(2001L, 2001L, 2002L, 2005L), Status = c("InForce", "Repealed", "InForce", "InForce"), Year_repealed = c(NA, 2004L, NA, NA), PolicyNo = c(6L, 9L, 7L, 2L)), .Names = c("City", "State", "Year", "Status", "Year_repealed", "PolicyNo"), class = "data.frame", row.names = c(NA, -4L))

repeals = df %>%
  filter(!is.na(Year_repealed)) %>%
  mutate(Year = Year_repealed, PolicyNo = -1 * PolicyNo)
repeals
#    City State Year   Status Year_repealed PolicyNo
# 1 Phil.    PA 2004 Repealed          2004       -9

all_years = expand.grid(City = unique(df$City), State = unique(df$State),
                        Year = 2001:2005)

df = bind_rows(df, repeals, all_years)
#     City State Year   Status Year_repealed PolicyNo
# 1   Pitt    PA 2001  InForce            NA        6
# 2  Phil.    PA 2001 Repealed          2004        9
# 3   Pitt    PA 2002  InForce            NA        7
# 4   Pitt    PA 2005  InForce            NA        2
# 5  Phil.    PA 2004 Repealed          2004       -9
# 6   Pitt    PA 2001     <NA>            NA       NA
# 7  Phil.    PA 2001     <NA>            NA       NA
# 8   Pitt    PA 2002     <NA>            NA       NA
# 9  Phil.    PA 2002     <NA>            NA       NA
# 10  Pitt    PA 2003     <NA>            NA       NA
# 11 Phil.    PA 2003     <NA>            NA       NA
# 12  Pitt    PA 2004     <NA>            NA       NA
# 13 Phil.    PA 2004     <NA>            NA       NA
# 14  Pitt    PA 2005     <NA>            NA       NA
# 15 Phil.    PA 2005     <NA>            NA       NA

Теперь таблица показывает каждый год города-государства и включает отмены. Это таблица, которую мы можем обобщить.

df = df %>%
  group_by(Year, State) %>%
  summarize(annual_change = sum(PolicyNo, na.rm = TRUE))
df
# Source: local data frame [5 x 3]
# Groups: Year [?]
# 
#    Year State annual_change
#   <int> <chr>         <dbl>
# 1  2001    PA            15
# 2  2002    PA             7
# 3  2003    PA             0
# 4  2004    PA            -9
# 5  2005    PA             2

Это дает нам политикуНикаких изменений в каждом штате-год. Совокупная сумма изменений дает нам уровни.

df = df %>%
  ungroup() %>%
  mutate(PolicyNo = cumsum(annual_change))
df
# # A tibble: 5 × 4
#    Year State annual_change PolicyNo
#   <int> <chr>         <dbl>    <dbl>
# 1  2001    PA            15       15
# 2  2002    PA             7       22
# 3  2003    PA             0       22
# 4  2004    PA            -9       13
# 5  2005    PA             2       15
person effel    schedule 03.12.2016
comment
Еще один вопрос @effel, если вы не возражаете. В случае, когда у меня есть несколько столбцов политики нет, есть ли способ выполнить этот анализ одновременно? - person Tobi Adekanye; 04.12.2016
comment
Да, я бы предложил растопить более широкую таблицу и добавить столбец переменных (с указанием политик) в вызовы group_by в качестве еще одного идентификатора. Если вышеизложенное сработало хорошо, не стесняйтесь принять ответ. - person effel; 04.12.2016

С пакетом data.table вы можете сделать это следующим образом:

melt(setDT(dat), 
     measure.vars = c(3,5),
     value.name = 'Year',
     value.factor = FALSE)[!is.na(Year)
                           ][variable == 'Year_repealed', PolicyNo := -1*PolicyNo
                             ][CJ(Year = min(Year):max(Year), State = State, unique = TRUE), on = .(Year, State)
                               ][is.na(PolicyNo), PolicyNo := 0
                                 ][, .(PolicyNo = sum(PolicyNo)), by = .(Year, State)
                                   ][, .(Year, State, PolicyNo = cumsum(PolicyNo))]

Результат приведенного выше кода:

   Year State PolicyNo
1: 2001    PA       15
2: 2002    PA       22
3: 2003    PA       22
4: 2004    PA       13
5: 2005    PA       15

Как видите, нужно пройти несколько шагов, чтобы прийти к желаемому конечному результату:

  • Сначала вы конвертируете в data.table (setDT(dat)), преобразуете его в длинный формат и удаляете строки без Year
  • Затем вы делаете значение для строк с 'Year_repealed' отрицательным.
  • С помощью перекрестного соединения (CJ) вы убедитесь, что все годы для каждого штата присутствуют, и преобразуете NA-значения в столбце PolicyNo в ноль.
  • Наконец, вы суммируете по годам и делаете кумулятивный итог по результату.
person h3rm4n    schedule 03.12.2016