Расчет месяцев между факторированными временными переменными - PullRequest
2 голосов
/ 05 октября 2010

У меня есть факторированный временной ряд, который выглядит следующим образом:

df <- data.frame(a=c("11-JUL-2004", "11-JUL-2005", "11-JUL-2006", 
                   "11-JUL-2007", "11-JUL-2008"),
                 b=c("11-JUN-1999", "11-JUN-2000", "11-JUN-2001", 
                     "11-JUN-2002", "11-JUN-2003"))

Во-первых, я хотел бы преобразовать это в формат, родной для R. Во-вторых, я хотел бы рассчитать количество месяцев междудве колонки.

Обновление:

По сути, я пытаюсь воссоздать то, что я делаю в SPSS, в R.

В SPSS я бы:

  1. Преобразовать строки в формат даты ДД-МММ-ГГГГ
  2. КОМПЬЮТЕР.RND ((ab) /60/60/24/30.416)

30,416 - это короткое время для 365/12. Меня не волнует крайний случай месяца, следовательно, операция округления.

Ответы [ 5 ]

4 голосов
/ 05 октября 2010
df <- data.frame(c("11-JUL-2004","11-JUL-2005","11-JUL-2006","11-JUL-2007","11-JUL-2008"),
                 c("11-JUN-1999","11-JUN-2000","11-JUN-2001","11-JUN-2002","11-JUN-2003"))
names(df) <- c("X1","X2")
df <- within(df, X1 <- as.Date(X1, format = "%d-%b-%Y"))
df <- within(df, X2 <- as.Date(X2, format = "%d-%b-%Y"))

Тогда difftime() даст разницу в неделях:

> with(df, difftime(X1, X2, units = "weeks"))
Time differences in weeks
[1] 265.2857 265.1429 265.1429 265.1429 265.2857

Или, если мы используем приближение Брэндона:

> with(df, difftime(X1, X2) / 30.416)
Time differences in days
[1] 61.05339 61.02052 61.02052 61.02052 61.05339

Ближайшее, что я мог получить сlubridate (как выделено Дирком) является (используя выше df)

> m <- with(df, as.period(subtract_dates(X1, X2)))
> m
[1] 5 years and 1 month   5 years and 1 month   5 years and 1 month   5 years and 1 month   5 years and 1 month
> str(m)
Classes ‘period’ and 'data.frame':  5 obs. of  6 variables:
 $ year  : int  5 5 5 5 5
 $ month : int  1 1 1 1 1
 $ day   : num  0 0 0 0 0
 $ hour  : int  0 0 0 0 0
 $ minute: int  0 0 0 0 0
 $ second: num  0 0 0 0 0
3 голосов
/ 06 октября 2010

Brandon

Вы можете сделать это с помощью пакета lubridate.

> library(lubridate)

Сообщите R, что это даты. Используйте функцию синтаксического анализатора dmy (), потому что даты пишутся день, месяц, год (т.е. dmy).

> df <- transform(df, a = dmy(a), b = dmy(b))

Рассчитайте разницу как период. Это даст вам количество целых лет, месяцев, дней и т. Д.

> diff <- as.period(df$a - df$b)

Используйте математику, чтобы преобразовать результаты в месяцы.

> 12* diff$year + diff$month

Все они были на расстоянии 61 месяц. Это было бы до следующего месяца. Если вы хотите округлить количество дней, вы можете сделать что-то вроде

> 12* diff$year + diff$month + round(diff$day/30)

Я работаю над тем, чтобы сделать эти шаги более простыми / интуитивными в следующей версии lubridate.

3 голосов
/ 05 октября 2010

Джош в курсе того, что может означать месяц .Пакет lubridate имеет несколько ответов на этот вопрос.

С точки зрения базы R мы можем ответить на нее неделями, хотя:

> df[,"pa"] <- as.POSIXct(strptime(as.character(df$a),
+                         format="%d-%B-%Y", tz="GMT"))
> df[,"pb"] <- as.POSIXct(strptime(as.character(df$b),
+                         format="%d-%B-%Y",tz="GMT"))
> df[,"weeks"] <- difftime(df$pa, df$pb, unit="weeks")
> df[,"months"] <- difftime(df$pa, df$pb, unit="days")/30.416
> df
            a           b         pa         pb        weeks      months
1 11-JUL-2004 11-JUN-1999 2004-07-11 1999-06-11 265.29 weeks 61.053 days
2 11-JUL-2005 11-JUN-2000 2005-07-11 2000-06-11 265.14 weeks 61.021 days
3 11-JUL-2006 11-JUN-2001 2006-07-11 2001-06-11 265.14 weeks 61.021 days
4 11-JUL-2007 11-JUN-2002 2007-07-11 2002-06-11 265.14 weeks 61.021 days
5 11-JUL-2008 11-JUN-2003 2008-07-11 2003-06-11 265.29 weeks 61.053 days
> 

При этом используется измененный data.frame согласно моему редактированию, чтобы у нас были правильные имена столбцов.И если вы бросите as.numeric() вокруг difftime(), вы также получите числа.

2 голосов
/ 06 октября 2010

Номер 1, показанный ниже, наиболее близок к тому, что вы просите, но 2 и 3 - это альтернативы, которые вы также можете рассмотреть в зависимости от вашей цели. Также числа 1 и 3 можно попробовать без округления, если вы хотите учесть дробное число месяцев.

# first convert columns of df to "Date" class
df[] <- lapply(df, as.Date, "%d-%b-%Y")

# 1. difference in days divided by 365.25/12
with(df, round((as.numeric(a) - as.numeric(b)) / (365.25/12)))

# 2. convert to 1st of month & then take diff in mos
library(zoo)
with(df, 12 * (as.yearmon(a) - as.yearmon(b)))

# 3. business style difference in months. See: ?"mondate-class"
library(mondate)
with(df, round(as.numeric(mondate(a) - mondate(b))))
2 голосов
/ 05 октября 2010
> Data <- data.frame(
+ V1=c("11-JUL-2004","11-JUL-2005","11-JUL-2006","11-JUL-2007","11-JUL-2008"),
+ V2=c("11-JUN-1999","11-JUN-2000","11-JUN-2001","11-JUN-2002","11-JUN-2003"))
> Data[,1] <- as.Date(Data[,1],"%d-%b-%Y")
> Data[,2] <- as.Date(Data[,2],"%d-%b-%Y")
> # Assuming 30 days per month
> (Data[,1]-Data[,2])/30
Time differences in days
[1] 61.90000 61.86667 61.86667 61.86667 61.90000
> # Assuming 30.416 days per month
> (Data[,1]-Data[,2])/30.416
Time differences in days
[1] 61.05339 61.02052 61.02052 61.02052 61.05339
> # Assuming month crosses
> require(zoo)
> Data[,1] <- as.yearmon(Data[,1])
> Data[,2] <- as.yearmon(Data[,2])
> (Data[,1]-Data[,2])*12
[1] 61 61 61 61 61
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...