Performance 计算移动平均线最有效的数据结构是什么?
在股票市场上工作时,需要计算包括28天平均值、14天平均值等的计算指标 此外,每天平均需要更新,以包括最近一天的收盘/高/低/成交量 现在,通常需要循环数组以查找总和、平均值、最大值和最小值 我认为队列(以动态数组、链表或任何你能想到的形式)似乎是基于FIFO方法的最佳数据结构 问题:Performance 计算移动平均线最有效的数据结构是什么?,performance,perl,data-structures,quantitative-finance,Performance,Perl,Data Structures,Quantitative Finance,在股票市场上工作时,需要计算包括28天平均值、14天平均值等的计算指标 此外,每天平均需要更新,以包括最近一天的收盘/高/低/成交量 现在,通常需要循环数组以查找总和、平均值、最大值和最小值 我认为队列(以动态数组、链表或任何你能想到的形式)似乎是基于FIFO方法的最佳数据结构 问题: 与哈希相比,队列的效率和可伸缩性如何 当运行Perl脚本时,队列将不在内存中,因此必须进行初始化和处理(从CSV文件初始化的值),我知道这是非常不相关的,但是对于每天执行的Perl脚本,哪种数据结构最适合使用 我
我只想使用一个简单的
%hash
,其中键是时间戳的一些字符串化或数字化表示,值是与该时间序列项关联的数据。您可以对散列的键进行排序,例如
#numeric
@srtdKeys = sort{$a<=>$b}(keys(%hash));
循环最后28或14等。然后从散列中检索值。此处信息不足。您是否在处理整整一天的报价,以获得每日的高/低/低报价 你是在每个仪器的基础上计算平均值吗 对于任何移动平均线,您只需使用组成平均线总和的值列表。当一个新值被添加时,一个值会下降并重新计算
因此,如果您在运行时使用仪器并进行计算,则会出现一系列列表。如果您在每次运行时都要从头开始重新构建数据,或许您应该仔细查看 很遗憾你把这个当成CSV。通过访问数据库服务器,您可以通过几次SQL查询获得此信息。使用此功能,您可以从更大的“数组”(1D矩阵)中选取一个片段,然后对该片段进行统计,然后选取另一个片段并重复。PDL有许多内置的统计功能,如果这还不够,还有附加功能
对于Perl,PDL就像MatLab或NumPy(我们认为更好!)。它针对数值阵列的“循环”进行了高度优化。我把“循环”放在引号里,因为这些循环是在C级实现的(听起来很快吧?)。看一眼 什么是最有效的取决于
- 散列是无序的。他们可以通过字符串键在几乎恒定的时间内查找值。查找在计算上非常昂贵,并且至少比数组查找慢一个数量级。散列的性能取决于“bucket”的数量和键的数量。但是,哈希查找要比在数组中循环查找所有非平凡情况下的元素更快。哈希比数组需要更多的空间
- Perl中的数组既有数组(随机访问)的特性,也有双链表(通过推、弹出、移位、取消移位)的特性。它们易于使用,而且速度足够快。如果要添加/删除多个元件,请使用切片或
是拼接功能<代码>拼接
的推广<代码>取消移位,并且比循环更快推送
- 字符串可用于存储整数数组。这是非常有效的,但也非常有限(仅INT)
使用字符串具有数组(随机访问)和单链表的特性(使用
进行追加很简单)。其他操作也相当快(=
有很多用途)substr
List::Util
和List::MoreUtils
中的高效函数,这些函数提供诸如sum
、average
、max
和min
(用C编写以提高速度)等函数
如果要构建值列表,并且只需要固定数量,请在添加新元素时执行以下操作:
push @array, $new_value;
shift @array if @array > $max_length; # keep constant length
这是节省空间的,但可能比简单地创建列表和执行
splice @array, 0, -$max_length; # remove all but $max_length last elems
要仅访问数组的特定部分(而不分配新变量),请使用切片:
use List::Util qw/sum/;
my $last_24_sum = sum @array[-24 .. $#$array]; sum the last 24 elems
如果您想使用哈希,但在编译时知道所有可能的字段,那么可以为字段定义常量名称,并改用数组。所以不要这样做
my $hashref = { foo => $x, bar => $y }; # requires a lot of space
$hashref->{foo}; # slooow
但是
use constant {
EL_FOO => 0, # make sure the integer range is continouus
EL_BAR => 1, # Perl doesn't have native enums
};
my $arrayref = [$x, $y];
$arrayref->[EL_FOO]; # faster!
相反
在处理深度嵌套的数据时,有时缓存嵌套的引用而不是每次访问时重新计算它们是值得的:
# disputable
for my $i (...) {
for my $j (...)
do_something_with $x->[$i][$j][$_] for 1 .. 1e3;
}
}
# possibly better
for my $i (...) {
for my $j (...) {
my $aref = $x->[$i][$j];
do_something_with $aref->[$_] for 1 .. 1e3;
}
}
如果你每天计算一次这些东西。。。使用最简单的数据结构进行编码!计算真的要花这么多时间吗?如果是,继续阅读 总和和平均数可能更容易。如果您添加的是整数,则可以使用FIFO并将总和保留在变量中。无论何时插入或删除元素,都要相应地更新总和(加法或减法) 如果添加浮点值,则上述方法可能会导致累积错误。如果数值大小非常不同和/或序列非常长,则可能发生这种情况。在这种情况下,您需要更复杂的东西(见下文) 对于max和min,最有效的数据结构是。请注意,您可以将它们嵌入到数组中。您需要将它们与FIFO队列的元素交叉引用,以便立即找到每次都必须删除的元素 最普遍的解决方案是扩充自平衡树。Cormen、Leiserson、Rivest和Stein在“算法简介”第14章中解释了增强数据结构。基本上,树将在每个节点中包含数据序列的一个元素。每个节点还包含i的和、最小值和最大值
use constant {
EL_FOO => 0, # make sure the integer range is continouus
EL_BAR => 1, # Perl doesn't have native enums
};
my $arrayref = [$x, $y];
$arrayref->[EL_FOO]; # faster!
# disputable
for my $i (...) {
for my $j (...)
do_something_with $x->[$i][$j][$_] for 1 .. 1e3;
}
}
# possibly better
for my $i (...) {
for my $j (...) {
my $aref = $x->[$i][$j];
do_something_with $aref->[$_] for 1 .. 1e3;
}
}