#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