65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (5投票s)

2012 年 5 月 8 日

CPOL

3分钟阅读

viewsIcon

57511

本文探讨了使用 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: Cronos
库 2: MathNet

请查阅这些库的文档以获取更多信息。 当然,线性代数和优化方法的可扩展性是基石,也是其他文章的主题。 我在图 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.LockedParameterState.FreeParameterState.Consequential。 锁定的参数在优化方法中保持其当前值,自由参数被优化,结果参数被计算为其他参数和数据的函数。 有关更多信息,请参见 Cronos 上的库。

图 2. 最大似然方法的代码清单
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 上。
© . All rights reserved.