Назначьте квинтили для каждого года в панельных данных

Привет, у меня есть данные панели, которые содержат 3 столбца: Firm, Year, Income.

Firm <- rep(c("AAA", "BBB", "CCC", "DDD", "EEE"), each = 20)
Year <- rep(seq(1997, 2016, 1), times = 5)
Income <- rnorm(100, mean = 50, sd = 10)
df <- cbind(Firm, Year, Income)

Фактические данные содержат более 5000 фирм и более 50 лет для каждой фирмы. Но это достаточно хороший пример для использования.

Я хотел бы назначить квинтиль дохода для всех фирм за КАЖДЫЙ ГОД отдельно и поместить его в новый столбец под названием Quint. Например, в 1997 году Фирма AAA получила доход 50, Фирма BBB получила доход 49, Фирма CCC получила доход 48, Фирма DDD получила доход 47, а Фирма EEE получила доход 46. Итак, Фирма AAA получила 1, BBB получила 2, CCC получила 3, DDD получил 4, а EEE получил 5, за 1997 год.

У меня есть настраиваемая функция, которая делает это все годы, но не может работать КАЖДЫЙ ГОД:

quan <- function (x){
  y <-ifelse(x <= quantile(x, c(.2), na.rm = TRUE), 1,
        ifelse(x > quantile(x, c(.2), na.rm = TRUE) & x <= quantile(x, c(.4), na.rm = TRUE), 2,
          ifelse(x > quantile(x, c(.4), na.rm = TRUE) & x <= quantile(x, c(.6), na.rm = TRUE), 3,        
            ifelse(x > quantile(x, c(.6), na.rm = TRUE) & x <= quantile(x, c(.8), na.rm = TRUE), 4,
              ifelse(x > quantile(x, c(.8), na.rm = TRUE), 5, NA)))))
  y
}

Как это делать на каждый год? Спасибо.


person Dylan    schedule 23.01.2017    source источник
comment
Я думаю, вы можете использовать cut с quantile в качестве перерывов. Если мы хотим работать за каждый год, используйте aggregate, data.table или dplyr с «Годом» в качестве группирующей переменной. Также создайте df <- data.frame(Firm, Year, Income) и aggregate(Income ~., df, quan)   -  person akrun    schedule 23.01.2017
comment
Кстати, для каждой фирмы, года или комбинации у вас есть только одно наблюдение. Итак, если он основан только на «Годе» как группе, тогда aggregate(Income ~Year, df, quan)   -  person akrun    schedule 23.01.2017
comment
Ваш код df <- cbind(Firm,Year,Income) создает матрицу строк. Это бесполезно для того, что вы хотите делать. Вместо этого используйте df <- data.frame(Firm,Year,Income).   -  person lmo    schedule 23.01.2017


Ответы (1)


Здесь нам нужно использовать одну из функций group by. Используя функцию quan OP в base R, мы можем сделать aggregate

res <- do.call(data.frame, aggregate(Income ~Year, df, quan))

Другой вариант - использовать cut с breaks в качестве quantiles

quan2 <- function(x) as.integer(cut(x, breaks = quantile(x, 
                   c(0, .2, .4, .6, .8, 1)), include.lowest=TRUE))

res2 <- do.call(data.frame, aggregate(Income ~Year, df, quan2))
all.equal(res1, res2)
#[1] TRUE

Другие альтернативы включают пакетные решения, такие как data.table

library(data.table)
setDT(df)[, as.list(quan(Income)), by = Year]

Or dplyr/tidyr

library(dplyr)
library(tidyr)
df %>%
    group_by(Year) %>% 
    summarise(Income = list(quan(Income))) %>%
    unnest %>% 
    group_by(Year) %>% 
    mutate(ind = paste0("Income", row_number())) %>% 
    spread(ind, Income)

Комментарии / обсуждение

1) Результат aggregate в столбце «Доход» как matrix, поэтому мы преобразуем его в правильные столбцы data.frame с do.call(data.frame.

2) Использование cbind для создания набора данных приведет к matrix и matrix может иметь только один class. Если есть какое-либо значение character, весь набор данных будет преобразован в матрицу character. Поэтому лучше работать с data.frame или list, когда class столбцов различаются

данные

df <- data.frame(Firm, Year, Income)
person akrun    schedule 23.01.2017
comment
Спасибо @akrun. Но выскакивает ошибка: аргументы подразумевают разное количество строк. Я провел небольшое исследование, и это видно, потому что длина компаний не одинакова. Как я могу это сделать? - person Dylan; 24.01.2017
comment
res ‹- do.call (data.frame, aggregate (Income ~ Year, df, quan)) не работает, когда у компаний нет равного количества строк. Как мне это решить? - person Dylan; 24.01.2017
comment
@Dylan Вы пробовали другие решения. Я смотрю на ваш пример только когда тестировал - person akrun; 24.01.2017
comment
Я попробовал и два других. setDT (df) [, as.list (quan (Income)), by = Year] дает мне матрицу вместо вектора, который мне нужен. Версия dplyr / tidyr выдает ошибку:: не удалось найти функцию unnest - person Dylan; 24.01.2017
comment
@Dylan У вас установлена ​​последняя версия tidyr? - person akrun; 24.01.2017
comment
Да, у меня последняя версия тидыра. Но это дает мне странные результаты. Есть ли способ сделать это в базе R? Агрегирование не может работать, если у каждой компании не одинаковое количество наблюдений. Спасибо. - person Dylan; 25.01.2017
comment
Да у меня есть последняя версия или тидыр. Так неужели нет способа сделать это, если наблюдения для каждой фирмы различаются? Буду признателен любому, кто сможет это понять. Спасибо. - person Dylan; 04.02.2017
comment
@Dylan Пожалуйста, обновите свой пост примером, который дает ошибку, поскольку я не могу воспроизвести ошибку в этом примере - person akrun; 04.02.2017
comment
конечно, давайте просто удалим одну строку, чтобы не у каждой фирмы было одинаковое количество наблюдений. Фирма ‹- rep (c (AAA, BBB, CCC, DDD, EEE), каждый = 20) Год‹ - rep (seq (1997,2016,1), раз = 5) Доход ‹- rnorm (100, среднее = 50 , sd = 10) df ‹- cbind (Фирма, Год, Доход) df‹ - as.data.frame (df) df ‹- df [! (df $ Firm == AAA & df $ Year == 2016),] - person Dylan; 05.02.2017