不确定我的标题是否合适。假设我保存这样的data.table:
set.seed(1234);
Type <- c("o", "o", "o", "o", "o", "o", "o", "s", "s", "s", "s", "s");
Contract.Month <- c("F", "G", "F", "G", "F", "G", "H", "F", "G", "F", "G", "F");
Date <- c(as.Date("2015-10-21"), as.Date("2015-10-21"), as.Date("2015-10-22"), as.Date("2015-10-22"), as.Date("2015-10-23"), as.Date("2015-10-23"), as.Date("2015-10-23"), as.Date("2015-10-21"), as.Date("2015-10-21"), as.Date("2015-10-22"), as.Date("2015-10-22"), as.Date("2015-10-23"));
Price <- rnorm(12);
Volume <- c(11, 10, 0, 12, 0, 0, 12, 1, 1, 1, 1, 1);
DT = data.table(Date, Price, Type, Contract.Month, Volume);
结果如下表:
Date Price Type Contract.Month Volume
1: 2015-10-21 -1.2070657 o F 11
2: 2015-10-21 0.2774292 o G 10
3: 2015-10-22 1.0844412 o F 0
4: 2015-10-22 -2.3456977 o G 12
5: 2015-10-23 0.4291247 o F 0
6: 2015-10-23 0.5060559 o G 0
7: 2015-10-23 -0.5747400 o H 12
8: 2015-10-21 -0.5466319 s F 1
9: 2015-10-21 -0.5644520 s G 1
10: 2015-10-22 -0.8900378 s F 1
11: 2015-10-22 -0.4771927 s G 1
12: 2015-10-23 -0.9983864 s F 1
现在我想要实现的是获得具有类型"o"的唯一天数的所有行,并将类型"s"的行转换为列。结果会是这样的:
Date Price Contract.Month Volume S1.Price S2.Price
1: 2015-10-21 -0.7485253 F 11 -0.5466319 -0.5644520
2: 2015-10-22 0.3015246 G 12 -0.4771927
3: 2015-10-23 0.4846456 H 12
为了进一步解释,我在实际场景中使用的是在一个大数据表中加载的期货价格及其点差价格。"o"是直接的,"s"是分散的。因此,我想创建连续合约,从直接行,然后添加从该月到该日的所有点差作为列。所以在我的例子中,我使用volume来创建连续合约(如果volume为0,那么当天不使用该合约,但我也想简单地使用最早的合约,并将其作为另一种方法使用到到期)。在我的例子中,第一天有两个点差,因为直接合约是F,点差是F和G,第二天只有G点差,因为直接合约已经是G了,第三天没有点差信息,因为直接合约月份晚于当天的点差。
我已经试了好几天了,但没有成功。我是R和数据表的新手,但基本原理对我来说似乎很清楚,我只是不知道如何实现这种精确的转换,因为它看起来不太简单。任何帮助将非常感激!
编辑添加set.seed
Edit2 如果有人发现这个问题,我做了这样的事情(抱歉没有检查它是否适用于样本数据,但你可以得到一个想法):
DTs <- DT %>% filter(Type=="s")
DTo <- DT %>% filter(Type=="o")
DT1 <- DT %>% filter(Type=="o") %>% group_by(Date) %>% filter(Date == Date & Contract.Month == min(Contract.Month) & Volume != 0)
out = inner_join(DT1, DTs, by = c("Date" = "Date")) %>% filter(Contract.Month.x <= Contract.Month.y)
out = out[, s1_seq:=paste0('s1_', seq(.N)), by=Date]
dcast(out, ... ~ s1_seq, value.var = c("Contract.Month.y", "Price.y"))
我试了一下,这是我得到的:(我使用set.seed(1234),你需要库(dplyr)来执行代码)
DT1 <- DT %>% filter(Type=="o") %>% group_by(Date) %>% filter(Volume==max(Volume))
第一部分很简单,DT1包含由最大音量过滤的组"o"中的唯一天数:
Date Price Type Contract.Month Volume
1 2015-10-21 -1.207066 o F 11
2 2015-10-22 -2.345698 o G 12
3 2015-10-23 -0.574740 o H 12
第二部分有点棘手,我使用的代码有一个糟糕的运行时,但这是我想出的解决方案:
DTs <- DT %>% filter(Type=="s")
DTo <- DT %>% filter(Type=="o")
out <- data.frame(matrix(NA,ncol=length(unique(DT$Contract.Month)),nrow=length(unique(DTo$Date))),"Date"=unique(DTo$Date))
names(out) <- c(unique(DT$Contract.Month),"Date")
创建虚拟子集和一个包含所有可能合同月份的新数据框架。
for(i in 1:nrow(out)){
for(j in 1:length(unique(DT$Contract.Month))){
if((nrow(DTo[which(DTo$Contract.Month==names(out)[j]&DTo$Date==out[i,"Date"])])!=0) &
(nrow(DTs[which(DTs$Contract.Month==names(out)[j]&DTs$Date==out[i,"Date"])])!=0)){
out[i,j] <- ifelse(DTo[which(DTo$Contract.Month==names(out)[j]&DTo$Date==out[i,"Date"])] %>% select(Volume) == 0,NA,DTs[which(DTs$Contract.Month==names(out)[j]&DTs$Date==out[i,"Date"])] %>% select(Price))
}
}
}
现在,每个可能的合约月份在两个虚拟数据集中按天进行比较,如果类型o的成交量= 0,则类型s的价格保存在特定的合约月份。
cbind(DT1,out[,1:3])
Date Price Type Contract.Month Volume F G H
1: 2015-10-21 -1.207066 o F 11 -0.5466319 -0.5644520 NA
2: 2015-10-22 -2.345698 o G 12 NA -0.4771927 NA
3: 2015-10-23 -0.574740 o H 12 NA NA NA
绑定这个data.frame,结果看起来就像你从你的问题中得到的那样。
希望对你有帮助。