【问题标题】:Get the 4th Wednesday of each November in R在 R 中获取每年 11 月的第四个星期三
【发布时间】:2011-11-23 18:05:54
【问题描述】:

我有一个时间索引矩阵(xts 对象),我只想要每年 11 月的第四个星期三。

require(quantmod)
getSymbols("^GSPC", from="1900-01-01")   #returns GSPC
GSPC$WED  <- weekdays(time(GSPC)) == "Wednesday"
GSPC$NOV  <- months(time(GSPC)) == "November"
G         <- GSPC[GSPC$WED==1 & GSPC$NOV==1]

这就是我在 R 中所能达到的程度。为了解决我的问题,我开始使用 bash。

write.zoo(G, "wen_in_nov")

我做了以下破解:

cat wen_in_nov |
grep -v IND |
cut -c 1-10 | 
sed 's/-/ /g' | 
awk '{if($3 >= 22 && $3 < 29) print $1, $2, $3, "winner"}' |
sed 's/ /-/g' > fourth_wen

fourth_wen 文件需要将 - 与字符串 'winner' 分开,所以我只是在 vi 中这样做了。导入回 R:

fourth_wen <- read.zoo("fourth_wen", format="%Y-%m-%d")

这实际上是自 1950 年以来 11 月的第四个星期三。有没有办法在 R 中用更少的代码完成这一切?

【问题讨论】:

  • 您能展示一下您的 wen_in_nov 的样子吗?
  • Jaypal,您可以将上面的前 6 行复制并粘贴到 R 中,您应该将文件放在工作目录中(当然,您需要安装 quantmod

标签: r


【解决方案1】:

使用 .indexmon 等直接访问 POSIXlt 值

GSPC[.indexmon(GSPC)==10 & .indexmday(GSPC) > 22 & .indexmday(GSPC) < 29
       &.indexwday(GSPC) == 3]

           GSPC.Open GSPC.High GSPC.Low GSPC.Close GSPC.Volume GSPC.Adjusted
2007-11-28   1432.95   1471.62  1432.95    1469.02  4508020000       1469.02
2008-11-26    852.90    887.68   841.37     887.68  5793260000        887.68
2009-11-25   1106.49   1111.18  1104.75    1110.63  3036350000       1110.63
2010-11-24   1183.70   1198.62  1183.70    1198.35  3384250000       1198.35
2011-11-23   1187.48   1187.48  1161.79    1161.79  3798940000       1161.79

【讨论】:

  • 不错。通过访问 bashscript 并返回来防止我出错。
  • 最终用户必须记住,它使用相同的容易出错的 POSIX 约定,将月份从 0 到 11。不太友好。
  • 你的表情错过了1961年、1967年、1972年、1978年、1989年、1995年和2006年;查看我编辑的答案。
  • 也错过了2000年;错误归结为需要“>=”的“>”(与第 22 天相比)。
  • 你对容易出错的问题提出了很好的看法。这个月从0 开始,但indexmday 不是。我选择这个作为答案是因为 1)它使用熟悉的语法(不是最好的理由,我知道我需要稍微扩展一下)和 2)你可以用它来子集黑色星期五,这是第四个星期四的第二天十一月。黑色星期五并不总是 11 月的第四个星期五。我肯定会很快探索 Rcpp。我需要一个关于 C++ 和 Boost 的良好截屏视频课程。
【解决方案2】:

我的RcppBDT 包有这个功能。

RcppBDT 包装了Boost Date_Time 库的一部分,而Boost Date_Time 恰好有许多类似的函数。所以这里是 2008 年到 2011 年的快速循环,每年 11 月的第四个星期三:

R> library(RcppBDT)
Loading required package: Rcpp
Creating a generic function for ‘print’ from package ‘base’ in package ‘RcppBDT’
Creating a generic function for ‘format’ from package ‘base’ in package ‘RcppBDT’
R> for (y in 2008:2011) print(getNthDayOfWeek(fourth, Wed, Nov, y))
[1] "2008-11-26"
[1] "2009-11-25"
[1] "2010-11-24"
[1] "2011-11-23"
R> 

这里的fourthWedNov 是包命名空间中的常量,模仿底层C++ 库中对应的enum 类型。使用起来非常方便。

编辑:这是自 2000 年以来所有 4th-Wed-in-Nov 的完整示例。我确保周三的 GSPC 和向量 Wed 一致 @ 987654332@ 类型。然后只需将Wed 粘贴到GSPC 中即可:

R> library(quantmod)
Loading required package: Defaults
Loading required package: TTR
R> getSymbols("^GSPC", from="1900-01-01")  
R> Wed <- sapply(2000:2011, function(y) getNthDayOfWeek(fourth, Wed, Nov, y))
R> index(GSPC) <- as.Date(index(GSPC))
R> GSPC[as.Date(Wed)]
           GSPC.Open GSPC.High GSPC.Low GSPC.Close GSPC.Volume GSPC.Adjusted
2000-11-22   1347.35   1347.35  1321.89    1322.36   963200000       1322.36
2001-11-28   1149.50   1149.50  1128.29    1128.52  1423700000       1128.52
2002-11-27    913.31    940.41   913.31     938.87  1350300000        938.87
2003-11-26   1053.89   1058.45  1048.28    1058.45  1097700000       1058.45
2004-11-24   1176.94   1182.46  1176.94    1181.76  1149600000       1181.76
2005-11-23   1261.23   1270.64  1259.51    1265.61  1985400000       1265.61
2006-11-22   1402.69   1407.89  1402.26    1406.09  2237710000       1406.09
2007-11-28   1432.95   1471.62  1432.95    1469.02  4508020000       1469.02
2008-11-26    852.90    887.68   841.37     887.68  5793260000        887.68
2009-11-25   1106.49   1111.18  1104.75    1110.63  3036350000       1110.63
2010-11-24   1183.70   1198.62  1183.70    1198.35  3384250000       1198.35
2011-11-23   1187.48   1187.48  1161.79    1161.79  3798940000       1161.79
R> 

编辑 2 作为公共服务公告,这是 Jeff 的回答失败的地方:

R> ind <- .indexmon(GSPC)==10 & .indexmday(GSPC) > 22 & .indexmday(GSPC) < 29 
+         & .indexwday(GSPC) == 3
R> index(GSPC)[ind]
 [1] "1951-11-28" "1952-11-26" "1953-11-25" "1954-11-24" "1955-11-23"
 [6] "1956-11-28" "1957-11-27" "1958-11-26" "1959-11-25" "1960-11-23"
[11] "1962-11-28" "1963-11-27" "1964-11-25" "1965-11-24" "1966-11-23"
[16] "1968-11-27" "1969-11-26" "1970-11-25" "1971-11-24" "1973-11-28"
[21] "1974-11-27" "1975-11-26" "1976-11-24" "1977-11-23" "1979-11-28"
[26] "1980-11-26" "1981-11-25" "1982-11-24" "1983-11-23" "1984-11-28"
[31] "1985-11-27" "1986-11-26" "1987-11-25" "1988-11-23" "1990-11-28"
[36] "1991-11-27" "1992-11-25" "1993-11-24" "1994-11-23" "1996-11-27"
[41] "1997-11-26" "1998-11-25" "1999-11-24" "2001-11-28" "2002-11-27"
[46] "2003-11-26" "2004-11-24" "2005-11-23" "2007-11-28" "2008-11-26"
[51] "2009-11-25" "2010-11-24" "2011-11-23"

R> S <- 1951:2011
R> S[!S %in% as.numeric(format(index(GSPC)[ind], "%Y")) ]
[1] 1961 1967 1972 1978 1989 1995 2000 2006
R> 

所以当你使用他的方法时,60 个样本中缺少 8 年。

【讨论】:

  • 太棒了!那么这个包是否对日期进行自然语言处理?
  • 不,我已经提到 'first'、'second'、... 只是 1、2、3 的常量。 Dito 表示一周中的几天和月份。键入“fourth, Wed, Nov”只是比键入“4, 3, 11”更容易,但这最终会传递给 C++ 代码。但即使在 C++ 中,您也会使用“fourth, Wed, Nov”的所有 API 函数,因为这些是适当的 Boost 命名空间中的枚举。这只是一个非常聪明的技巧,不需要 NLP ;-)
  • 我正在重新安装 Boost 来试一试。 (以为我已经安装了)
  • 再次提醒我,您使用的是 OS X?它应该可以在任何 Linux 上轻松运行,并且在 Windows 上,您可以获得预构建的 RcppBDT 二进制文件。对于 OS X,您可能需要调整包含路径。你可以随时在 Rcpp-devel 上提问。
  • 我得到了你的例子。您将如何在诸如 GSPC 之类的 xts 对象上调用此函数?或者您会创建一个单独的对象并将其与诸如 merge(GSPC, Rccpobject, all=FALSE) 之类的东西合并吗?
【解决方案3】:

这是一种方法

nov_dates <- expand.grid(1:30, 11, 1900:2011) 
nov_dates <- apply(nov_dates, 1, paste, collapse = "-")
nov_dates <- dmy(nov_dates)
nov_wed   <- nov_dates[wday(nov_dates, label = TRUE) == 'Wed']
nov_4wed  <- nov_wed[seq_along(nov_wed) %% 4 == 0]

编辑。一个小错误仍然存​​在。如果 11 月有 5 个星期三,则此代码不起作用。一个小的更正会处理它,我会尽快发布它。这是一个正常工作的解决方案

library(plyr)
library(lubridate)
nov_dates <- expand.grid(day = 1:30, month = 11, year = 1900:2011) 
nov_dates <- transform(nov_dates, 
   date = dmy(paste(day, month, year, sep = "-"))

nov_4_wed <- ddply(nov_dates, .(year), summarize, date[wday(date) == 4][4])

【讨论】:

    【解决方案4】:

    我没有花太多时间在时间​​序列对象上,所以可能有比使用substr 提取日期更好的功能(其实我确定有,只是不知道它离开了我的头顶)。但这似乎有效:

    rs <- subset(GSPC,weekdays(time(GSPC)) == "Wednesday" & 
                        months(time(GSPC)) == "November" & 
                        as.numeric(substr(time(GSPC),9,10)) >= 22 & 
                        as.numeric(substr(time(GSPC),9,10)) < 29)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-30
      • 2020-06-21
      • 2019-02-12
      相关资源
      最近更新 更多