How to classify a given date/time by the season (e.g. summer, autumn)
Here are three possibilities, one using cut
, as suggested by @Spacedman in the comments, a second using findInterval
, and a third which uses a rolling join in data.table
. As discussed in the comments above, solstice and equinox dates are defined as onset of a Season. This may explain the difference between my output and OP:s (not yet edited) desired result. I leave the mapping of 'seas' to more sensible season names to you.
1. cut
Date.time$seastime <- as.POSIXct(cut(Date.time$datetime, seasonality$seastime))
Date.time <- merge(Date.time, seasonality)
Date.time[ , c("datetime", "seas")]
# datetime seas
# 1 2012-12-20 19:28:00 September Equinox
# 2 2012-12-25 21:08:00 December Solstice
# 3 2012-12-29 02:50:00 December Solstice
# snip
# 12 2013-03-12 02:24:00 December Solstice
# 13 2013-03-18 21:54:00 December Solstice
# 14 2013-03-24 04:50:00 March Equinox
# 15 2013-03-31 05:54:06 March Equinox
# 16 2013-04-01 03:52:00 March Equinox
# 17 2013-04-04 12:34:00 March Equinox
2. findInterval
seasonality <- seasonality[order(seasonality$seastime), ]
Date.time$seas <- seasonality$seas[findInterval(x = Date.time$datetime, vec = seasonality$seastime)]
Date.time
# datetime seas
# 1 2012-12-20 19:28:00 September Equinox
# 2 2012-12-25 21:08:00 December Solstice
# 3 2012-12-29 02:50:00 December Solstice
# snip
# 12 2013-03-12 02:24:00 December Solstice
# 13 2013-03-18 21:54:00 December Solstice
# 14 2013-03-24 04:50:00 March Equinox
# 15 2013-03-31 05:54:06 March Equinox
# 16 2013-04-01 03:52:00 March Equinox
# 17 2013-04-04 12:34:00 March Equinox
3. data.table
rolling join
library(data.table)
setDT(Date.time)
setDT(seasonality)
setkey(Date.time, datetime)
setkey(seasonality, seastime)
seasonality[Date.time, roll = Inf]
# seastime seas
# 1: 2012-12-20 19:28:00 September Equinox
# 2: 2012-12-25 21:08:00 December Solstice
# 3: 2012-12-29 02:50:00 December Solstice
# snip
# 12: 2013-03-12 02:24:00 December Solstice
# 13: 2013-03-18 21:54:00 December Solstice
# 14: 2013-03-24 04:50:00 March Equinox
# 15: 2013-03-31 05:54:06 March Equinox
# 16: 2013-04-01 03:52:00 March Equinox
# 17: 2013-04-04 12:34:00 March Equinox
# possibly rename 'seastime' here.
'Date.time' used here:
structure(list(datetime = structure(c(1356028080, 1356466080,
1356745800, 1357039920, 1357878240, 1360560720, 1360703160, 1361011320,
1361268360, 1361535000, 1361853000, 1363051440, 1363640040, 1364097000,
1364702046, 1364781120, 1365071640), class = c("POSIXct", "POSIXt"
), tzone = "")), .Names = "datetime", class = "data.frame", row.names = c(NA,
-17L))
Determine season given timestamp in Python using datetime
if the date falls between March 21 and June 20, it is spring.
Regardless of the year. I want it to just look at the month and day
and ignore the year in this calculation.
#!/usr/bin/env python
from datetime import date, datetime
Y = 2000 # dummy leap year to allow input X-02-29 (leap day)
seasons = [('winter', (date(Y, 1, 1), date(Y, 3, 20))),
('spring', (date(Y, 3, 21), date(Y, 6, 20))),
('summer', (date(Y, 6, 21), date(Y, 9, 22))),
('autumn', (date(Y, 9, 23), date(Y, 12, 20))),
('winter', (date(Y, 12, 21), date(Y, 12, 31)))]
def get_season(now):
if isinstance(now, datetime):
now = now.date()
now = now.replace(year=Y)
return next(season for season, (start, end) in seasons
if start <= now <= end)
print(get_season(date.today()))
It is an extended version of @Manuel G answer to support any year.
Find which season a particular date belongs to
How about using something like this:
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"
One note: 2012 is a good year to which to convert all of the dates; since it is a leap year, any February 29ths in your data set will be handled smoothly.
Python: Datetime to season
You can use a simple mathematical formula to compress a month to a season, e.g.:
>>> [month%12 // 3 + 1 for month in range(1, 13)]
[1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 1]
So for your use-case using vector operations (credit @DSM):
>>> temp2.dt.month%12 // 3 + 1
1 3
2 3
3 3
4 4
5 4
6 4
7 4
8 4
Name: id, dtype: int64
group data by season according to the exact dates
You need DatetimeIndex.dayofyear
:
data['SEASON'] = data.index.dayofyear.map(season)
Another solution with pandas.cut
:
bins = [0, 91, 183, 275, 366]
labels=['Winter', 'Spring', 'Summer', 'Fall']
doy = data.index.dayofyear
data['SEASON1'] = pd.cut(doy + 11 - 366*(doy > 355), bins=bins, labels=labels)
How to determine the seasons of the year from a multitemporal data list using R?
1) Use findInterval to look up the date in the season_start vector and extract the associated season_name.
library(dplyr)
# given Date class vector returns vector of season names
date2season <- function(date) {
season_start <- c("0101", "0321", "0621", "0923", "1221") # mmdd
season_name <- c("Summer", "Autumn", "Winter", "Spring", "Summer")
mmdd <- format(date, "%m%d")
season_name[findInterval(mmdd, season_start)] ##
}
df %>% mutate(season = date2season(as.Date(Date_dmy, "%d/%m/%Y")))
giving:
sample_station Date_dmy Temperature season
1 A 01/01/2000 17 Summer
2 A 08/08/2000 20 Winter
3 A 16/03/2001 24 Summer
4 A 22/09/2001 19 Winter
5 A 01/06/2002 17 Autumn
...snip...
1a) The last line in date2season, marked ##, could optionally be replaced with
season_name[(mmdd >= "0101") + (mmdd >= "0321") + (mmdd >= "0621") +
(mmdd >= "0923") + (mmdd >= "1221")]
and in that case you don't need the line defining season_start either.
2) An alternative is to use case_when:
df %>%
mutate(mmdd = format(as.Date(Date_dmy, "%d/%m/%Y"), "%m%d"),
season = case_when(
mmdd <= "0320" ~ "Summer",
mmdd <= "0620" ~ "Autumn",
mmdd <= "0922" ~ "Winter",
mmdd <= "1220" ~ "Spring",
TRUE ~ "Summer")) %>%
select(-mmdd)
R Need to extract month and assign season
Regarding the subject/title of the question, its actually possible to do this without extracting the month. The first two solutions below do not extract the month. There is also a third solution which does extract the month but only to increment it.
1) as.yearqtr/as.yearmon Convert the dates to year/month and add one month (1/12). Then the calendar quarters correspond to the seasons so convert to year/quarter, yq
, and label the quarters as shown:
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"))
giving:
dates Season
1 7/28/2010 summer
2 4/21/2011 spring
3 7/23/2010 summer
4 6/14/2011 summer
5 12/3/2010 winter
6 11/18/2010 fall
7 11/6/2010 fall
8 7/23/2010 summer
9 6/14/2011 summer
1a) A variation of this is to use chron's quarters
which produces a factor so that levels=1:4
does not have to be specified. To use chron replace the last line in (1) with:
library(chron)
DF$Season <- factor(quarters(as.chron(yq)),
labels = c("winter", "spring", "summer", "fall"))
chron could also be used in conjunction with the remaining solutions.
2) cut. This solution only uses the base of R. First convert the dates to the first of the month using cut
and add 32 to get a date in the next month, d
. The quarters corresponding to d
are the seasons so compute the quarters using quarters
and construct the labels in the same fashion as the first answser:
d <- as.Date(cut(as.Date(DF$dates, "%m/%d/%Y"), "month")) + 32
DF$Season <- factor(quarters(d), levels = c("Q1", "Q2", "Q3", "Q4"),
labels = c("winter", "spring", "summer", "fall"))
giving the same answer.
3) POSIXlt This solution also uses only the base of R:
p <- as.POSIXlt(as.Date(DF$dates, "%m/%d/%Y"))
p$day <- 1
p$mo <- p$mo+1
DF$Season <- factor(quarters(p), levels = c("Q1", "Q2", "Q3", "Q4"),
labels = c("winter", "spring", "summer", "fall"))
Note 1: We could optionally omit levels=
in all these solutions if we knew that every season appears.
Note 2: We used this data frame:
DF <- data.frame(dates = c('7/28/2010', '4/21/2011', '7/23/2010',
'6/14/2011', '12/3/2010', '11/18/2010', '11/6/2010', '7/23/2010',
'6/14/2011'))
Extract seasons from datetime pandas
first you want your date_UTC
in datetime
format, second, you can use pd.cut
:
date = df.date_UTC.dt.month*100 + df.date_UTC.dt.day
df['season'] = (pd.cut(date,[0,321,620,922,1220,1300],
labels=['winter','spring','summer','autumn','winter '])
.str.strip()
)
With a little numeric trick, you can get rid of the slow str.strip()
:
df['date_offset'] = (df.date_UTC.dt.month*100 + df.date_UTC.dt.day - 320)%1300
df['season'] = pd.cut(df['date_offset'], [0, 300, 602, 900, 1300],
labels=['spring', 'summer', 'autumn', 'winter'])
Related Topics
Calculate the Derivative of a Data-Function in R
Error in Bind_Rows_(X, .Id):Column Can't Be Converted from Factor to Numeric
Running an R Script Using a Windows Shortcut
Pass String as Name of Attached Data Column Name
Does R-Server or Shiny Server Create a New R Process/Instance for Each User
How to Write Data from R to Postgresql Tables with an Autoincrementing Primary Key
Dplyr 0.7 Equivalent for Deprecated Mutate_
R Dataframe with Varied Column Lengths
How to Do Str_Extract with Base R
Ggplot2: Dashed Line in Legend
Remove Text Inside Brackets, Parens, And/Or Braces
How to Count Sequences of Ones in a Logical Vector
Bold Formatting for Significant Values in a Rmarkdown Table
Split Column in Data.Table to Multiple Rows
How Many Elements in a Vector Are Greater Than X Without Using a Loop