我怎样才能避免为此使用 for 循环?或至少尽量减少它的使用(R)
How can i avoid using for loop for this? or atleast minimize the use of it (R)
我想根据 30 分钟的数据创建市场概况。而不是字母我想要一个价格的字母总和(例如:价格 2500.00 = 'abcdefg' 将改为 2500.00 = 7)
市场概况是纵轴显示价格,横轴显示时间的概念,每个字母表示 30 分钟的交易 activity
例如:
9:30 到 9:59 = 'a'
10:00 到 10:29 = 'b'
10:30 到 10:59 = 'c'
以此类推直到交易日结束,每30分钟发一个新字母
假设在 9:30 到 9:59 最高价为 2505,最低价为 2502 那么它将显示为
2505 = 一个
2504=一个
2503=一个
2502=一个
2501 =
2500 =
假设在 10:00 到 10:29 最高价是 2503,最低价是 2500 那么它将显示为
2505 = 一个
2504=一个
2503 = ab
2502 = ab
2501 = b
2500 = b
假设在 10:30 到 10:59 最高价为 2502,最低价为 2500 那么它将显示为
2505 = 一个
2504=一个
2503 = ab
2502 = abc
2501 = 公元前
2500 = 公元前
现在我想要的是每天每个价格的字母总和。
为此,我创建了一个包含 data.table 的列表,其中包含一天的 30m 条数据,因此每个 data.table 大约有 40 多行。
我已经创建了一个相应的列表,其中包含相应日期的 0.25 的低价到高价序列。
而代码所做的是查看每个 30m 柱数据(在 'es.d' 中)的最低价和最高价是否低于和高于从低到高的每个价格(在 'es.mp' 中)如果是这样,则意味着在
30m 的价格确实在那里交易,因此在 'es.mp'
中价格旁边的 tpo 列 +1
所以上面的字母示例看起来像
2505 = 1
2504 = 1
2503 = 2
2502 = 3
2501 = 2
2500 = 2
'es.d'是包含一天30m数据的列表
str(es.d)
List of 1291
$ 2016/7/18 :Classes ‘data.table’ and 'data.frame': 47 obs. of 12 variables:
..$ Date : chr [1:47] "2016-07-18 00:00:00" "2016-07-18 00:30:00" "2016-07-18 01:00:00" "2016-07-18 01:30:00" ...
..$ Open : num [1:47] 2156 2156 2156 2158 2156 ...
..$ High : num [1:47] 2157 2157 2158 2158 2158 ...
..$ Low : num [1:47] 2156 2156 2156 2156 2156 ...
..$ Last : num [1:47] 2156 2156 2158 2156 2158 ...
..$ Volume : num [1:47] 1827 1921 2856 3096 2883 ...
..$ # of Trades: num [1:47] 1017 834 1525 1759 1593 ...
..$ OHLC Avg : num [1:47] 2156 2156 2157 2157 2157 ...
..$ HLC Avg : num [1:47] 2156 2156 2157 2157 2157 ...
..$ HL Avg : num [1:47] 2156 2156 2157 2157 2157 ...
..$ Bid Volume : num [1:47] 1000 826 1083 1709 1508 ...
..$ Ask Volume : num [1:47] 827 1095 1773 1387 1375 ...
..- attr(*, ".internal.selfref")<externalptr>
'es.mp' 是包含当天最低价到最高价的相应列表,增量为 .25
str(es.mp)
List of 1291
$ 2016/7/18 :Classes ‘data.table’ and 'data.frame': 43 obs. of 2 variables:
..$ price: num [1:43] 2153 2153 2153 2154 2154 ...
..$ tpo : num [1:43] 0 0 0 0 0 0 0 0 0 0 ...
..- attr(*, ".internal.selfref")=<externalptr>
并且只是为两个列表添加,data.table 每个元素中的行数不一定相同
这是代码,它有 3 个 for 循环,如果你愿意,它会花费太长时间或永远
for(i in 1:length(es.d)){
for(j in 1:nrow(es.d[[i]])){
for(k in 1:nrow(es.mp[[i]])){
es.mp[[i]] = es.mp[[i]][k,tpo := nrow(es.d[[i]][Low<=es.mp[[i]][k,price] & High>=es.mp[[i]][k,price]])]}}}
听起来您正在寻找一个频率 table 显示有多少个 30m 周期跨越不同的价格点。这是一个快速 dplyr/tidyr
方法。这里的关键是你设置循环的方式是高度嵌套的,它没有利用 R 的速度优势进行“矢量化”计算:https://www.noamross.net/archives/2014-04-16-vectorization-in-r-why/ 一个矢量化的答案依赖于基础 R 或 data.table 或(正如我在下面所做的那样)tidyverse 语法将比嵌套循环快得多。
首先我做了一些假数据,在这个例子中是 30 天:
library(dplyr); library(tidyr); library(ggplot2)
set.seed(42)
days = 30
fake_data <- tibble(Date = as.POSIXct("2016-07-18 00:00:00") +
1800 * (1:(48*days) - 1),
Low = runif(48 * days, 2000, 2200),
High = Low + runif(48 * days, 200, 300),
period_letter = rep(c(letters, LETTERS[1:22]), days))
这是它的样子:
ggplot(fake_data, aes(Date, Low, xend = Date, yend = High)) + geom_segment()
每个 0.25 价格水平被突破的频率是多少?在这里,我制作了一个价格水平向量,然后将其与假数据交叉,并计算每个价格区间被交叉的次数。在这种情况下,30 天的 3000 万个周期 = 1,440 个周期,乘以大约 2000 个价格区间 = 280 万行,这是一个非常易于管理的大小,可以在 <1 秒内计算。
price_bucket = seq(from = floor(min(fake_data$Low)/0.25)*0.25,
to = ceiling(max(fake_data$High)/0.25)*0.25,
by = 0.25)
crossing(fake_data, price_buckets) %>%
filter(Low <= price_buckets, High >= price_buckets) %>%
count(price_buckets) %>%
ggplot(aes(price_buckets, n)) +
geom_col()
它会越来越慢,在我的情况下,大约 10 秒,持续 1000 天。我认为转换为 data.table 语法会更快,但我还不太了解如何做到最好。
听取 Jon Spring 的建议,以下是我完全避免 for 循环的方法。我仍然认为它可以更快,但目前效果还不错。
这是代码
library(data.table); library(dplyr); library(tidyr)
mp = function(x,y){
tpo = data.table(crossing(x, y) %>%
filter(Low <= y, High >= y) %>%
count(y))
setnames(tpo,c('y','n'),c('price','tpo'))}
es.mp = lapply(es.d,function(x) mp(x[,.(Low,High)],seq(min(x[,Low],na.rm=T),max(x[,High],na.rm=T),.25)))
我想根据 30 分钟的数据创建市场概况。而不是字母我想要一个价格的字母总和(例如:价格 2500.00 = 'abcdefg' 将改为 2500.00 = 7)
市场概况是纵轴显示价格,横轴显示时间的概念,每个字母表示 30 分钟的交易 activity
例如:
9:30 到 9:59 = 'a'
10:00 到 10:29 = 'b'
10:30 到 10:59 = 'c'
以此类推直到交易日结束,每30分钟发一个新字母
假设在 9:30 到 9:59 最高价为 2505,最低价为 2502 那么它将显示为
2505 = 一个
2504=一个
2503=一个
2502=一个
2501 =
2500 =
假设在 10:00 到 10:29 最高价是 2503,最低价是 2500 那么它将显示为
2505 = 一个
2504=一个
2503 = ab
2502 = ab
2501 = b
2500 = b
假设在 10:30 到 10:59 最高价为 2502,最低价为 2500 那么它将显示为
2505 = 一个
2504=一个
2503 = ab
2502 = abc
2501 = 公元前
2500 = 公元前
现在我想要的是每天每个价格的字母总和。 为此,我创建了一个包含 data.table 的列表,其中包含一天的 30m 条数据,因此每个 data.table 大约有 40 多行。 我已经创建了一个相应的列表,其中包含相应日期的 0.25 的低价到高价序列。
而代码所做的是查看每个 30m 柱数据(在 'es.d' 中)的最低价和最高价是否低于和高于从低到高的每个价格(在 'es.mp' 中)如果是这样,则意味着在 30m 的价格确实在那里交易,因此在 'es.mp'
中价格旁边的 tpo 列 +1所以上面的字母示例看起来像
2505 = 1
2504 = 1
2503 = 2
2502 = 3
2501 = 2
2500 = 2
'es.d'是包含一天30m数据的列表
str(es.d)
List of 1291
$ 2016/7/18 :Classes ‘data.table’ and 'data.frame': 47 obs. of 12 variables:
..$ Date : chr [1:47] "2016-07-18 00:00:00" "2016-07-18 00:30:00" "2016-07-18 01:00:00" "2016-07-18 01:30:00" ...
..$ Open : num [1:47] 2156 2156 2156 2158 2156 ...
..$ High : num [1:47] 2157 2157 2158 2158 2158 ...
..$ Low : num [1:47] 2156 2156 2156 2156 2156 ...
..$ Last : num [1:47] 2156 2156 2158 2156 2158 ...
..$ Volume : num [1:47] 1827 1921 2856 3096 2883 ...
..$ # of Trades: num [1:47] 1017 834 1525 1759 1593 ...
..$ OHLC Avg : num [1:47] 2156 2156 2157 2157 2157 ...
..$ HLC Avg : num [1:47] 2156 2156 2157 2157 2157 ...
..$ HL Avg : num [1:47] 2156 2156 2157 2157 2157 ...
..$ Bid Volume : num [1:47] 1000 826 1083 1709 1508 ...
..$ Ask Volume : num [1:47] 827 1095 1773 1387 1375 ...
..- attr(*, ".internal.selfref")<externalptr>
'es.mp' 是包含当天最低价到最高价的相应列表,增量为 .25
str(es.mp)
List of 1291
$ 2016/7/18 :Classes ‘data.table’ and 'data.frame': 43 obs. of 2 variables:
..$ price: num [1:43] 2153 2153 2153 2154 2154 ...
..$ tpo : num [1:43] 0 0 0 0 0 0 0 0 0 0 ...
..- attr(*, ".internal.selfref")=<externalptr>
并且只是为两个列表添加,data.table 每个元素中的行数不一定相同
这是代码,它有 3 个 for 循环,如果你愿意,它会花费太长时间或永远
for(i in 1:length(es.d)){
for(j in 1:nrow(es.d[[i]])){
for(k in 1:nrow(es.mp[[i]])){
es.mp[[i]] = es.mp[[i]][k,tpo := nrow(es.d[[i]][Low<=es.mp[[i]][k,price] & High>=es.mp[[i]][k,price]])]}}}
听起来您正在寻找一个频率 table 显示有多少个 30m 周期跨越不同的价格点。这是一个快速 dplyr/tidyr
方法。这里的关键是你设置循环的方式是高度嵌套的,它没有利用 R 的速度优势进行“矢量化”计算:https://www.noamross.net/archives/2014-04-16-vectorization-in-r-why/ 一个矢量化的答案依赖于基础 R 或 data.table 或(正如我在下面所做的那样)tidyverse 语法将比嵌套循环快得多。
首先我做了一些假数据,在这个例子中是 30 天:
library(dplyr); library(tidyr); library(ggplot2)
set.seed(42)
days = 30
fake_data <- tibble(Date = as.POSIXct("2016-07-18 00:00:00") +
1800 * (1:(48*days) - 1),
Low = runif(48 * days, 2000, 2200),
High = Low + runif(48 * days, 200, 300),
period_letter = rep(c(letters, LETTERS[1:22]), days))
这是它的样子:
ggplot(fake_data, aes(Date, Low, xend = Date, yend = High)) + geom_segment()
每个 0.25 价格水平被突破的频率是多少?在这里,我制作了一个价格水平向量,然后将其与假数据交叉,并计算每个价格区间被交叉的次数。在这种情况下,30 天的 3000 万个周期 = 1,440 个周期,乘以大约 2000 个价格区间 = 280 万行,这是一个非常易于管理的大小,可以在 <1 秒内计算。
price_bucket = seq(from = floor(min(fake_data$Low)/0.25)*0.25,
to = ceiling(max(fake_data$High)/0.25)*0.25,
by = 0.25)
crossing(fake_data, price_buckets) %>%
filter(Low <= price_buckets, High >= price_buckets) %>%
count(price_buckets) %>%
ggplot(aes(price_buckets, n)) +
geom_col()
它会越来越慢,在我的情况下,大约 10 秒,持续 1000 天。我认为转换为 data.table 语法会更快,但我还不太了解如何做到最好。
听取 Jon Spring 的建议,以下是我完全避免 for 循环的方法。我仍然认为它可以更快,但目前效果还不错。
这是代码
library(data.table); library(dplyr); library(tidyr)
mp = function(x,y){
tpo = data.table(crossing(x, y) %>%
filter(Low <= y, High >= y) %>%
count(y))
setnames(tpo,c('y','n'),c('price','tpo'))}
es.mp = lapply(es.d,function(x) mp(x[,.(Low,High)],seq(min(x[,Low],na.rm=T),max(x[,High],na.rm=T),.25)))