Создание новой строки, которая отличается от одной строки от скалярного значения - PullRequest
2 голосов
/ 21 апреля 2019

Предполагая, что у меня есть следующая игрушечная модель, набор данных называется Answer:

Country    year     Y       Ex1       Ex2
A          2015    lala     5         5
A          2016    Popo     2         2
B          2015    baba     15        60
B          2016    nono     9         20

Я хочу найти среднее значение 2016 и 2015 гг. Для всех числовых переменных.Как только у меня будет среднее значение, я хочу новые строки для 2015 и 2016 годов, чтобы подчеркнуть разницу между исходным значением и средним значением.

В этом случае Country A: mean(Ex1) = 3.5, mean(Ex2) = 3.5

Мой окончательный набор данных долженвыглядит так:

Country    year     Y       Ex1       Ex2     demeanEx1    demeanEx2
A          2015    lala     5         5          .            .
A          2016    Popo     2         2          .            .
A          2015    lala     .         .          1.5         1.5
A          2016    Popo     .         .         -1.5        -1.5
B          2015    baba     15        60         .            .
B          2016    nono     9         20         .            .
B          2015    baba     .         .          3            20
B          2016    nono     .         .         -3           -20

Если кому-то интересно, я пытаюсь реализовать фиксированные эффекты вручную, создавая униженные значения для моих переменных.У меня есть 90 переменных в моем текущем наборе данных;поиск средств для всех переменных вручную будет долгой задачей.

Я пытался использовать команду demeanlist в пакете lfe, но R продолжает прерываться каждый раз, когда я пытаюсь его запустить.

Я знаю, что фиксированные эффекты можно запускать с пакетом plm, используя model = within, но я пытаюсь реализовать его вручную.

Ответы [ 3 ]

3 голосов
/ 21 апреля 2019

Мы можем сделать это с tidyverse. После группировки по 'Страна', transmute_at для создания столбцов 'demean' путем вычитания значений столбцов 'Ex' из их mean, а затем связывания данных с исходными данными (bind_rows), arrange путем 'Country', 'year', replace NA в 'year', 'Y' для каждой 'Country' с элементами не-NA из этих столбцов

library(tidyverse)
df1 %>%
   group_by(Country) %>% 
   transmute_at(vars(starts_with("Ex")), 
        list(demean = ~ . - mean(.))) %>%
   bind_rows(df1, .) %>%  
   arrange(Country, year ) %>%        
   group_by(Country) %>% 
   mutate_at(vars(year, Y), list(~ replace(., is.na(.), .[!is.na(.)])))
# A tibble: 8 x 7
# Groups:   Country [2]
#  Country  year Y       Ex1   Ex2 Ex1_demean Ex2_demean
#  <chr>   <int> <chr> <int> <int>      <dbl>      <dbl>
#1 A        2015 lala      5     5       NA         NA  
#2 A        2016 Popo      2     2       NA         NA  
#3 A        2015 lala     NA    NA        1.5        1.5
#4 A        2016 Popo     NA    NA       -1.5       -1.5
#5 B        2015 baba     15    60       NA         NA  
#6 B        2016 nono      9    20       NA         NA  
#7 B        2015 baba     NA    NA        3         20  
#8 B        2016 nono     NA    NA       -3        -20  

Или в слегка измененном виде

df1 %>%
   group_by(Country)  %>% 
   nest %>% 
   mutate(data = map(data, ~ 
              .x %>% 
                   transmute_at(vars(starts_with("Ex")), 
                       list(demean = ~ . - mean(.))) %>% 
                   bind_cols(.x[1:2], .) %>%
                   bind_rows(.x, .))) %>% 
   unnest

Данные

df1 <- structure(list(Country = c("A", "A", "B", "B"), year = c(2015L, 
 2016L, 2015L, 2016L), Y = c("lala", "Popo", "baba", "nono"), 
Ex1 = c(5L, 2L, 15L, 9L), Ex2 = c(5L, 2L, 60L, 20L)), 
 class = "data.frame", row.names = c(NA, -4L))
2 голосов
/ 21 апреля 2019

Рассчитайте и добавьте столбцы demean *, а затем привязайте их к себе, выполняя соответствующие столбцы. Наконец, изменить порядок. Пакеты не используются.

a <- transform(Answer, demean1 = Ex1 - ave(Ex1, Country), demean2 = Ex2 - ave(Ex2, Country))
a2 <- rbind(transform(a, demean1 = NA, demean2 = NA), transform(a, Ex1 = NA, Ex2 = NA))
a2[order(a2$Country), ]

Результат:

  Country year    Y Ex1 Ex2 demean1 demean2
1       A 2015 lala   5   5      NA      NA
2       A 2016 Popo   2   2      NA      NA
5       A 2015 lala  NA  NA     1.5     1.5
6       A 2016 Popo  NA  NA    -1.5    -1.5
3       B 2015 baba  15  60      NA      NA
4       B 2016 nono   9  20      NA      NA
7       B 2015 baba  NA  NA     3.0    20.0
8       B 2016 nono  NA  NA    -3.0   -20.0

или если мы не знаем, сколько существует столбцов Ex, то сначала определим ix как номера столбцов Ex столбцов и вычислим приведенные значения как demeans.

Создайте фрейм данных из трех блоков столбцов, как показано. Наконец-то рассортируйте.

# ix <- 4:ncol(Answer)
ix <- grep("Ex", names(Answer)) ##

demeans <-  Answer[ix] - sapply(Answer[ix], ave, Answer$Country)
names(demeans) <- paste0("demean", names(demeans))

aa <- cbind(
  Answer[-ix], 
  rbind(Answer[ix], NA * Answer[ix]), 
  rbind(NA * demeans, demeans)
)
aa[order(aa$Country), ]
2 голосов
/ 21 апреля 2019

Попытка base R, используя ave для получения отличий от соответствующих средних и некоторой индексации для перезаписи наборов старых и новых значений:

meas <- c("Ex1","Ex2")
s <- seq_len(nrow(dat))

out <- dat[rep(s,2),]
out[-s, meas] <- NA
out[-s, paste0("demean",meas)] <- lapply(
    dat[meas],
    function(x) x - ave(x,dat["Country"])
)
out

#    Country year    Y Ex1 Ex2 demeanEx1 demeanEx2
#1         A 2015 lala   5   5        NA        NA
#2         A 2016 Popo   2   2        NA        NA
#3         B 2015 baba  15  60        NA        NA
#4         B 2016 nono   9  20        NA        NA
#1.1       A 2015 lala  NA  NA       1.5       1.5
#2.1       A 2016 Popo  NA  NA      -1.5      -1.5
#3.1       B 2015 baba  NA  NA       3.0      20.0
#4.1       B 2016 nono  NA  NA      -3.0     -20.0

Где dat было:

dat  <- read.table(text="Country    year     Y       Ex1       Ex2
A          2015    lala     5         5
A          2016    Popo     2         2
B          2015    baba     15        60
B          2016    nono     9         20", header=TRUE)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...