分配日期到财政年度

14

我正在努力编写一些代码,以便查看日期并将其分配到财年。我完全被卡住了。

我有一个包含POSIXct格式日期的变量:

df$Date
#2015-05-01 CST
#2015-04-30 CST
#2014-09-01 CST

我需要做的是将那些日期转换成财政年度,该年度从5月1日到4月30日。例如,2016财政年度为2015-05-01到2016-04-30。结果应该类似于这样:

df$Date                df$FiscalYear
#2015-05-01 CST        #FY2016
#2015-04-30 CST        #FY2015
#2014-09-01 CST        #FY2015

有没有简单的方法做到这一点?


可能重复?http://stackoverflow.com/questions/26684514/how-to-calculate-mean-by-date-grouped-as-fiscal-quarters - romants
我并不认为那个解决方案特别清晰易懂,或者说是我自己不够聪明,可能更多是后者。 - Churly Pickle
4个回答

23
这里有一些替代方案。它们都返回数值年份,但如果你真的需要以FY开头的字符串,可以使用paste0("FY", ...),例如paste0("FY", as.integer(as.yearmon(dates) - 4/12 + 1))。它们都支持向量输入,即输入dates可以是一个向量。 1) zoo::as.yearmon zoo包中有一个"yearmon"类,它将年/月表示为年份+分数,其中分数为0表示一月,1/12表示二月,2/12表示三月,依此类推。
使用这个一行代码就可以完成。它减去4/12(因为四月是年底),然后加1(即加一年)。然后取整数部分即可得到年份:
library(zoo)

as.integer(as.yearmon(dates) - 4/12 + 1)
## [1] 2016 2015 2015

2) POSIXlt 这里有一个不使用任何包的解决方案。将日期转换为POSIXlt类。它的mo组件将一月表示为0,二月表示为1,以此类推。因此,如果我们是五月或之后(mo为4或更多),则财政年度为下一个日历年,否则为当前日历年。POSIXlt对象的year组件是自1900年以来的年数,因此如果我们是五月或之后,则将年份加到1900年上再加1:
lt <- as.POSIXlt(dates)
lt$year + (lt$mo >= 4) + 1900
## [1] 2016 2015 2015

3) 格式 如果月份大于或等于5,则将年份加1(如果不是,则加零)。这也不使用任何软件包:

as.numeric(format(dates, "%Y")) + (format(dates, "%m") >= "05")
## [1] 2016 2015 2015

4) substr。我们可以使用substr提取年份,转换为数字,并在提取的月份(也使用substr提取)为"05"或更大时加1。再次不使用任何包。
as.numeric(substr(dates, 1, 4)) + (substr(dates, 6, 7) >= "05")
## [1] 2016 2015 2015

5) read.table 这个函数也不使用任何包。

with(read.table(text = format(dates), sep = "-"), V1 + (V2 >= 5))
## [1] 2016 2015 2015

注意:我们将这个作为输入的“dates”使用了。
dates <- as.Date(c("2015-05-01", "2015-04-30", "2014-09-01"))

添加了 (2),(3) 和 (4)。 - G. Grothendieck
2
谢谢GG。我认为英国的等价物是as.numeric(format(dates, "%Y")) - (format(dates, "%m") <= "03") - geotheory
太棒了,选择第三个方案,干得好。应该是正确答案,更易读。 - Tunn

11

继G. Grothendieck的优秀回答之后,使用lubridate

year(dates) + (month(dates) >= 5)

7
你可以使用seq与POSIXct对象一起使用,生成跨越数据的年份的“切点”或财政年度的第一天列表,然后使用findInterval来计算特定日期落入哪个区间:
> dates <- as.POSIXct( c('2015-05-01','2015-04-30','2014-09-01'))
> fy.tmp <- seq( as.POSIXct('2000-05-01'), length=25, by='year')
> fiscalYear <- (2001:2025)[ findInterval(dates,fy.tmp) ]
> fiscalYear
[1] 2016 2015 2015

如果您想要结果为因子,可以使用cut函数而不是findInterval


0

尝试修改这个:

Federal.FY <- function(x,firstMonth=10,  # I've altered this line to follow the federal fiscal year, October
                       fy.prefix='FY',
                       quarter.prefix='Q',
                       sep='-',
                       level.range=c(min(x), max(x)) ) {if(level.range[1] > min(x) | level.range[2] < max(x)) {
warning(paste0('The range of x is greater than level.range. Values ',
               'outside level.range will be returned as NA.'))}
quarterString <- function(d) {
year <- as.integer(format(d, format='%Y'))
month <- as.integer(format(d, format='%m'))
y <- ifelse(firstMonth > 1 & month >= firstMonth, year+1, year)
q <- cut( (month - firstMonth) %% 12, breaks=c(-Inf,2,5,8,Inf),
          labels=paste0(quarter.prefix, 1:4))
return(paste0(fy.prefix, y, sep, q))}
vals <- quarterString(x)
levels <- unique(quarterString(seq(
as.Date(format(level.range[1], '%Y-%m-01')),
as.Date(format(level.range[2], '%Y-%m-28')), by='month')))
return(factor(vals, levels=levels, ordered=TRUE))}

d <- as.Date("2016-10-02")
Federal.FY(d)
##[1] FY2017-Q1
##Levels: FY2017-Q1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接