2013-07-15 3 views
0

У меня есть dataframe так:R: условно заменить значения в цикле

rel  <- c(2, 5, NA, 3, 6) 
year.in <- c(4, NA, 2, 3, 2) 
year.out <- c(6, 7, NA, 5, 4) 
year.1 <- c(NA, NA, NA, NA, NA) 
year.2 <- c(NA, NA, NA, NA, NA) 
year.3 <- c(NA, NA, NA, NA, NA) 
year.4 <- c(NA, NA, NA, NA, NA) 
year.5 <- c(NA, NA, NA, NA, NA) 

df <- as.data.frame(cbind(rel, year.in, year.out, year.1, year.2, year.3, 
         year.4, year.5)) 

То, что я хотел бы сделать, это обновление недостающие значения в год.1 - год5 со значением «отн» , но только если: (year.in> = year.i AND year.out < = year.i) (с i is 1: 5)

Сфокусировавшись только на год входа, я придумал это :

for (i in 1:5) ifelse(df$year.in < i, 
    df[paste("year", i, sep= ".")]<- NA, 
    df[paste("year", i, sep= ".")]<- df["rel"]) 

Но это просто заменяет все year.i переменные со значением rel.

У меня есть два вопроса:

  • как я могу изменить переменные year.i со значениями «отн» на условиях, указанных?

  • Плохо ли использовать здесь инструкцию if else?

Самый лучший и заранее спасибо,

Ричард

ответ

4
library(data.table) 
dt = data.table(df) 

for(i in 1:5) dt[year.in <= i & i <= year.out, paste0('year.', i) := rel] 

dt 
# rel year.in year.out year.1 year.2 year.3 year.4 year.5 
#1: 2  4  6  NA  NA  NA  2  2 
#2: 5  NA  7  NA  NA  NA  NA  NA 
#3: NA  2  NA  NA  NA  NA  NA  NA 
#4: 3  3  5  NA  NA  3  3  3 
#5: 6  2  4  NA  6  6  6  NA 
+0

Спасибо, это очень помогает. Я обязательно изучу пакет data.table более подробно! – Richard

1

Я бы melt ваших данных, используя reshape2 пакет:

library(reshape2)  
df.melt <- melt(df, id.vars=c('rel', 'year.in', 'year.out')) 

выкопать числовой год:

df.melt$year <- as.integer(gsub('year\\.', '', df.melt$variable)) 

Затем используйте векторизованные операции:

subsetter <- with(df.melt, year.in >= year & year.out <= year.out) 
subsetter[is.na(subsetter)] <- FALSE 
df.melt$value[subsetter] <- df.melt$rel[subsetter] 

Однако, в вашем примере, все терпит неудачу вашего состояния.

Использование ifelse вполне приемлемо, однако, не выполняйте назначение внутри. Вместо этого присвойте свой результат чему-то, как показано ниже. Проблема заключалась в том, что два назначения, которые вы выполняли внутри ifelse, не были на каждом подмножестве, а вместо этого действовали так, как будто они просто запускались независимо.

for (i in 1:5) { 
    year_col <- paste('year', i, sep='.') 
    df[[year_col]] <- ifelse(df$year.in >= i & df$year.out <= i, 
         df$rel, 
         df[[year_col]]) 
} 

Чтобы ответить на ваши пули:

  • См выше.

  • Нет ничего особенного в использовании ifelse, и иногда это удобно для удобства чтения. Тем не менее, это «петлевая» конструкция и, следовательно, часто может быть заменена более эффективным векторизованным решением.

+0

Дорогой Джастин, спасибо за явно обращаясь на мои вопросы. Сожалею, что мне сложно работать с кодом. Первая часть кода работает нормально, но не обеспечивает ожидаемого результата. например значение 2 в году 1, а year.in == 4 и year.out == 6. В цикле for выдается предупреждение в моем случае: Предупреждающие сообщения: «В' [<-. data.frame '('* tmp *', year_col, value = list (c (NA_real_,: предоставил 5 переменных, чтобы заменить 1 переменную " – Richard

+1

Спасибо за примечание, моя ошибка. Неожиданный вывод - это то, что у вас есть свое условие, записанное назад в ваш вопрос. Однако предупреждение было непреднамеренным и исправлено с помощью '[[' для индексации 'df' на' year_col' (см. мое редактирование). – Justin

+0

Спасибо, что вернулись к этому. Да, я был несогласован в выражении условия : [ – Richard

Смежные вопросы