#r #list #dplyr #na
Вопрос:
Допустим, у меня есть хронологический список доходов домашних хозяйств и база данных идентификаторов городов с доходами домашних хозяйств, но есть некоторые NAS, которые я хочу заполнить.
HouseholdIncome_list <- c(10000, 20000, 30000,40000,50000, 60000, 70000)
Town_ID <- c("A", "A", "A", "A", "B", "B", "B", "B", "B")
HouseholdIncome <- c(10000, 40000, 50000, NA, 20000, 40000, NA, NA, 60000)
df <- data.frame(Town_ID, HouseholdIncome)
Town_ID HouseholdIncome
1 A 10000
2 A 40000
3 A 50000
4 A NA
5 B 20000
6 B 40000
7 B NA
8 B NA
9 B 60000
Как заполнить NAs во фрейме данных, чтобы отсутствующие значения были теми, которые указаны в списке. Таким образом, это выглядит как df ниже
Town_ID HouseholdIncome
1 A 10000
2 A 40000
3 A 50000
4 A 60000
5 B 20000
6 B 40000
7 B 50000
8 B 50000
9 B 60000
Я потратил время на поиск какого-то варианта заполнения, но не могу найти тот, который соответствует заданному списку
Комментарии:
1. Как вы
HouseholdIncome_list
связаны с вашимHouseholdIncome
? Первое отсутствующее значение в A заменяется на 60000, а остальные-на 50000? На данный момент это кажется мне немного случайным.2. @Serkan, это следующее значение в списке, поэтому в случае замены A на 60000 это следующее значение в списке доходов домохозяйства после 50000. Для B 50000 заменяет NA, потому что в списке HouseholdIncome_list он находится между 40000 и 60000. Поэтому я хочу заполнить NAs следующим или предыдущим значением, как указано в списке HouseholdIncome_list
3. Хорошо, смотрите мой ответ. Это простое решение, которое должно сработать для вас.
Ответ №1:
вот еще один подход, основанный на соединениях, который также будет вменять первое значение группы в случае, если оно отсутствует:
library(tidyverse)
rdf <- data.frame(HouseholdIncome_list = c(10000, 20000, 30000,40000,50000, 60000, 70000)) %>%
dplyr::mutate(rn = as.double(dplyr::row_number()))
df <- data.frame(Town_ID = c("A", "A", "A", "A", "B", "B", "B", "B", "B"),
HouseholdIncome = c(10000, 40000, 50000, NA, 20000, 40000, NA, NA, 60000))
df %>%
dplyr::left_join(rdf, by = c("HouseholdIncome" = "HouseholdIncome_list")) %>%
dplyr::group_by(Town_ID) %>%
tidyr::fill(rn, .direction = "down") %>%
tidyr::fill(rn, .direction = "up") %>%
dplyr::mutate(rn2 = dplyr::row_number()) %>%
dplyr::ungroup() %>%
dplyr::mutate(rn = case_when(is.na(HouseholdIncome) amp; rn2 == 1 amp; rn == min(rdf$rn) ~ rn,
is.na(HouseholdIncome) amp; rn2 == 1 ~ rn - 1,
is.na(HouseholdIncome) amp; rn < max(rdf$rn) ~ rn 1,
TRUE ~ rn)) %>%
dplyr::left_join(rdf, by = "rn") %>%
select(Town_ID, HouseholdIncome = HouseholdIncome_list)
# A tibble: 9 x 2
Town_ID HouseholdIncome
<chr> <dbl>
1 A 10000
2 A 40000
3 A 50000
4 A 60000
5 B 20000
6 B 40000
7 B 50000
8 B 50000
9 B 60000
Ответ №2:
Это ужасное решение, но оно сделает вашу работу.
library(tidyr)
library(dplyr)
df %>%
group_by(grp = cumsum(!is.na(HouseholdIncome))) %>%
rowwise() %>%
mutate(Income = ifelse(length(which(HouseholdIncome_list == HouseholdIncome)) > 0,
HouseholdIncome_list[which(HouseholdIncome_list == HouseholdIncome) 1],
NA_real_)) %>%
ungroup() %>%
fill(Income) %>%
mutate(HouseholdIncome = ifelse(is.na(HouseholdIncome), Income, HouseholdIncome)) %>%
select(Town_ID, HouseholdIncome)
ВОЗВРАТ
# A tibble: 9 x 2
Town_ID HouseholdIncome
<chr> <dbl>
1 A 10000
2 A 40000
3 A 50000
4 A 60000
5 B 20000
6 B 40000
7 B 50000
8 B 50000
9 B 60000
Если ваш первый пункт- NA
это не сработает.
Ответ №3:
Возможный вариант базового R
transform(
df,
HouseholdIncome = ave(
HouseholdIncome,
Town_ID,
FUN = function(x) replace(x, is.na(x), x[min(which(is.na(x))) - 1] 1e4)
)
)
дает
Town_ID HouseholdIncome
1 A 10000
2 A 40000
3 A 50000
4 A 60000
5 B 20000
6 B 40000
7 B 50000
8 B 50000
9 B 60000
Ответ №4:
Я бы немного «схитрил», используя tidyverse
. Очевидно, что доход домохозяйства находится в интервалах 10 000, и поэтому мы можем использовать это,
df %>% mutate(
is_na = as.numeric(is.na(HouseholdIncome)) * 10000
) %>% fill(
HouseholdIncome, .direction = "down"
) %>% mutate(
HouseholdIncome =(HouseholdIncome is_na),
is_na = NULL
)
Сначала мы проверяем наличие NA
, здесь is_na = 1 * 10000
если TRUE
, а затем используем fill
для переноса последних значений вперед.
В конце концов sum
мы изменяем переменную is_na
и HouseholdIncome
получаем следующий HouseholdIncome
интервал.
В результате получается следующее,
Town_ID HouseholdIncome
1 A 10000
2 A 40000
3 A 50000
4 A 60000
5 B 20000
6 B 40000
7 B 50000
8 B 50000
9 B 60000