R — Хранить новейшие данные, которые не являются NA, если доступны только NA

#r #dataframe #subset #na

#r #фрейм данных #подмножество #na #dataframe

Вопрос:

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

 year = c(2010, 2013, 2010, 2013, 2013)
city = c("Berlin","Berlin", "Munich", "Munich", "Frankfurt")
value = c(1234, NA, NA, 6372, NA)
data <- data.frame(year, value1, value2)

 year    city    value
1 2010    Berlin   1234
2 2013    Berlin     NA
3 2010    Munich     NA
4 2013    Munich   6372
5 2013 Frankfurt     NA
  

Я хотел бы знать, как подмножествовать это, чтобы я сохранял только самые новые доступные данные, чтобы в конце у меня остались такие данные:

  year    city    value
1 2010    Berlin   1234
2 2013    Munich   6372
3 2013 Frankfurt     NA
  

Если я выполняю подмножество в самом высоком году, я получаю NAS, где за этот год нет данных. Если я включу подмножество !is.na() , я потеряю все строки, в которых есть только NA.

Что я хочу сделать конкретно, так это получить самый высокий год для данного города с данными, если только для этого города нет только NAS, а затем самый высокий год с NA. Как бы я поступил по этому поводу?

Комментарии:

1. Что именно вы хотите подмножить? Из вашего примера кажется, что вы не хотите указывать подмножество для самого высокого года, есть ли другая переменная, которую вы здесь не показываете?

2. Ах, нет: я хочу подмножество для столбца city: самый высокий год с данными для данного города, если для этого города нет только NAS, затем самый высокий год с NA. Это делает его более понятным?

Ответ №1:

Мы можем использовать data.table . Преобразуем ‘data.frame’ в ‘data.table’ ( setDT(data) ), сгруппированные по ‘city’, мы указываем ‘i’ как ‘year’ в нисходящем order индексе, if есть any ‘значение’, отличное от NA, мы подмножествуем ‘Data.table’ на основе индекса первого ‘значения’, отличного от NA, или else возвращаем подмножество Data.table.

 library(data.table)
setDT(data)[order(-year), if(any(!is.na(value)))  
            .SD[which(!is.na(value))[1L]] else .SD, by = city]
  

Или компактный вариант от @David Arenburg, из которого мы получаем индекс which.max

 setDT(data)[order(-year), .SD[which.max(!is.na(value))], by = city] 
  

Или используйте модификацию с помощью .I , чтобы ускорить ее

 setDT(data)[data[order(-year), .I[which.max(!is.na(value))], by = city]$V1]
  

Комментарии:

1. это действительно потрясающе, спасибо! попробовал это на моем реальном наборе данных, и это сработало отлично 🙂 хотя один вопрос: если у меня есть несколько лет для города с NA (например, 2010, Франкфурт, штат На-Майне; 2011, Франкфурт, штат На-Майне; 2013, Франкфурт, штат На-Майне), он сохраняет все эти годы. Как мне сохранить только самый новый год для этого случая?

2. Или просто setDT(data)[order(-year), .SD[which.max(!is.na(value))], by = city]

3. @DavidArenburg Это было очень хорошо. На самом деле, я пытался аналогично с which . Был на вызове, поэтому не смог сосредоточиться на нем

4. Разница между which и which.max заключается в том, что в случае, если все FALSE , which ничего не вернет, пока which.max вернет первую строку. Сравните which(FALSE) и which.max(FALSE) . В любом случае, вы можете добавить это в свой ответ, если хотите

Ответ №2:

Более подробный, обходной подход с использованием dplyr . Это также работает для вашего случая, когда у вас есть несколько лет NA .

 library(dplyr)
data %>%
  group_by(city) %>%
  mutate(all_na = all(is.na(value)),
         remove = ifelse(all_na,
                         year != max(year),
                         is.na(value))) %>%
  ungroup() %>%
  filter(!remove) %>%
  select(-all_na, -remove)
  

Ответ №3:

max_pos(x) возвращает позицию в x последнего элемента, отличного от NA, x или, если элементов, отличных от NA, нет, возвращает последнюю позицию x . is_max возвращает логическое значение, которое имеет значение TRUE в максимальной позиции и FALSE в другом месте. Обратите внимание, что это ave приведет его результат к типу его первого аргумента, поэтому мы используем !! , чтобы вернуть его к логическому. Наконец, мы выделяем эти элементы в подмножество. Это предполагает, что входные данные отсортированы по годам в пределах города, как в случае с вопросом.

Обратите внимание, что max_pos было сделано компактным с использованием этих фактов:

  • в seq_along(x) * 0*x 0*x есть вектор нулей и NAs, поэтому добавьте к нему NAs соответствующие элементы seq_along(x) . То есть это дает тот же результат, что и replace(seq_along(x), is.na(x), NA) который можно было бы использовать вместо него.
  • which.max возвращает результат нулевой длины, если x это все значения NA, и c(arg1, arg2)[1] выдает тот же результат, что и if (length(arg1) == 0) arg2 else arg1 который можно было бы использовать вместо него.

Пакеты не используются.

 max_pos <- function(x) c(which.max(seq_along(x)   0*x), length(x))[1]
is_max <- function(x) seq_along(x) == max_pos(x)
subset(data, !!ave(value, city, FUN = is_max))
  

предоставление:

   year      city value
1 2010    Berlin  1234
4 2013    Munich  6372
5 2013 Frankfurt    NA