У меня возникли проблемы с циклом for, который содержит множество условий и работает целую вечность (из-за размера фрейма данных). Следовательно, я хотел бы заменить его векторизованной функцией семейства apply. У меня есть переменная формата месяц/год, и я хотел бы определить переменную года, в зависимости от того, меньше ли месяц или равен 10 (октябрь), который будет определен как сам год, или больше 10, что будет быть годом + 1 (например, 09/2001 = 2001, тогда как 12/2001 = 2002). Переменная даты содержит несколько NA. Ниже я привожу упрощенную версию своего фрейма данных, включая цикл for, который я применил. Любая подсказка для векторизованной функции будет оценена по достоинству.
Пример набора данных:
d <- data.frame("10/2010")
names(d) <- "data"
d$data <- as.character(d$data)
d <- rbind(d, "11/2010","12/2009","08/2008", NA)
Для цикла:
d$ano <- NA
for(i in 1:length(d$data)){
month <- as.numeric(substring(d$data[i],1,2))
if (!is.na(d$data[i]) & month <=10){
d$ano[i] <- substring(d$data[i],4,7)
}
if (!is.na(d$data[i]) & month >10){
d$ano[i] <- as.numeric(substring(d$data[i],4,7))+1
}
}
Большое спасибо за это быстрое и простое решение!
Вы можете сделать это, например. с ifelse
:
d$ano <- as.numeric(substring(d$data,4,7)) + ifelse(as.numeric(substring(d$data,1,2)) <= 10, 0, 1)
или используя тот факт, что ИСТИНА равна 1, а ЛОЖЬ равна 0, как в комментарии Эндрю Густара:
d$ano <- as.numeric(substring(d$data,4,7)) + (as.numeric(substring(d$data,1,2)) > 10)
1) Преобразуйте его в класс yearmon
, который представляет год и месяц как год + 0 для января, год + 1/12 для февраля, год + 2/12 для марта и так далее. Затем прибавьте 2 месяца, т. е. 2/12, и возьмите год.
library(zoo)
transform(d, ano = as.integer(as.yearmon(data, format = "%m/%Y") + 2/12))
давая:
data ano
1 10/2010 2010
2 11/2010 2011
3 12/2009 2010
4 08/2008 2008
5 <NA> NA
2) В качестве альтернативы, это также можно сделать в базе R с POSIXlt, отметив, что в этом случае мы должны добавить смещения 1900 к компоненту year
и 1 к компоненту mon
. В этом случае добавьте 1 к году, если mon+1 превышает 10.
transform(d, ano = with(as.POSIXlt(paste(data, 1),
format = "%m/%Y %d"), year + 1900 + (mon + 1 > 10)))
3) Другим базовым решением R является чтение data
с помощью read.table
и управление месяцем и годом из этого:
transform(d, ano = with(read.table(text = data, sep = "/", fill = TRUE),
V2 + (V1 > 10)))
dplyr
/tidyr
решение:
library(tidyverse)
dat %>%
separate(data, c('month', 'year'), '/', convert = T) %>%
transmute(ano = year + (month > 10)) %>%
bind_cols(dat, .)
# data ano
# 1 10/2010 2010
# 2 11/2010 2011
# 3 12/2009 2010
# 4 08/2008 2008
# 5 <NA> NA
Данные:
dat <- structure(
list(data = c("10/2010", "11/2010", "12/2009", "08/2008", NA)),
row.names = c(NA,-5L),
class = "data.frame"
)
month <- as.numeric(substr(d$data,1,2))
получите вектор месяцев, тогдаd$ano <- as.numeric(substr(d$data,4,7)) + (month>10)