R: создайте новый столбец в R, чтобы определить семестр на основе двух дат

У меня есть некоторые данные. Идентификатор и дата, и я пытаюсь создать новое поле для семестра.

df:

id  date
1   20160822
2   20170109
3   20170828
4   20170925
5   20180108
6   20180402
7   20160711
8   20150831
9   20160111
10  20160502
11  20160829
12  20170109
13  20170501

У меня также есть таблица semester:

start       end         season_year
20120801    20121222    Fall-2012
20121223    20130123    Winter-2013
20130124    20130523    Spring-2013
20130524    20130805    Summer-2013
20130806    20131228    Fall-2013
20131229    20140122    Winter-2014
20140123    20140522    Spring-2014
20140523    20140804    Summer-2014
20140805    20141227    Fall-2014
20141228    20150128    Winter-2015
20150129    20150528    Spring-2015
20150529    20150803    Summer-2015
20150804    20151226    Fall-2015
20151227    20160127    Winter-2016
20160128    20160526    Spring-2016
20160527    20160801    Summer-2016
20160802    20161224    Fall-2016
20161225    20170125    Winter-2017
20170126    20170525    Spring-2017
20170526    20170807    Summer-2017
20170808    20171230    Fall-2017
20171231    20180124    Winter-2018
20180125    20180524    Spring-2018
20180525    20180806    Summer-2018
20180807    20181222    Fall-2018
20181223    20190123    Winter-2019
20190124    20190523    Spring-2019
20190524    20180804    Summer-2019

Я хочу создать новое поле в df, если df$date находится между semester$start и semester$end, а затем поместить соответствующее значение semester$season_year в df

Я пытался посмотреть, может ли пакет смазки помочь, но, похоже, это больше для расчетов.

Я видел этот вопрос, и он кажется наиболее близким к тому, что я хочу, но, чтобы усложнить ситуацию, не все наши семестры составляют шесть месяцев.


person tangerine7199    schedule 26.06.2018    source источник
comment
Взгляните на этот вопрос. Это не совсем то же самое, но вы должны пройти 90% пути: stackoverflow.com/questions/37933800/   -  person divibisan    schedule 26.06.2018


Ответы (2)


Решение, использующее объединение обновлений non-equi с использованием пакетов data.table и lubridate, может быть следующим:

library(data.table)

setDT(df)
setDT(semester)


df[,date:=as.IDate(as.character(date), format = "%Y%m%d")]
semester[,':='(start = as.IDate(as.character(start), format = "%Y%m%d"), 
                         end=as.IDate(as.character(end), format = "%Y%m%d"))]


df[semester, on=.(date >= start, date <= end), season_year := i.season_year]

df
#    id       date season_year
# 1:  1 2016-08-22   Fall-2016
# 2:  2 2017-01-09 Winter-2017
# 3:  3 2017-08-28   Fall-2017
# 4:  4 2017-09-25   Fall-2017
# 5:  5 2018-01-08 Winter-2018
# 6:  6 2018-04-02 Spring-2018
# 7:  7 2016-07-11 Summer-2016
# 8:  8 2015-08-31   Fall-2015
# 9:  9 2016-01-11 Winter-2016
# 10: 10 2016-05-02 Spring-2016
# 11: 11 2016-08-29   Fall-2016
# 12: 12 2017-01-09 Winter-2017
# 13: 13 2017-05-01 Spring-2017

Данные:

df <- read.table(text="
id  date
1   20160822
2   20170109
3   20170828
4   20170925
5   20180108
6   20180402
7   20160711
8   20150831
9   20160111
10  20160502
11  20160829
12  20170109
13  20170501",
header = TRUE, stringsAsFactors = FALSE)


semester <- read.table(text="
start       end         season_year
20120801    20121222    Fall-2012
20121223    20130123    Winter-2013
20130124    20130523    Spring-2013
20130524    20130805    Summer-2013
20130806    20131228    Fall-2013
20131229    20140122    Winter-2014
20140123    20140522    Spring-2014
20140523    20140804    Summer-2014
20140805    20141227    Fall-2014
20141228    20150128    Winter-2015
20150129    20150528    Spring-2015
20150529    20150803    Summer-2015
20150804    20151226    Fall-2015
20151227    20160127    Winter-2016
20160128    20160526    Spring-2016
20160527    20160801    Summer-2016
20160802    20161224    Fall-2016
20161225    20170125    Winter-2017
20170126    20170525    Spring-2017
20170526    20170807    Summer-2017
20170808    20171230    Fall-2017
20171231    20180124    Winter-2018
20180125    20180524    Spring-2018
20180525    20180806    Summer-2018
20180807    20181222    Fall-2018
20181223    20190123    Winter-2019
20190124    20190523    Spring-2019
20190524    20180804    Summer-2019",
header = TRUE, stringsAsFactors = FALSE)
person MKR    schedule 26.06.2018
comment
Спасибо за ваше предложение! Я начал это около двадцати минут назад, чтобы добавить новое поле в df, и это еще не закончилось. есть ли у вас какие-либо мысли, которые могут помочь ускорить его? - person tangerine7199; 26.06.2018
comment
Только вариант @Walker может заключаться в том, чтобы не использовать lubridate. Вместо этого вы можете использовать as.IDate из самого data.table. Надеюсь, это поможет. - person MKR; 26.06.2018
comment
@Walker Я обновил ответ. Спасибо, что указали. Я изменил ответ, чтобы использовать IDate. Пожалуйста, сообщите нам о преимуществах производительности, так как это также поможет будущим пользователям. - person MKR; 26.06.2018
comment
Используйте data.table::between() вместо (date >= start, date <= end) - person smci; 26.06.2018

Это работает?

library(lubridate)

semester$start <- ymd(semester$start)
semester$end <- ymd(semester$end)
df$date <- ymd(df$date)

LU <-  Map(`:`, semester$start, semester$end)
LU <- data.frame(value = unlist(LU),
                 index = rep(seq_along(LU), lapply(LU, length)))


df$semester <- semester$season_year[LU$index[match(df$date, LU$value)]]
person Christian Million    schedule 26.06.2018