#r #if-statement #conditional-statements
#r #if-оператор #условные операторы
Вопрос:
Попытка заменить определенные значения столбцов на NA на основе определенных критериев строк во фрейме данных. Пример набора данных (тест) и код, который я пробовал, приведены ниже. Обратите внимание, что мой фактический набор данных намного больше, но мне, по сути, нужно заменить определенные столбцы в определенных строках (определенные годы) на NA. В примере я пытаюсь использовать индексацию столбцов для вставки NAs для столбцов 3: 5 за 2002 год, но в результате все значения в столбцах 3: 5 заменяются на NAs. Я хочу использовать индексацию столбцов вместо имен столбцов, потому что у меня много столбцов в моих фактических данных.
test <- data.frame(YEAR=c(2000,2001,2002,2003,2004,2000,2001,2002,2003,2004),
zone=c('A','A','A','A','A','B','B','B','B','B'),
value=c(5,9,2,5,7,1,8,4,2,1),
value2=c(5,3,6,8,9,7,2,6,1,7),
value3=c(1,5,7,3,9,1,8,2,9,8))
ifelse(test$YEAR==2002,test[,3:5]<-NA,test[])
Ответ №1:
test[,3:5] <- lapply(test[,3:5], replace, test$YEAR == 2002, NA)
test
# YEAR zone value value2 value3
# 1 2000 A 5 5 1
# 2 2001 A 9 3 5
# 3 2002 A NA NA NA
# 4 2003 A 5 8 3
# 5 2004 A 7 9 9
# 6 2000 B 1 7 1
# 7 2001 B 8 2 8
# 8 2002 B NA NA NA
# 9 2003 B 2 1 9
# 10 2004 B 1 7 8
Пошаговый:
- Базовый вызов
replace(x, test$YEAR == 2002, NA)
, который заменяет каждое значениеx
(подлежащее определению) наNA
, если соответствующий год равен 2002; значения, которые не соответствуют 2002 году, сохраняются; lapply(test[,3:5], replace, test$YEAR == 2002, NA)
эквивалентноlapply(test[,3:5], function(x) replace(x, test$YEAR == 2002, NA))
и действует на каждую из колонок 3-5. Для каждого столбца он вызывает
replace
функцию и возвращает результаты.lapply
собирается вернуть список. Поскольку мы хотим заменить только несколько столбцов всего фрейма, мы делаемtest[,3:5] <-
это, сохраняя остальные столбцы.
Примечание:
Это также можно было бы сделать ifelse
, и это выглядело бы так:
lapply(test[,3:5], function(x) ifelse(test$YEAR == 2002, NA, x))
Я склонен отдавать предпочтение replace
ifelse
в подобных ситуациях, которые очень хорошо определены. Почему? (1) replace
меньше и быстрее. (2) ifelse
имеет множество проблем с определением class
столбцов, см., Например ifelse(TRUE,Sys.time(),Sys.time())
. ifelse
(3) при неправильном использовании он может возвращать разные классы без предупреждения или ошибки. Хотя это может быть желательно, этого можно и не ожидать, и оно молчит. Смотрите, как ifelse(c(T,F), c(pi,pi), c("hello","hello"))
всегда будет возвращать character
вектор, который может быть нежелательным.
Несмотря на это, я никогда не видел ни одного случая ifelse
, когда имело смысл выполнять назначения в вызове. То есть ни одно из них (для меня) никогда не имеет смысла:
ifelse(a <- foo > bar, ..., ...)
ifelse(..., b <- 1, ...)
ifelse(..., b[2:9] <- 11, ...)
Комментарии:
1. Ну, это просто отлично сработало! Большое спасибо @r2evans
Ответ №2:
Просто чтобы обеспечить решение tidyverse:
test %>%
mutate(across(contains("value"), ~if_else(YEAR == 2002, NA_real_, .)))
или
test %>%
mutate(across(contains("value"), ~replace(., YEAR == 2002, NA)))
дает
# YEAR zone value value2 value3
# 1 2000 A 5 5 1
# 2 2001 A 9 3 5
# 3 2002 A NA NA NA
# 4 2003 A 5 8 3
# 5 2004 A 7 9 9
# 6 2000 B 1 7 1
# 7 2001 B 8 2 8
# 8 2002 B NA NA NA
# 9 2003 B 2 1 9
# 10 2004 B 1 7 8
Комментарии:
1. Да, спасибо за это. Я часто использую tidyverse.