尝试转换以下R data.frame:
structure(list( Time=c("09:30:01" ,"09:30:29" ,"09:35:56", "09:37:17" ,"09:37:21" ,"09:37:28" ,"09:37:35" ,"09:37:51" ,"09:42:11" ,"10:00:31"),
Price=c(1,2,3,4,5,6,7,8,9,10),
Volume=c(100,200,300,100,200,300,100,200,600,100)),
.Names = c("Time", "Price", "Volume"),
row.names = c(NA,10L),
class = "data.frame")
Time Price Volume
1 09:30:01 1 100
2 09:30:29 2 200
3 09:35:56 3 300
4 09:37:17 4 100
5 09:37:21 5 200
6 09:37:28 6 300
7 09:37:35 7 100
8 09:37:51 8 200
9 09:42:11 9 600
10 10:00:31 10 100
进入这个
Time Price Volume Bin
1 09:30:01 1 100 1
2 09:30:29 2 200 1
3 09:35:56 3 200 1
4 09:35:56 3 100 2
5 09:37:17 4 100 2
6 09:37:21 5 200 2
7 09:37:28 6 100 2
8 09:37:28 6 200 3
9 09:37:35 7 100 3
10 09:37:51 8 200 3
11 09:42:11 9 500 4
12 09:42:11 9 100 5
13 10:00:31 10 100 5
基本上,它是计算累积的总量和每次突破500时的分箱。因此,bin 1为100 + 200 + 200,音量在09:35:56分成200/100并插入一个新行,bin计数器递增。
对于基础R来说,这是相对简单的,但我想知道dplyr是否有更优雅,更有希望更快的方式。
干杯
更新
谢谢@Frank和@AntoniosK。
为了解决您的问题,音量值的范围是从1到10k的所有正整数值。
我微观标记了这两种方法,而dplyr在一个类似于上面的约200k行的数据集上稍微快一点但没有多少。
真的很感激快速的回应和帮助
答案 0 :(得分:4)
不确定这是最好还是最快的方式,但对于那些Volume
值似乎很快。理念很简单。根据{{1}}值,您可以使用Volume
创建多行Time
和Price
。然后,每次有新的500批次时,让Volume = 1
添加数字和标记。使用这些标志来创建cumsum
值。
Bin
答案 1 :(得分:3)
这很难“直截了当”。
使用data.table,它仍然有很多行代码:
library(data.table)
setDT(DF)
DF[, c("cV","cVL") := shift(cumsum(Volume), 0:1, type="lag", fill=0) ]
DF[, end := ( cV %/% 500 ) - ( cV %% 500 == 0 ) ]
DF[, start := shift(end, type = "lag", fill = -1) + ( cVL %% 500 == 0 ) ]
badcols = c("Volume","cV","cVL","start","end")
DF[,{
V =
if (start==end) Volume
else c((start+1)*500-cVL, rep(500, max(end-start-2,0)), cV - end*500)
c(.SD[, !badcols, with=FALSE], list(Volume = V, Bin = 1+start:end))
}, by=.(r=seq(nrow(DF)))][,!"r",with=FALSE]
给出了
Time Price Volume Bin
1: 09:30:01 1 100 1
2: 09:30:29 2 200 1
3: 09:35:56 3 200 1
4: 09:35:56 3 100 2
5: 09:37:17 4 100 2
6: 09:37:21 5 200 2
7: 09:37:28 6 100 2
8: 09:37:28 6 200 3
9: 09:37:35 7 100 3
10: 09:37:51 8 200 3
11: 09:42:11 9 500 4
12: 09:42:11 9 100 5
13: 10:00:31 10 100 5
答案 2 :(得分:3)
以下是使用data.table
和滚动连接功能的一种方式:
require(data.table) # v1.9.6+
setDT(df)[, csum := cumsum(Volume)]
ans = rbind(df, df[.(csum=500 * seq_len(max(csum)%/% 500L)), roll=-Inf, on="csum"])
setorder(ans, Price, csum)
ans = ans[, `:=`(Volume = c(csum[1L], diff(csum)),
id = (csum-1L) %/% 500L + 1L,
csum = NULL)][Volume > 0L]
第一步添加一个新列,累计总和为Volume
。
第二步也许是最重要的一步。让我们看看第二部分。对于500
到max(csum)
的每个倍数,它会加到第一个值> = df$csum
上的500的倍数。这是一个滚动的NOCB连接(下一个观察向后移动)。有了这个,我们得到:
# Time Price Volume csum
# 1: 09:35:56 3 300 500
# 2: 09:37:28 6 300 1000
# 3: 09:37:51 8 200 1500
# 4: 09:42:11 9 600 2000
这些是需要添加到原始data.table的断点。这就是我们对rbind()
所做的事情。
然后,我们所做的就是按Price, csum
订购,生成返回Volume
列。从那里,可以使用id
列生成csum
列,如图所示。