#r #for-loop #dplyr
#r #для цикла #dplyr
Вопрос:
Я работаю над базой данных панели с фирмами и годами. Я интерполирую значения для заполнения NA, если для интерполяции достаточно наблюдений ( um(!is.na(var))>1
требуется как минимум два наблюдения) и сохраняю предыдущие значения, если переменной недостаточно значений для интерполяции ( ifelse(sum(!is.na(var))>1, na_interpolation(var),var)
), чтобы не потерять значения.
set.seed(1)
data <- data.frame(Output_manufacturing = runif(6),
Output_agriculture = runif(6),
ID=c(1,1,2,2,3,3),
Date=c(1991,20000,1991,2000,1991,2000))
vars <- ls(data, pattern="Output_*")
for (var in vars) {
data<- data %>%
group_by(ID) %>%
mutate(!!sym(paste0(var, "_interpolated")) := ifelse(sum(!is.na(var))>1, na_interpolation(var),var))
}
I get the error "Error in for (var in vars) { : invalid for() loop sequence"
Комментарии:
1. Я думаю, что ваш код может быть неправильным, нет объекта data_interp
2. это все еще были данные. Я пропустил строку кода data_interp <- data
3. теперь нет столбца ID
4. Где это
na_interpolation
определено?
Ответ №1:
Я не думаю, что вам нужен for
цикл. Я буду использовать mtcars
для демонстрации и наивное предположение о na_interpolation
функциональности (что действительно имеет отношение к моей точке зрения):
library(dplyr)
mt <- select(mtcars, cyl, disp, hp, drat) %>%
group_by(cyl) %>%
slice(1:3) %>%
ungroup()
mt$disp[c(1,7:8)] <- mt$hp[c(2:3)] <- NA
mt
# # A tibble: 9 x 4
# cyl disp hp drat
# <dbl> <dbl> <dbl> <dbl>
# 1 4 NA 93 3.85
# 2 4 147. NA 3.69
# 3 4 141. NA 3.92
# 4 6 160 110 3.9
# 5 6 160 110 3.9
# 6 6 258 110 3.08
# 7 8 NA 175 3.15
# 8 8 NA 245 3.21
# 9 8 276. 180 3.07
na_interpolation <- function(x) mean(x, na.rm = TRUE)
А теперь настоящая работа:
vars <- c("disp", "hp")
mt %>%
group_by(cyl) %>%
mutate_at(vars, list(
interpolated = ~ if (sum(is.na(.)) > 1) na_interpolation(.) else .
)) %>%
ungroup()
# # A tibble: 9 x 6
# cyl disp hp drat disp_interpolated hp_interpolated
# <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 4 NA 93 3.85 NA 93
# 2 4 147. NA 3.69 147. 93
# 3 4 141. NA 3.92 141. 93
# 4 6 160 110 3.9 160 110
# 5 6 160 110 3.9 160 110
# 6 6 258 110 3.08 258 110
# 7 8 NA 175 3.15 276. 175
# 8 8 NA 245 3.21 276. 245
# 9 8 276. 180 3.07 276. 180
Побочные моменты: ifelse
со сводной статистикой не является правильным инструментом по нескольким причинам:
base::ifelse
может быть плохо: он удаляет class (ifelse(TRUE,Sys.time(),Sys.time())
) и не выполняет принудительное исполнение для возвращаемого значения type (ifelse(TRUE,1L,"2")
); оба мотивировали написаниеdplyr::if_else
(иdata.table::fifelse
);- Декларативный: если вы уверены, что ваше условие всегда будет иметь длину 1, затем объявите это с помощью
if
/else
; если вы видите предупреждения оthe condition has length > 1
, то ваши предположения неверны, что означает, что какое-то другое предположение о положении вещей может быть неверным; (возможно, здесь этого не произойдет, но этоэто хорошая практика защитного программирования).
Это говорит о том, что ваш код (без for
цикла) может быть:
vars <- grep("^Output_", names(data), value = TRUE)
data %>%
group_by(ID) %>%
mutate_at(vars, list(
interpolated = ~ if (sum(is.na(.)) > 1) na_interpolation(.) else .
)) %>%
ungroup()
# A tibble: 6 x 6
# Output_manufacturing Output_agriculture ID Date Output_manufacturing_interpolated Output_agriculture_interpolated
# <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 0.266 0.945 1 1991 0.266 0.945
# 2 0.372 0.661 1 20000 0.372 0.661
# 3 0.573 0.629 2 1991 0.573 0.629
# 4 0.908 0.0618 2 2000 0.908 0.0618
# 5 0.202 0.206 3 1991 0.202 0.206
# 6 0.898 0.177 3 2000 0.898 0.177
(Из этого неясно, будет ли na_interpolation
это правильно, поскольку у вас не более 2 строк на ID
, и ни одна из ваших данных не является NA
, но я не думаю, что это имеет значение. Код все равно должен работать.)
Обновлено, чтобы отразить, что mutate_at
заменено вместо mutate(across(...), ...)
.
data %>%
group_by(ID) %>%
mutate(across(vars, list(
interpolated = ~ if (sum(is.na(.)) > 1) na_interpolate(.) else .
))) %>%
ungroup()
# A tibble: 6 x 6
# Output_manufacturing Output_agriculture ID Date Output_manufacturing_interpolated Output_agriculture_interpolated
# <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 0.266 0.945 1 1991 0.266 0.945
# 2 0.372 0.661 1 20000 0.372 0.661
# 3 0.573 0.629 2 1991 0.573 0.629
# 4 0.908 0.0618 2 2000 0.908 0.0618
# 5 0.202 0.206 3 1991 0.202 0.206
# 6 0.898 0.177 3 2000 0.898 0.177