在我的数据集中,我想创建一个新变量,其中月份向后设置一个。我可以这样做:
df$month.min.1 <- gsub('1', '12', df$month)
df$month.min.1 <- gsub('2', '1', df$month)
df$month.min.1 <- gsub('3', '2', df$month)
df$month.min.1 <- gsub('4', '3', df$month)
....
由于我还想创建月份设置为两个月和三个月的变量,我想知道是否有更有效的方法来做到这一点?
答案 0 :(得分:3)
听起来你只有1到12代表你的“月”。如果是这种情况,您可以编写如下函数:
myfun <- function(x = 1:12, n = 1) c(tail(x, n), head(x, -n))
myfun()
# [1] 12 1 2 3 4 5 6 7 8 9 10 11
然后,您可以使用它来创建滞后值。
一些例子:
set.seed(1)
x <- sample(12, 20, replace = TRUE) ## Imagine this is your "month" variable
x
# [1] 4 5 7 11 3 11 12 8 8 1 3 3 9 5 10 6 9 12 5 10
myfun()[x] ## Default -- set one month backwards
# [1] 3 4 6 10 2 10 11 7 7 12 2 2 8 4 9 5 8 11 4 9
myfun(n = 2)[x] ## "n" can be changed
# [1] 2 3 5 9 1 9 10 6 6 11 1 1 7 3 8 4 7 10 3 8
答案 1 :(得分:3)
如果m
是月份的向量,使得每个组件都是1(Jan)到12(Dec)之间的数字,则这是前几个月k
个月的月份数:
(m - k - 1) %% 12 + 1
<强>实施例强>
m <- 1:12 # input months
# one month before
k <- 1
(m - k - 1) %% 12 + 1 ## 12 1 2 3 4 5 6 7 8 9 10 11
# two months before
k <- 2
(m - k - 1) %% 12 + 1 ## 11 12 1 2 3 4 5 6 7 8 9 10
# three months before
k <- 3
(m - k - 1) %% 12 + 1 ## 10 11 12 1 2 3 4 5 6 7 8 9
# one month in the future
k <- -1
(m - k - 1) %% 12 + 1 ## 2 3 4 5 6 7 8 9 10 11 12 1
注意如果我们使用编码0(Jan)到11(Dec),那么公式简化为此,其中m0
是新编码中的月份向量和结果也在新编码中:
(m0 - k) %% 12
答案 2 :(得分:2)
您可以使用difftime
但是对于加法和减法,我喜欢lubridate
包。请注意,此答案以前使用mydate - months(1)
语法,如果日期是在该月的最后一天,则该语法可能会产生看似不正确的结果。 %m-%
(或%m+%
)语法确实可以像大多数人期望的那样工作。
library(lubridate)
mydate <- as.Date('2013-12-31')
mydate %m-% months(1)
这给出了以下输出:
> library(lubridate)
> mydate <- as.Date('2013-12-31')
> mydate %m-% months(1)
[1] "2013-11-30"
编辑:Hadley在下面的评论中指出,在某些情况下可能很难定义什么是“正确的”。根据{{1}}包文档(我的重点):
用句点指导算术的逻辑可能不直观。 从版本1.3.0开始,lubridate强制执行可逆 算术的属性(例如日期+期间 - 期间=日期) 如果您通过添加句点创建不可信的日期,则返回NA 以月或年为单位的日期。例如,添加一个月 2013年1月31日结果于2013年2月31日,这不是真实的 日期。 lubridate用户过去曾在2013年2月31日争论过 应该延期到2013年3月3日或者回到2月份 然而,这些修正中的每一个都会破坏 添加的可逆性(3月3日 - 1个月== 2月3日!= 1月31日,2月 28 - 一个月== 1月28日!= 1月31日)。如果你想添加和 以将结果回滚到最后一天的方式减去月份 一个月(适当时)使用特殊运算符%m +%和 %间 - %
这些是合理的论点,但这种设计理念有时会导致lubridate
函数产生既不是预期也不直观的结果。例如,下面的代码段可能会让大多数用户在第一次遇到它时感到惊讶:
months
我认为生成NA是因为11月只有30天,因此> z <- as.Date("2008-12-31")
> z - months(1)
[1] NA
是不可能的日期。相反,这个例子很好用,这是大多数人所期望的:
2013-11-31
故事的寓意是,如果您是> z <- as.Date("2008-12-30")
> z - months(1)
[1] "2008-11-30"
用户,那么在许多情况下,您应首先考虑使用lubridate
和%m-%
。不幸的是,%m+%
不是一种特别令人难忘或易于理解的语法,在扫描文档时它也不会在包的功能列表中脱颖而出。例如,在pdf文档的书签中,%m-%
在字母顺序问题上排在倒数第二位,离%m+%
很远,大多数用户都在寻找这样的功能
month
和%m-%
的'英语'别名可能是该套餐的有用补充,例如类似%m+%
的内容与上述语法相同,但使用方法如下:
months.lastday
答案 3 :(得分:1)
这会更有效率:
n <- 1
df$month.min.1 <- df$month - n
df$month.min.1[df$month.min.1 < 1] <- df$month.min.1[df$month.min.1 < n] + 12
这适用于任何n < 12
。
答案 4 :(得分:0)
可能效率不高,但这可行
mydate <- as.Date('2013-12-29')
tail(seq(mydate, length.out=2, by="-1 month"),1))
如果要转换数据框,可能需要将其包装在函数中Vectorize
。