2015-02-02 3 views
3

У меня есть таблица данных миллионов строк, а один из столбцов - столбец даты. Я хотел бы добавить 12 месяцев к всем датам в этой колонке и создать новый столбец. Поэтому я использую пакеты dplyr и lubridate, например.R: эффективные способы добавления месяцев к датам?

library(dplyr) 
library(lubridate) 
new_data <- data %>% mutate(date12m = date %m+% months(12)) 

Это работает, однако для больших наборов данных это очень медленно. Я что-то упускаю? Как это можно ускорить? Я вообще не ожидал R работать в течение более чем 10 минут для такой простой задачи

Edit:

Хочу отметить, что мое решение уже более эффективно, чем использование as.yearmon. Благодаря полковнику Beauvel для решения

a <- data.frame(date = rep(today(),1000000)) 


func = function(u) { 
    d = as.Date(as.yearmon(u)+1, frac=1) 
    if(day(u)>day(d)) return(d) 
    day(d) = day(u) 
    d 
} 

pt <- proc.time() 
a <- a %>% mutate(date12m = func(date)) 
data.table::timetaken(pt) 


pt <- proc.time() 
a <- a %>% mutate(date12m = date %m+% 12) 
data.table::timetaken(pt) 
+2

Можете ли вы предоставить небольшую часть своих данных? – jazzurro

+0

надеюсь, что ответ поможет, вам нужно преобразовать нужные столбцы в даты перед применением моей функции. –

+0

Я согласен, что это должно быть быстрее, но это не простая задача, учитывая, что даты хранятся как секунды с тех пор, как jan 1 1970 – hadley

ответ

4

Просто добавьте 1 с month:

x=seq.Date(from=as.Date("2007-01-01"), to=as.Date("2014-12-12"), by="day") 
month(x) = month(x) + 1 

#> head(x) 
#[1] "2007-02-01" "2007-02-02" "2007-02-03" "2007-02-04" "2007-02-05" "2007-02-06" 

Редактировать: согласно @akrun комментарий здесь решение, используя as.yearmon из zoo пакета. Хитрость заключается в том, чтобы сделать быструю проверку при приеме в день последнего дня следующего месяца:

library(zoo) 

func = function(u) 
{ 
    d = as.Date(as.yearmon(u)+1/12, frac=1) 
    if(day(u)>day(d)) return(d) 
    day(d) = day(u) 
    d 
} 

x=as.Date(c("2014-01-31","2015-02-28","2013-03-02")) 
#> as.Date(sapply(x, func)) 
#[1] "2014-02-28" "2015-03-28" "2013-04-02" 
+0

eagle eyes, теперь это решено :) –

+0

Спасибо, но было бы лучше, если бы вы показали некоторые ориентиры поскольку te OP хочет иметь эффективный код. Из моих тестов, решение OP эффективно по сравнению с «mondate». Не проверял ваш :-) – akrun

+0

Я получаю предупреждение, применяя к тестовому набору данных. 'In if (day (u)> day (d)) return (d): условие имеет длину> 1, и будет использоваться только первый элемент' – akrun

2

Я также работаю с большими кадрами данных в R, вы можете использовать пакет DescTools, он имеет функцию с именем AddMonths (date, NoOfMonths).

Это хорошо работает для меня.

> a <- ymd("2011-09-9") 
> b <- AddMonths(a,1) 
> b 

[1] "2011-10-09" 
+0

Работы по фреймов данных. seq не работает с кадрами данных. вам нужно сделать некоторую настройку, прежде чем вы сможете использовать ее в кадрах данных. AddMonths довольно прямолинейно. – Jack

+0

как применить к кадру данных. Кажется, это очень медленно! –

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