C#.NET 中的时间序列分析,第一部分





5.00/5 (5投票s)
本文探讨了使用 ABMath 和 MathNet .NET 包进行时间序列分析的方法。
引言
现在,我在 TCW 的公司专注于开发用于神经科学研究的中间件应用程序的 .NET 语言线性及非线性时间序列应用程序。 具体来说,我正在构建 R 统计和 MATLAB 语言的混合应用程序,用于原型设计,然后转换为 C#.NET 和/或 C++.NET,以分析和预测来自 BCI 游戏应用程序的 fMRI/EEG 数据。
这是由五部分组成的系列文章的第一篇,该系列文章探讨了使用开源库构建基于 .NET 的时间序列应用程序,这些应用程序可用于神经科学研究以及商品/股票价格预测。 目标是提供开源非线性时间序列算法作为统计引擎的一部分,即 TIME JAQUAR,用于时域和频域,可以在多 CPU/多 GPU 平台上运行,以处理来自 BCI 设备的实时建模和预测。 本系列文章中的所有代码和版本都可以在 CodePlex 上的 modelmaker3.codeplex.com 找到。
因为网络上有许多关于时间序列分析的优秀教程以及我所写的内容,所以我在这里不再重复。
背景
有几个好的库可以作为命名空间和原型模板,以帮助在 .NET 中进行线性及非线性时间序列应用程序的原型设计。 以下是我的一些应用程序中使用的几个库
请查阅这些库的文档以获取更多信息。 当然,线性代数和优化方法的可扩展性是基石,也是其他文章的主题。 我在图 1 中提供了基础知识,以说明这两个库的一些特性,并将代码发布在 CodePlex 上,以便您可以关注该项目。
目前,我也正在修改这些库以提高 GPU 性能。
使用代码
以下步骤是要执行的用于估计的方法步骤 1: 指定 ARMA 模型的参数
步骤 2: 生成模拟数据
步骤 3: 使用最大似然估计 (MLE) 等估计方法拟合模型
步骤 4: 获取模型数据、预测和残差输出
图 1. 步骤 1-4 的代码清单
using ABMath.ModelFramework.Models;
using ABMath.ModelFramework.Data;
using MathNet.Numerics.Distributions;
using MathNet.Numerics.RandomSources;
using MathNet.Numerics;
namespace TCW_ModelMaker3
{
class Program
{
static void Main(string[] args)
{
runARMATest();
}
public static void ConsoleWrite()
{
Console.WriteLine("Welcome to ModelMaker 3");
Console.ReadKey();
}
public static void runARMATest()
{
//Specify the AR and MA paramaters
ARMAModel model1 = new ARMAModel(4, 3);
ARMAModel model2 = new ARMAModel(0, 1);
//Select an random distribution for the data
var sd = new StandardDistribution();
//Make new time series variable
TimeSeries ts1 = new TimeSeries();
var dt = new DateTime(2001, 1, 1);
var normalSim = new StandardDistribution();
var current = new DateTime(2001, 1, 1);
//Create the data
for (int t = 0; t < 100; ++t)
{
double s1 = normalSim.NextDouble();
ts1.Add(current, s1, false);
current = new DateTime(current.AddDays(1).Ticks);
}
model1.SetInput(0, ts1, null);
//Maximum Likelihood Estimation
model1.FitByMLE(10, 10, 10,null);
//Compute the residuals
model1.ComputeResidualsAndOutputs();
//Get the predicted values
var preds = model1.GetOutput(3) as TimeSeries;
var predName = model1.GetOutputName(3);
//Write the model description with parameter values
Console.WriteLine(model1.Description);
Console.ReadKey();
}
}
}
上面最有趣的方法是 FitByMLE
方法。 此函数使用 Halton 序列从参数空间中采样,并通过优化对数似然来获得最佳模型。 参数值有三种状态:ParameterState.Locked
、ParameterState.Free
或 ParameterState.Consequential
。 锁定的参数在优化方法中保持其当前值,自由参数被优化,结果参数被计算为其他参数和数据的函数。 有关更多信息,请参见 Cronos 上的库。
public virtual void FitByMLE(int numIterationsLDS, int numIterationsOpt,
double consistencyPenalty,
Optimizer.OptimizationCallback optCallback)
{
thisAsMLEEstimable = this as IMLEEstimable;
if (thisAsMLEEstimable == null)
throw new ApplicationException("MLE not supported for this model.");
int optDimension = NumParametersOfType(ParameterState.Free);
int numConsequential = NumParametersOfType(ParameterState.Consequential);
int numIterations = numIterationsLDS + numIterationsOpt;
var trialParameterList = new Vector[numIterationsLDS];
var trialCubeList = new Vector[numIterationsLDS];
var hsequence = new HaltonSequence(optDimension);
for (int i = 0; i < numIterationsLDS; ++i)
{
Vector smallCube = hsequence.GetNext();
Vector cube = CubeInsert(smallCube);
trialParameterList[i] = thisAsMLEEstimable.CubeToParameter(cube);
trialCubeList[i] = cube;
}
var logLikes = new double[numIterationsLDS];
for (int i = 0; i < numIterationsLDS; ++i)
{
Vector tparms = trialParameterList[i];
if (numConsequential > 0)
{
tparms = ComputeConsequentialParameters(tparms);
trialParameterList[i] = tparms;
}
double ll = LogLikelihood(tparms, consistencyPenalty);
logLikes[i] = ll;
if (optCallback != null)
lock (logLikes)
optCallback(tparms, ll, i*100/numIterations, false);
}
// Step 1: Just take the best value.
Array.Sort(logLikes, trialParameterList);
Parameters = trialParameterList[numIterationsLDS - 1];
// Step 2: Take some of the top values and use them to create a simplex, then optimize
// further in natural parameter space with the Nelder Mead algorithm.
// Here we optimize in cube space, reflecting the cube when necessary to make parameters valid.
var simplex = new List<Vector>();
for (int i = 0; i <= optDimension; ++i)
simplex.Add(FreeParameters(thisAsMLEEstimable.ParameterToCube(
trialParameterList[numIterationsLDS - 1 - i])));
var nmOptimizer = new NelderMead {Callback = optCallback, StartIteration = numIterationsLDS};
currentPenalty = consistencyPenalty;
nmOptimizer.Minimize(NegativeLogLikelihood, simplex, numIterationsOpt);
Parameters = ComputeConsequentialParameters(
thisAsMLEEstimable.CubeToParameter(CubeFix(CubeInsert(nmOptimizer.ArgMin))));
ComputeResidualsAndOutputs();
}
当然,这是基于 Nelder Mead 的主要算法,也是未来文章的主题。 但是,这应该足以让您入门。
关注点
可以使用代码片段编辑器将图 1 中的代码片段以代码片段的形式放入 Visual Studio 2010 中。 请访问 Workshop 观看相关视频。
历史
- 2012 年 5 月 8 日:代码已放置在 CodePlex 上。