【问题标题】:`spread= a - b` calculation on the tall data with `dplyr` and `data.table`使用 `dplyr` 和 `data.table` 对 tall 数据进行 `spread= a - b` 计算
【发布时间】:2014-04-07 22:41:52
【问题描述】:

我有一些高格式的(金融时间序列)数据:

require(data.table)
DT <- data.table(Variable=c(rep("a",times = 3), rep("b", times=3)), 
                 Date=as.Date(c("2014-04-01","2014-04-02","2014-04-03"
                                ,"2014-04-02", "2014-04-03","2014-04-04")),
                 Value=c(1:3,3:1), key=c("Variable","Date"))

DT

   Variable       Date Value
1:        a 2014-04-01     1
2:        a 2014-04-02     2
3:        a 2014-04-03     3
4:        b 2014-04-02     3
5:        b 2014-04-03     2
6:        b 2014-04-04     1

我想计算第三个变量spread,其中spread = a - b 对应每个常见的Date 行(基本上是两个时间序列之间的差值——金融领域的常见转换)。

期望的输出:

   Variable       Date Value
1:   spread 2014-04-02    -1
2:   spread 2014-04-03     1

我知道当我将dcast.data.table 数据转换为宽格式(即转换为具有列c("Date", "a", "b") 的表)时的解决方案,但是由于大数据的性能问题,有没有一种优雅的方法可以直接在tall 格式使用 a)dplyr 和 b)data.table(两部分问题)?

理想情况下,在dplyr 方面,我正在寻找像mutate(tbl_dt(DT, tall=TRUE), spread=a-b) 这样富有表现力的东西。 (免责声明:我是dplyr 的新手)

真实数据集:

# download 200 stocks from Quandl.com. requires free registration
library(Quandl); library(data.table); library(plyr)
ntickers <- 200 ; auth.token="register_free_to_obtain_token"
code.file <- tempfile()
download.file("https://s3.amazonaws.com/quandl-static-content/quandl-stock-code-list.csv",
              destfile=code.file)
tickers <- na.omit(read.csv2(code.file, sep=",", stringsAsFactors=FALSE)[,"Price.Code"])
lst <- na.omit(tickers)[1:ntickers]
names(lst) <- lst
Q <- ldply(lst, Quandl, 
           type = "raw", end_date="2014-04-08", 
           sort="asc", auth=auth.token) # might take minutes
DT <- as.data.table(Q)[,Date:=as.IDate(Date)]
setnames(DT, ".id", "Instrument")
setkey(DT, Instrument, Date)

> dim(DT); object.size(DT)
[1] 685512      8
41145752 bytes
> DT
              Instrument       Date Open High  Low Close Volume Adjusted Close
     1:    GOOG/AMEX_ABI 1981-03-11   NA   NA 6.56  6.75 217200             NA
     2:    GOOG/AMEX_ABI 1981-03-12   NA   NA 6.66  6.88 616400             NA
     3:    GOOG/AMEX_ABI 1981-03-13   NA   NA 6.81  6.84 462000             NA
     4:    GOOG/AMEX_ABI 1981-03-16   NA   NA 6.81  7.00 306400             NA
     5:    GOOG/AMEX_ABI 1981-03-17   NA   NA 6.88  6.88 925600             NA
    ---                                                                       
685508: YAHOO/TSX_AHX_TO 2014-04-02 0.75 0.75 0.75  0.75   5000           0.75
685509: YAHOO/TSX_AHX_TO 2014-04-03 0.79 0.82 0.75  0.82  25700           0.82
685510: YAHOO/TSX_AHX_TO 2014-04-04 0.81 0.81 0.78  0.80   4500           0.80
685511: YAHOO/TSX_AHX_TO 2014-04-07 0.80 1.05 0.80  0.96  40400           0.96
685512: YAHOO/TSX_AHX_TO 2014-04-08 0.95 0.96 0.90  0.95  21300           0.95

【问题讨论】:

  • 假设 500 万行 * 3 列(1000 个仪器,每个仪器每天都有 20 年的历史)是的,我知道 dcast.data.table,这就是我的想法。问题已编辑
  • 可能发生在任何地方(数据间隙、假期等)。此外,ab 在日期组中的位置事先不知道,并且可能还有其他变量,所以这需要按变量名 (a - b) 引用/子集,而不是按位置 (Value[1] - Value[2]),抱歉不清楚
  • 我可以生成一些典型的大样本(多变量价格数据),因为这是金融中反复出现的主题。在 SO,链接到 Google Drive 上共享多 MB 数据的常用方法是什么?
  • @Arun 您删除的解决方案似乎是最直接的方法(顺便说一句,过滤 NA 可能比在 if 期间这样做更便宜) - 为什么 将其删除?
  • @Arun 包含用于更大数据集下载的代码

标签: r data.table dplyr


【解决方案1】:

你应该能够使用这个:

> merge(DT["a", ], DT["b",], by="Date")
         Date Variable.x Value.x Variable.y Value.y
1: 2014-04-02          a       2          b       3
2: 2014-04-03          a       3          b       2

merge.data.table 的帮助页面建议您阅读常见问题解答 1.12,以详细比较此方法与 X[Y,...] 方法。

【讨论】:

  • 谢谢,问题解决了。 +1 用于单线和常见问题解答参考。 merge vs X[Y, ...] 的一个缺点是前者不支持 roll 参数。即使我在最初的问题中没有触及它,但当科学家容忍使用最后可用的值替换缺失值时,请考虑观察间隙的情况:unique(setkey(rbind(X[Y, roll=T, rollends=FALSE], Y[X, roll=T, rollends=FALSE], use.names=T), Variable, Date))。在这个特定的问题中,X=DT["a",]; Y=DT["b",]。感谢 FAQ 1.12 的观点!
【解决方案2】:

这是使用 dplyr 的一种方法。首先我们创建数据:

require(dplyr)

df <- data.frame(
  Variable = rep(c("a", "b"), each = 3), 
  Date = rep(as.Date("2014-04-01") + 0:2, 2),
  Value = c(1:3, 3:1)
)

我们可以使用矢量化而不是旋转成宽格式 比较:

df %.% 
  group_by(Date) %.%
  summarise(spread = Value[Variable == "a"] - Value[Variable == "b"])

## Source: local data frame [3 x 2]
## 
##         Date spread
## 1 2014-04-01     -2
## 2 2014-04-02      0
## 3 2014-04-03      2

如果 a 或 b 有多个值,这将正确地失败,因为 summarise() 要求结果的长度为 1。同样的做法 可以与 data.table 一起使用,但您需要更加小心 关于检查结果(因为数据表不那么严格/更多 与 dplyr 相比,这里更灵活)。

您也可以使用 BondedDust 建议的连接方法。它不是 使用 dplyr 和使用 data.table 一样方便:

a <- df %.% filter(Variable == "a") %.% select(-Variable)
b <- df %.% filter(Variable == "b") %.% select(-Variable)

inner_join(a, b, by = "Date") %.%
  mutate(spread = Value.x - Value.y)

##         Date Value.x Value.y spread
## 1 2014-04-01       1       3     -2
## 2 2014-04-02       2       2      0
## 3 2014-04-03       3       1      2

【讨论】:

  • 感谢介绍,我非常喜欢df %.% group_by(Date) %.% summarise(spread = Value[Variable == "a"] - Value[Variable == "b"]) 语法。为了进一步使其更加紧凑(可能存在太多松散端的风险),您是否认为summarisemutate 可以直接接受公式表达式spread = a - b 作为参数并将其解析为高/宽格式不可知逻辑,因此如果没有找到具有该名称的列,则将它们猜测为行子集(想想reshape2:::guess_value 类比)。
  • @DanielKrizian 没有。我认为您应该以标准方式存储变量并使用标准方式来引用它们,例如 vita.had.co.nz/papers/tidy-data.html
  • 谢谢,我花时间阅读了文档。有趣的框架。 Quite common case in financial modelling
【解决方案3】:

这是一个使用 dcast.data.table 的 data.table 方法。

我希望我提供一个有用的开始,关于选择 NA 和速度增益有以下一些问题。

# Create Dataset
require(data.table)
require(reshape2)
DT <- data.table(Variable=c(rep("a",times = 3), rep("b", times=3)), 
             Date=as.Date(c("2014-04-01","2014-04-02","2014-04-03"
                            ,"2014-04-02", "2014-04-03","2014-04-04")),
             Value=c(1:3,3:1), key=c("Variable","Date"))

# using data.table
DT2 <- dcast.data.table(DT, Date ~ Variable, drop=FALSE) 
DT2[, spread:= a-b, by = Date][!is.na(spread),]
# Actually I'm not clear about the different between `drop= FALSE` and `drop = TRUE` 

这是输出

日期 a b 价差 1:2014-04-02 2 3 -1 2: 2014-04-03 3 2 1

【讨论】:

  • drop=FALSE 还包括缺失的组合。考虑DT &lt;- data.table(x=1:2, y=3:4, z=5:6, val=1L); dcast.data.table(DT, x+y~z, value.var="val", drop=TRUE)。现在更改 drop=FALSE 并重试。
猜你喜欢
  • 2021-10-22
  • 1970-01-01
  • 2019-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-25
相关资源
最近更新 更多