2012-02-29 161 views
32

Tôi có vectơ ngày và cho mỗi mục nhập, tôi muốn chỉ định một phần. Vì vậy, ví dụ, nếu một ngày là giữa 21,12. và 21.3., tôi sẽ nói đó là winter. Cho đến nay tôi đã thử các mã sau đây nhưng tôi không thể làm cho nó chung chung hơn, bất kể năm.Tìm một ngày cụ thể thuộc về

my.dates <- as.Date("2011-12-01", format = "%Y-%m-%d") + 0:60 
low.date <- as.Date("2011-12-15", format = "%Y-%m-%d") 
high.date <- as.Date("2012-01-15", format = "%Y-%m-%d") 

my.dates[my.dates <= high.date & my.dates >= low.date] 
[1] "2011-12-15" "2011-12-16" "2011-12-17" "2011-12-18" "2011-12-19" "2011-12-20" "2011-12-21" "2011-12-22" "2011-12-23" "2011-12-24" "2011-12-25" 
[12] "2011-12-26" "2011-12-27" "2011-12-28" "2011-12-29" "2011-12-30" "2011-12-31" "2012-01-01" "2012-01-02" "2012-01-03" "2012-01-04" "2012-01-05" 
[23] "2012-01-06" "2012-01-07" "2012-01-08" "2012-01-09" "2012-01-10" "2012-01-11" "2012-01-12" "2012-01-13" "2012-01-14" "2012-01-15" 

Tôi đã thử định dạng ngày tháng không có năm nhưng không hoạt động.

ld <- as.Date("12-15", format = "%m-%d") 
hd <- as.Date("01-15", format = "%m-%d") 
my.dates[my.dates <= hd & my.dates >= ld] 
+3

Đừng quên đặt trong một mùa giải sắp xếp lại chuyển đổi cho bạn bè của chúng tôi tại Oz :-) –

+1

@CarlWitthoft An d New Zealand! Và Brazil ... Đối với Angelinos (LA) và mùa: có thể chỉ có một! – Iterator

+0

Lưu ý rằng rất nhiều câu trả lời ở đây tập trung vào các mùa thiên văn (thường được sử dụng ở châu Âu).Ở một số nơi (như Úc), và cũng thường trong khoa học, mùa được định nghĩa đơn giản là ba tháng (DJF, MAM naught101

Trả lời

38

Làm thế nào về việc sử dụng một cái gì đó như thế này:

getSeason <- function(DATES) { 
    WS <- as.Date("2012-12-15", format = "%Y-%m-%d") # Winter Solstice 
    SE <- as.Date("2012-3-15", format = "%Y-%m-%d") # Spring Equinox 
    SS <- as.Date("2012-6-15", format = "%Y-%m-%d") # Summer Solstice 
    FE <- as.Date("2012-9-15", format = "%Y-%m-%d") # Fall Equinox 

    # Convert dates from any year to 2012 dates 
    d <- as.Date(strftime(DATES, format="2012-%m-%d")) 

    ifelse (d >= WS | d < SE, "Winter", 
     ifelse (d >= SE & d < SS, "Spring", 
     ifelse (d >= SS & d < FE, "Summer", "Fall"))) 
} 

my.dates <- as.Date("2011-12-01", format = "%Y-%m-%d") + 0:60 
head(getSeason(my.dates), 24) 
# [1] "Fall" "Fall" "Fall" "Fall" "Fall" "Fall" "Fall" 
# [8] "Fall" "Fall" "Fall" "Fall" "Fall" "Fall" "Fall" 
# [15] "Winter" "Winter" "Winter" "Winter" "Winter" "Winter" 

Một lưu ý: 2012 là một tốt năm để chuyển đổi tất cả các ngày; vì đây là năm nhuận, bất kỳ ngày 29 tháng 2 nào trong tập dữ liệu của bạn sẽ được xử lý suôn sẻ.

+0

Chức năng rất tiện dụng, tôi hy vọng nó tìm đường vào một gói. –

+0

Có một "|" nơi cần có một "&" trong vòng ifelse đầu tiên. Tôi không thể chỉnh sửa nó vì nó quá ngắn để chỉnh sửa rõ ràng. nhưng yêu mã: Cảm ơn bạn! – Puddlebunk

+1

@Puddlebunk Không, nó có nghĩa là là một "|", vì có hai cách rời rạc để được vào mùa đông - ngày dương lịch có thể sau đông chí HOẶC trước mùa xuân phân. Rất vui vì bạn đã tìm thấy mã hữu ích. –

4

Tôi nghĩ rằng điều này sẽ làm điều đó, nhưng nó là một giải pháp xấu xí:

my.dates <- as.Date("2011-12-01", format = "%Y-%m-%d") + 0:60 
    ld <- as.Date("12-15", format = "%m-%d") 
    hd <- as.Date("01-15", format = "%m-%d") 
    my.dates2 <- as.Date(unlist(lapply(strsplit(as.character(my.dates),split=""),function(x) paste(x[6:10],collapse=""))),format="%m-%d") 
    my.dates[my.dates2 <= hd | my.dates2 >= ld] 
    [1] "2011-12-15" "2011-12-16" "2011-12-17" "2011-12-18" "2011-12-19" 
    [6] "2011-12-20" "2011-12-21" "2011-12-22" "2011-12-23" "2011-12-24" 
    [11] "2011-12-25" "2011-12-26" "2011-12-27" "2011-12-28" "2011-12-29" 
    [16] "2011-12-30" "2011-12-31" "2012-01-01" "2012-01-02" "2012-01-03" 
    [21] "2012-01-04" "2012-01-05" "2012-01-06" "2012-01-07" "2012-01-08" 
    [26] "2012-01-09" "2012-01-10" "2012-01-11" "2012-01-12" "2012-01-13" 
    [31] "2012-01-14" "2012-01-15" 
8

Tôi có một cái gì đó tương tự như xấu xí như Tim:

R> toSeason <- function(dat) { 
+ 
+  stopifnot(class(dat) == "Date") 
+ 
+  scalarCheck <- function(dat) { 
+   m <- as.POSIXlt(dat)$mon + 1  # correct for 0:11 range 
+   d <- as.POSIXlt(dat)$mday   # correct for 0:11 range 
+   if ((m == 3 & d >= 21) | (m == 4) | (m == 5) | (m == 6 & d < 21)) { 
+    r <- 1 
+   } else if ((m == 6 & d >= 21) | (m == 7) | (m == 8) | (m == 9 & d < 21)) { 
+    r <- 2 
+   } else if ((m == 9 & d >= 21) | (m == 10) | (m == 11) | (m == 12 & d < 21)) { 
+    r <- 3 
+   } else { 
+    r <- 4 
+   } 
+   r 
+  } 
+ 
+  res <- sapply(dat, scalarCheck) 
+  res <- ordered(res, labels=c("Spring", "Summer", "Fall", "Winter")) 
+  invisible(res) 
+ } 
R> 

Và đây là một thử nghiệm:

R> date <- Sys.Date() + (0:11)*30 
R> DF <- data.frame(Date=date, Season=toSeason(date)) 
R> DF 
     Date Season 
1 2012-02-29 Winter 
2 2012-03-30 Spring 
3 2012-04-29 Spring 
4 2012-05-29 Spring 
5 2012-06-28 Summer 
6 2012-07-28 Summer 
7 2012-08-27 Summer 
8 2012-09-26 Fall 
9 2012-10-26 Fall 
10 2012-11-25 Fall 
11 2012-12-25 Winter 
12 2013-01-24 Winter 
R> summary(DF) 
     Date    Season 
Min. :2012-02-29 Spring:3 
1st Qu.:2012-05-21 Summer:3 
Median :2012-08-12 Fall :3 
Mean :2012-08-12 Winter:3 
3rd Qu.:2012-11-02    
Max. :2013-01-24    
R> 
6

tôi sẽ tạo ra một bảng tra cứu, và đi từ đó. Một ví dụ (chú ý obfuscation mã sử dụng d() chức năng và cách thực dụng của điền các LUT):

# Making lookup table (lut), only needed once. You can save 
# it using save() for later use. Note I take a leap year. 
d = function(month_day) which(lut$month_day == month_day) 
lut = data.frame(all_dates = as.POSIXct("2012-1-1") + ((0:365) * 3600 * 24), 
       season = NA) 
lut = within(lut, { month_day = strftime(all_dates, "%b-%d") }) 
lut[c(d("Jan-01"):d("Mar-20"), d("Dec-21"):d("Dec-31")), "season"] = "winter" 
lut[c(d("Mar-21"):d("Jun-20")), "season"] = "spring" 
lut[c(d("Jun-21"):d("Sep-20")), "season"] = "summer" 
lut[c(d("Sep-21"):d("Dec-20")), "season"] = "autumn" 
rownames(lut) = lut$month_day 

Sau khi tạo bảng tra cứu, bạn có thể trích xuất khá dễ dàng từ nó với những gì mùa một sự kết hợp tháng/ngày thuộc đến:

dat = data.frame(dates = Sys.Date() + (0:11)*30) 
dat = within(dat, { 
    season = lut[strftime(dates, "%b-%d"), "season"] 
}) 
> dat 
     dates season 
1 2012-02-29 winter 
2 2012-03-30 spring 
3 2012-04-29 spring 
4 2012-05-29 spring 
5 2012-06-28 summer 
6 2012-07-28 summer 
7 2012-08-27 summer 
8 2012-09-26 autumn 
9 2012-10-26 autumn 
10 2012-11-25 autumn 
11 2012-12-25 winter 
12 2013-01-24 winter 

Tất cả đều đẹp và được vector hóa :). Tôi nghĩ rằng một khi bảng được tạo ra, điều này rất nhanh.

1

Giải pháp của tôi không nhanh nhưng linh hoạt về sự bắt đầu của các mùa miễn là chúng được xác định trong một khung dữ liệu trước tiên cho hàm assignSeason. Nó yêu cầu magrittr cho các chức năng đường ống, lubridate cho hàm year và dplyr cho mutate.

seasons <- data.frame(
    SE = as.POSIXct(c("2009-3-20", "2010-3-20", "2011-3-20", "2012-3-20", 
     "2013-3-20", "2014-3-20"), format="%Y-%m-%d"), 
    SS = as.POSIXct(c("2009-6-21", "2010-6-21", "2011-6-21", "2012-6-20", 
     "2013-6-21", "2014-6-21"), format="%Y-%m-%d"), 
    FE = as.POSIXct(c("2009-9-22", "2010-9-23", "2011-9-23", "2012-9-22", 
     "2013-9-22", "2014-9-23"), format="%Y-%m-%d"), 
    WS = as.POSIXct(c("2009-12-21", "2010-12-21", "2011-12-22", "2012-12-21", 
     "2013-12-21", "2014-12-21"), format="%Y-%m-%d") 
) 

assignSeason <- function(dat, SeasonStarts=seasons) { 
    dat %<>% mutate(
     Season = lapply(Date, 
      function(x) { 
       findInterval(
        x, 
        SeasonStarts[which(year(x)==year(SeasonStarts$WS)), ] 
       ) 
      } 
     ) %>% unlist  
    ) 
    dat[which(dat$Season==0 | dat$Season==4), ]$Season <- "Winter" 
    dat[which(dat$Season==1), ]$Season     <- "Spring" 
    dat[which(dat$Season==2), ]$Season     <- "Summer" 
    dat[which(dat$Season==3), ]$Season     <- "Fall" 
    return(dat) 
} 

dữ liệu Ví dụ:

dat = data.frame(
    Date = as.POSIXct(strptime(as.Date("2011-12-01", format = "%Y-%m-%d") + 
     (0:10)*30, format="%Y-%m-%d")) 
) 
dat %>% assignSeason 

Kết quả:

  Date Season 
1 2011-12-01 Fall 
2 2011-12-31 Winter 
3 2012-01-30 Winter 
4 2012-02-29 Winter 
5 2012-03-30 Spring 
6 2012-04-29 Spring 
7 2012-05-29 Spring 
8 2012-06-28 Summer 
9 2012-07-28 Summer 
10 2012-08-27 Summer 
11 2012-09-26 Fall 
1

Tôi nghĩ rằng thư viện vườn thú sẽ dễ dàng

library(zoo) 
     yq <- as.yearqtr(as.yearmon(DF$dates, "%m/%d/%Y") + 1/12) 
     DF$Season <- factor(format(yq, "%q"), levels = 1:4, 
     labels = c("winter", "spring", "summer", "fall")) 
Các vấn đề liên quan