Заполнение отсутствующих уровней

У меня есть следующий тип фрейма данных:

Country <- rep(c("USA", "AUS", "GRC"),2)
Year    <- 2001:2006
Level   <- c("rich","middle","poor",rep(NA,3))
df <- data.frame(Country, Year,Level)

df 
Country Year  Level
1     USA 2001   rich
2     AUS 2002 middle
3     GRC 2003   poor
4     USA 2004   <NA>
5     AUS 2005   <NA>
6     GRC 2006   <NA>

Я хочу заполнить недостающие значения правильной меткой уровня в последнем из правого столбца.

Таким образом, ожидаемый результат должен быть таким:

Country Year  Level
1     USA 2001   rich
2     AUS 2002 middle
3     GRC 2003   poor
4     USA 2004   rich
5     AUS 2005 middle
6     GRC 2006   poor

Ответ 1

Мы можем группировать "Страна" и получать уникальное значение не-NA

library(dplyr)
df %>%
    group_by(Country) %>% 
    dplyr::mutate(Level = Level[!is.na(Level)][1])
# A tibble: 6 x 3
# Groups:   Country [3]
#  Country  Year  Level
#   <fctr> <int> <fctr>
#1     USA  2001   rich
#2     AUS  2002 middle
#3     GRC  2003   poor
#4     USA  2004   rich
#5     AUS  2005 middle
#6     GRC  2006   poor

Если мы загрузили dplyr вместе с plyr, лучше указать явно dplyr::mutate или dplyr::summarise так, чтобы он использовал функцию из dplyr. В plyr есть те же функции, что и потенциально может маскировать функции из dplyr, когда они загружаются, создавая различное поведение.

Ответ 2

В базе R вы можете использовать ave():

transform(df, Level = ave(Level, Country, FUN = na.omit))

#   Country Year  Level
# 1     USA 2001   rich
# 2     AUS 2002 middle
# 3     GRC 2003   poor
# 4     USA 2004   rich
# 5     AUS 2005 middle
# 6     GRC 2006   poor

Другая, более точная возможность - использовать соединение. Здесь мы объединяем столбец Country с данными, опущенными NA. Результат тот же, только в другом порядке строк.

merge(df["Country"], na.omit(df))

#   Country Year  Level
# 1     AUS 2002 middle
# 2     AUS 2002 middle
# 3     GRC 2003   poor
# 4     GRC 2003   poor
# 5     USA 2001   rich
# 6     USA 2001   rich

Ответ 3

Вы можете сделать это с помощью data.table и zoo: -

library(data.table)
library(zoo)
setDT(df)
df[, Level := na.locf(Level), by = Country]

Это даст вам: -

   Country Year  Level
1:     USA 2001   rich
2:     AUS 2002 middle
3:     GRC 2003   poor
4:     USA 2004   rich
5:     AUS 2005 middle
6:     GRC 2006   poor

Ответ 4

library(dplyr)

df %>% 
  group_by(Country) %>% 
  mutate(Level = replace(Level, is.na(Level), unique(na.omit(Level))))
  Country  Year  Level
   <fctr> <int> <fctr>
1     USA  2001   rich
2     AUS  2002 middle
3     GRC  2003   poor
4     USA  2004   rich
5     AUS  2005 middle
6     GRC  2006   poor

Или, более кратко, применяя идею @suchait к использованию na.locf:

df %>% 
  group_by(Country) %>% 
  mutate(Level = zoo::na.locf(Level))

Ответ 5

Решение с использованием и .

library(dplyr)
library(tidyr)

df %>%
  arrange(Country) %>%
  fill(Level) %>%
  arrange(Year)
#   Country Year  Level
# 1     USA 2001   rich
# 2     AUS 2002 middle
# 3     GRC 2003   poor
# 4     USA 2004   rich
# 5     AUS 2005 middle
# 6     GRC 2006   poor

Ответ 6

Вот еще одно решение data.table, которое обновляет соединение, используя таблицу поиска, которая создается из данного набора данных:

library(data.table)
setDT(df)[df[!is.na(Level)], on = .(Country), Level := Level][]
   Country Year  Level
1:     USA 2001   rich
2:     AUS 2002 middle
3:     GRC 2003   poor
4:     USA 2004   rich
5:     AUS 2005 middle
6:     GRC 2006   poor