Как анализировать год + номер недели в R?
Есть ли хороший способ получить год + неделю число, преобразованное в R? Я пробовал следующее:
> as.POSIXct("2008 41", format="%Y %U")
[1] "2008-02-21 EST"
> as.POSIXct("2008 42", format="%Y %U")
[1] "2008-02-21 EST"
Согласно ?strftime
:
% Y Год с веком. Обратите внимание, что если в оригинальный григорианский календарь, ISO 8601: 2004 определяет его действительность (интерпретируется как 1BC): см. http://en.wikipedia.org/wiki/0_(year). Заметка что в стандарте также говорится, что за годы до 1582 года в его календаре следует использовать только с согласия заинтересованных сторон.
% U Неделя года в виде десятичного числа (00-53) с использованием воскресенья в качестве первый день 1 недели (и, как правило, с первого воскресенья год как день 1 недели 1). Американская конвенция.
Ответы
Ответ 1
Это похоже на другой вопрос который вы, возможно, видели раньше.:)
Ключевой вопрос: какой день должен указывать номер недели? Это первый день недели? Последний? Это двусмысленно. Я не знаю, является ли первая неделя первой день года или 7-го числа года или, возможно, первое воскресенье или понедельник года (что является частой интерпретацией). (И это хуже, чем это: они обычно выглядят 0-индексированными, а не 1-индексированными.) Итак, нужно указать нужный день недели.
Например, попробуйте следующее:
as.POSIXlt("2008 42 1", format = "%Y %U %u")
Индикатор %u
указывает день недели.
Примечание: см. ?strptime
для различных вариантов преобразования формата. Важно следить за перечислением недель, так как они могут быть разделены в конце года, а день 1
неоднозначен: это указано на основании воскресенья или понедельника или с первого дня года? Все это должно быть указано и протестировано в разных системах, где будет работать R-код. Я не уверен, что Windows и POSIX-системы используют одну и ту же мелодию для некоторых из этих преобразований, поэтому я бы снова тестировал и тестировал.
Ответ 2
День недели == ноль в системе POSIXlt DateTimesClasses - воскресенье. Не совсем библейский и не согласуется с индексом R, который начинается с соглашения "1", но что это такое. Недельная ноль - первая (частичная) неделя в году. Первая неделя (но день недели) начинается с первого воскресенья. И все остальные типы последовательностей в POSIXlt имеют 0 в качестве отправной точки. Интересно посмотреть, что такое принудительное использование элементов списка объектов POSIXlt. Единственный способ изменить дату POSIXlt - изменить элементы $year, $mon или $mday. Другие, похоже, являются эпифеноменами.
today <- as.POSIXlt(Sys.Date())
today # Tuesday
#[1] "2012-02-21 UTC"
today$wday <- 0 # attempt to make it Sunday
today
# [1] "2012-02-21 UTC" The attempt fails
today$mday <- 19
today
#[1] "2012-02-19 UTC" Success
Ответ 3
Я не придумал это сам (он взял из сообщение в блоге от Forester), но тем не менее я думал, что добавлю это в список ответов, потому что это первая реализация соглашения номер недели ISO 8601, которое я видел в R.
Несомненно, номера недель - очень неоднозначная тема, но я предпочитаю стандарт ISO по сравнению с текущей версией недельных номеров через format(..., "%U")
, потому что кажется, что это то, о чем большинство людей согласилось, по крайней мере, в Германии (календари и т.д..).
Я поставил фактическую функцию def внизу, чтобы облегчить фокусировку на выходе. Кроме того, я просто наткнулся на пакет ISOweek, возможно, стоит попробовать.
Сравнение подходов
x.days <- c("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
x.names <- sapply(1:length(posix), function(x) {
x.day <- as.POSIXlt(posix[x], tz="Europe/Berlin")$wday
if (x.day == 0) {
x.day <- 7
}
out <- x.days[x.day]
})
data.frame(
posix,
name=x.names,
week.r=weeknum,
week.iso=ISOweek(as.character(posix), tzone="Europe/Berlin")$weeknum
)
# Result
posix name week.r week.iso
1 2012-01-01 Sun 1 4480458
2 2012-01-02 Mon 1 1
3 2012-01-03 Tue 1 1
4 2012-01-04 Wed 1 1
5 2012-01-05 Thu 1 1
6 2012-01-06 Fri 1 1
7 2012-01-07 Sat 1 1
8 2012-01-08 Sun 2 1
9 2012-01-09 Mon 2 2
10 2012-01-10 Tue 2 2
11 2012-01-11 Wed 2 2
12 2012-01-12 Thu 2 2
13 2012-01-13 Fri 2 2
14 2012-01-14 Sat 2 2
15 2012-01-15 Sun 3 2
16 2012-01-16 Mon 3 3
17 2012-01-17 Tue 3 3
18 2012-01-18 Wed 3 3
19 2012-01-19 Thu 3 3
20 2012-01-20 Fri 3 3
21 2012-01-21 Sat 3 3
22 2012-01-22 Sun 4 3
23 2012-01-23 Mon 4 4
24 2012-01-24 Tue 4 4
25 2012-01-25 Wed 4 4
26 2012-01-26 Thu 4 4
27 2012-01-27 Fri 4 4
28 2012-01-28 Sat 4 4
29 2012-01-29 Sun 5 4
30 2012-01-30 Mon 5 5
31 2012-01-31 Tue 5 5
Функция Def
Это взято непосредственно из сообщения в блоге, я только что изменил несколько незначительных вещей. Функция по-прежнему является отрывочной (например, номер недели первой даты далеко), но я считаю, что это хороший старт!
ISOweek <- function(
date,
format="%Y-%m-%d",
tzone="UTC",
return.val="weekofyear"
){
##converts dates into "dayofyear" or "weekofyear", the latter providing the ISO-8601 week
##date should be a vector of class Date or a vector of formatted character strings
##format refers to the date form used if a vector of
## character strings is supplied
##convert date to POSIXt format
if(class(date)[1]%in%c("Date","character")){
date=as.POSIXlt(date,format=format, tz=tzone)
}
# if(class(date)[1]!="POSIXt"){
if (!inherits(date, "POSIXt")) {
print("Date is of wrong format.")
break
}else if(class(date)[2]=="POSIXct"){
date=as.POSIXlt(date, tz=tzone)
}
print(date)
if(return.val=="dayofyear"){
##add 1 because POSIXt is base zero
return(date$yday+1)
}else if(return.val=="weekofyear"){
##Based on the ISO8601 weekdate system,
## Monday is the first day of the week
## W01 is the week with 4 Jan in it.
year=1900+date$year
jan4=strptime(paste(year,1,4,sep="-"),format="%Y-%m-%d")
wday=jan4$wday
wday[wday==0]=7 ##convert to base 1, where Monday == 1, Sunday==7
##calculate the date of the first week of the year
weekstart=jan4-(wday-1)*86400
weeknum=ceiling(as.numeric((difftime(date,weekstart,units="days")+0.1)/7))
#########################################################################
##calculate week for days of the year occuring in the next year week 1.
#########################################################################
mday=date$mday
wday=date$wday
wday[wday==0]=7
year=ifelse(weeknum==53 & mday-wday>=28,year+1,year)
weeknum=ifelse(weeknum==53 & mday-wday>=28,1,weeknum)
################################################################
##calculate week for days of the year occuring prior to week 1.
################################################################
##first calculate the numbe of weeks in the previous year
year.shift=year-1
jan4.shift=strptime(paste(year.shift,1,4,sep="-"),format="%Y-%m-%d")
wday=jan4.shift$wday
wday[wday==0]=7 ##convert to base 1, where Monday == 1, Sunday==7
weekstart=jan4.shift-(wday-1)*86400
weeknum.shift=ceiling(as.numeric((difftime(date,weekstart)+0.1)/7))
##update year and week
year=ifelse(weeknum==0,year.shift,year)
weeknum=ifelse(weeknum==0,weeknum.shift,weeknum)
return(list("year"=year,"weeknum"=weeknum))
}else{
print("Unknown return.val")
break
}
}