diff --git a/.gitignore b/.gitignore index e15812f..3e65f9d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ paper_tests/mv_probabilistic_forecast/ docs/build longhorizon/ -test.jl \ No newline at end of file +test.jl +test_ms.jl \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..6f3a291 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 5501 +} \ No newline at end of file diff --git a/Project.toml b/Project.toml index 992ffe7..85e46bf 100644 --- a/Project.toml +++ b/Project.toml @@ -11,7 +11,13 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +[weakdeps] +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" + +[extensions] +PlotsExt = "Plots" + [compat] -GLMNet = "0.5.0, 0.5.1, 0.5.2, 0.6.0, 0.6.1, 0.6.2, 0.6.3, 0.7.0, 0.7.1, 0.7.2, 0.7.3, 0.7.4" Distributions = "0.16, 0.17, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25" +GLMNet = "0.5.0, 0.5.1, 0.5.2, 0.6.0, 0.6.1, 0.6.2, 0.6.3, 0.7.0, 0.7.1, 0.7.2, 0.7.3, 0.7.4" julia = "1" diff --git a/README.md b/README.md index 06b902e..8388d9b 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ Current features include: Quick example of fit and forecast for the air passengers time-series. ```julia +using StateSpaceLearning using CSV using DataFrames using Plots @@ -69,8 +70,7 @@ fit!(model) prediction_log = StateSpaceLearning.forecast(model, steps_ahead) # arguments are the output of the fitted model and number of steps ahead the user wants to forecast prediction = exp.(prediction_log) -plot(airp.passengers, w=2 , color = "Black", lab = "Historical", legend = :outerbottom) -plot!(vcat(ones(length(log_air_passengers)).*NaN, prediction), lab = "Forecast", w=2, color = "blue") +plot_point_forecast(airp.passengers, prediction) ``` ![quick_example_airp](./docs/src/assets/quick_example_airp.PNG) @@ -78,11 +78,7 @@ plot!(vcat(ones(length(log_air_passengers)).*NaN, prediction), lab = "Forecast", N_scenarios = 1000 simulation = StateSpaceLearning.simulate(model, steps_ahead, N_scenarios) # arguments are the output of the fitted model, number of steps ahead the user wants to forecast and number of scenario paths -plot(airp.passengers, w=2 , color = "Black", lab = "Historical", legend = :outerbottom) -for s in 1:N_scenarios-1 - plot!(vcat(ones(length(log_air_passengers)).*NaN, exp.(simulation[:, s])), lab = "", α = 0.1 , color = "red") -end -plot!(vcat(ones(length(log_air_passengers)).*NaN, exp.(simulation[:, N_scenarios])), lab = "Scenarios Paths", α = 0.1 , color = "red") +plot_scenarios(airp.passengers, exp.(simulation)) ``` ![airp_sim](./docs/src/assets/airp_sim.svg) @@ -103,7 +99,7 @@ fit!(model) level = model.output.components["μ1"]["Values"] + model.output.components["ξ"]["Values"] slope = model.output.components["ν1"]["Values"] + model.output.components["ζ"]["Values"] -seasonal = model.output.components["γ1"]["Values"] + model.output.components["ω"]["Values"] +seasonal = model.output.components["γ1_12"]["Values"] + model.output.components["ω_12"]["Values"] trend = level + slope plot(trend, w=2 , color = "Black", lab = "Trend Component", legend = :outerbottom) @@ -216,7 +212,7 @@ ss_model = BasicStructural(log_air_passengers, 12) set_initial_hyperparameters!(ss_model, Dict("sigma2_ε" => residuals_variances["ε"], "sigma2_ξ" =>residuals_variances["ξ"], "sigma2_ζ" =>residuals_variances["ζ"], - "sigma2_ω" =>residuals_variances["ω"])) + "sigma2_ω" =>residuals_variances["ω_12"])) StateSpaceModels.fit!(ss_model) ``` diff --git a/datasets/artificial_solars.csv b/datasets/artificial_solars.csv new file mode 100644 index 0000000..d6c0ca0 --- /dev/null +++ b/datasets/artificial_solars.csv @@ -0,0 +1,721 @@ +y1,y2,y3 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.349879560056509,0.3650930570490589,3.023620077924308 +3.8535218135453837,0.8568894883762752,2.8285624382289107 +4.311774824942485,2.1198375388098576,3.454618858588569 +14.618282234345694,10.875801700975845,11.642201507214498 +15.150211735011148,7.963314216945096,13.678839341828832 +13.723355724850835,9.124574651316202,12.573034487568913 +16.720153772585483,11.038817554302877,12.070865997693488 +15.598538045527098,10.92651780732075,11.750452346948645 +15.369544189015942,7.341199364173555,11.845592352767385 +15.139484854729481,8.423656020640786,10.711195964263077 +14.640160610276373,10.189289981804299,14.928664597678344 +14.758142126504241,9.555606142842315,13.976499624199414 +13.276876322428262,10.083272044666492,10.793276478520074 +4.140891996372935,3.011189535834439,3.757399393958403 +4.192260576572667,2.0172475902809097,2.630788775539118 +4.422332648603,0.7572607316612189,3.0225142030645897 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.206531435212821,1.3955807712715949,1.7583626940780346 +4.443059514179521,2.2804898312669883,3.233067780391363 +3.7916686481977226,3.849765564743531,2.484521654849829 +14.84152214399672,9.224132179746876,10.525101546003071 +15.787951223452092,11.272537708723721,12.655753355474404 +14.405529873038072,8.153741976697448,12.411509247572182 +13.317081968848683,7.505791386540272,11.44232926893668 +13.55982315655119,10.594719611763159,10.502986713158148 +15.018454974426456,10.569510380713862,11.867906514619989 +16.16326171500944,9.748807017230288,11.251179046121637 +13.978860839607286,10.137019271034974,10.988324333334148 +14.554677735576659,13.735456295723033,11.99369634067523 +16.2252151480622,10.277719725510716,12.445982166739483 +3.4789168328260263,2.235404250086501,1.7110057998741215 +3.992572316101161,1.6872417030325637,3.591041334276717 +3.337645087148916,1.8183617776743497,3.6829577313300694 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.9847699828701373,1.4272424067700182,2.903383701725442 +4.392599131742787,1.6259193091213937,2.6868702032948315 +4.1256667993980045,1.8047517412355387,4.287741872110603 +16.412316423924022,9.423265814076771,12.853187269504128 +12.663978107735279,9.394025028452171,8.950675627028655 +15.90583793780859,8.563083819364955,11.330197099910995 +15.805531258471055,11.083705742067943,13.609412451665873 +14.73753787204669,8.68528965031098,12.49666380699091 +15.070610045453098,10.40676306178673,12.579021986903157 +16.79321056500526,9.375984070576605,11.245597983903378 +15.776026291412023,7.905483510110344,11.98047178652607 +13.357319373525932,9.505726010358208,11.284646626057679 +16.653062107592813,10.993581819512515,13.414587771257388 +3.6309503166205874,2.5265805867865283,3.326300067407764 +3.9719245785881134,2.9461302243285017,2.7896505521796335 +3.8056119234995736,0.6425984625940246,2.402984903657847 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.244735695353507,2.9541675426140457,2.8009931040239757 +3.576249216755485,1.229047876019043,2.292178749768177 +4.075710667198786,2.7003295229958555,3.3899577544562387 +13.364358076447616,7.368468436575003,13.02578678650458 +14.215153533659183,11.213036533252838,12.87269971015042 +13.907391332049912,9.838333605651538,11.511148673794311 +13.687063078055338,9.693454582784225,13.489030069194701 +15.74186051230212,8.213147377817847,11.196623753890426 +15.98027187613109,9.671660496140017,10.5729668355773 +15.334983462986758,11.314548124672998,12.204254724071586 +12.698673678807115,9.122034439124052,12.28102104713185 +14.612958853419093,10.21753214455107,11.871605883069275 +14.486762698191175,9.526960274486909,13.92726352957261 +4.325937212439281,1.7645416932102944,3.4131915600386415 +3.2853352025664533,2.2219616754444727,3.0436180150920245 +4.015245419422569,1.2642179559733822,2.542735874757526 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.5023585225440352,1.4086944569053832,2.5840093575090135 +3.8502574283501816,2.085036566891634,3.5172880050943394 +4.501178545020185,2.3044828087470255,3.126743211334812 +15.4077661673822,9.982960574827489,12.210933777759672 +13.889895041295167,9.869890846292781,11.641701053165802 +13.583162731154342,9.904682330204333,12.597279217967001 +14.699512237021432,9.496256094584762,11.369699477505813 +14.118344656831933,11.981712280734365,12.265279224907308 +14.486070541795478,10.571747763596015,11.596947814550424 +15.811729911796128,11.123383091467556,10.633678583728381 +13.178830132123018,9.367487892452653,11.370851336253265 +14.395660964558152,9.272124614851204,10.894895507187188 +16.017762767944884,10.605831445144982,12.373437489916737 +4.243820698388737,1.8258732210957749,2.7807759734680215 +3.833179106005972,2.4535352807558573,2.6207868381220893 +2.940138725609043,2.649961164133663,4.041045507147375 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.8937477387525545,1.792550812736869,2.618782427588757 +4.343980413940097,1.9645038214922517,1.8846582518469164 +3.98575074712879,2.2265219729254646,2.9721318697923644 +15.024047156497383,10.556487692171208,13.305394344896774 +15.944667617874092,10.230506674003063,12.370667621406044 +16.461415549627958,10.140486867854033,12.727266589242923 +14.753344793482654,9.261349640640978,12.177792324140347 +13.87694036327203,9.242992424979176,13.133889365007333 +14.775748929229664,10.428175558556452,12.22817819911133 +15.830541623880098,9.744933366628898,11.39847942781535 +16.28815868078636,9.85076593047856,13.816320388554818 +15.685867086248015,10.131298647663279,9.747740740329386 +15.777124664554405,9.95376526191774,11.941620137795066 +4.063359061660413,2.8010377265022335,2.5417747764263914 +4.366019420851442,2.0087813672837815,3.088127022173416 +4.620309588706219,2.391346082008109,2.7784837072952473 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.430857875511484,1.7568556844593683,2.932954838378018 +4.61111953859305,2.3154468950195537,3.3692428535406838 +4.207979780908232,1.8833746083848801,3.223078773496031 +15.456068227001392,10.962502588067522,11.448870834908812 +14.707630561805603,10.797393022748118,11.865226669827004 +14.994718792477707,9.472251282626521,12.972325800647809 +15.522971431993561,10.500423500137265,13.504536320967258 +15.044316249349738,9.463354918637311,11.92650237752098 +14.768028342659878,9.304430344990802,12.17658802883719 +14.171631820787669,9.529033576782396,10.333630854155723 +16.246128076984775,8.616894671007,12.85855611545992 +14.229542682648978,11.340728588639303,11.824251311032237 +13.427269636617437,10.162014159758614,10.844926474616038 +3.499094032991078,2.369809540971021,3.227400342334484 +4.367743273515437,3.371128568361291,3.0337071459243394 +3.8829554534706707,1.6135362966338673,3.1299424116695396 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.348302710767229,3.2308947933738668,1.8293165458025116 +3.9106130172345113,2.5066157104806983,3.4707455696861635 +4.572309190198401,2.8939217243000854,3.5889242512375836 +12.381102584378203,9.899385255452481,11.914594059130579 +13.854998778871579,10.25198359211229,12.207066958103853 +15.02346996522168,10.08633246849804,11.917141413851214 +15.100075132291446,9.448209538322658,10.983660548318865 +16.314271612645882,9.518156809093608,11.561228740275975 +15.250530736455024,9.158637570126062,13.018107042453007 +14.881253077627793,11.438502786547515,13.893844053013707 +15.167872490247452,10.443048934866404,11.094767363995281 +14.270401144231965,11.240730381970314,13.177614856275099 +15.011990770657079,9.043441558463737,12.43856045436121 +3.335382198915581,3.720783408141342,1.8093351890942244 +4.150336544156936,1.7513295281783132,3.301092358916702 +4.3092333117012345,2.3281674985008145,4.167138942883376 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.7763267853512135,1.1044801894359677,2.5953823827635185 +3.845970567385771,0.968127271734327,2.8379718281046915 +4.344948724825473,1.2578767353976827,2.306890429447739 +14.646843182918662,10.392754799815927,10.714398089682925 +17.099187954873912,7.5771835610931495,12.254495251826452 +14.987891838942666,10.054825530912158,9.840927433025147 +16.999697367797573,11.546527006296559,12.123488709924343 +16.281201985240504,10.860582396025354,12.23529178070615 +15.106099799476546,10.735411454224607,10.815693799610035 +13.379820929235994,10.432079413584123,13.043823479516064 +14.534234566477062,10.320119765571386,11.372447497323115 +15.899168636499097,8.815227232186686,12.676338622012533 +16.166700570063664,9.279775652740724,12.12540192586009 +3.5011513884666563,3.174034323730731,2.278146781812982 +3.8942340058050395,3.2478889909785913,2.8895042856210207 +5.0590697530105615,1.6318933811507779,1.822982029538691 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.380725466573027,2.3748071436624003,2.83880528879992 +4.162602488672278,2.736950342928399,2.5069020572093192 +3.9979949464008144,1.611822530917229,3.643160190842237 +16.230936729223497,11.153739157032327,11.379413451395651 +13.91771006122016,9.060994321116368,11.472528008024993 +15.590655804484685,10.485578837912216,12.142838637022045 +14.550374145868478,10.952712542474938,10.538219457976037 +16.241770442409585,7.597948759002711,10.710908285789737 +15.10044176437917,8.588929677931288,13.905959790937068 +11.886776079501093,9.75586325088217,13.718399588735794 +14.694503444651808,9.558268859060382,10.80829511626731 +15.419649864511944,7.492547369743192,10.841306536331519 +13.40518306539576,11.599426053124493,10.093480587394689 +3.5478177110839426,1.1607770301385418,4.003788937506066 +5.166813878698556,1.4994123525099141,2.989272362830536 +3.64145141335407,1.5510864502382882,2.7646661043434255 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.471576603481324,3.0844628216235983,3.593128658056928 +3.6676186516801517,2.734962453187844,2.671562958414409 +4.04966094629701,2.278061429865083,2.3221799925063484 +13.428109737698009,12.463940614732715,10.49125669460548 +14.453323138948981,9.63888571884461,11.657305441401572 +14.6911709563606,8.851634975932997,12.68007297231976 +15.2000235000845,9.706172436364701,13.169578990723183 +14.790842471697632,8.945102874282641,12.18505957175732 +15.560630772912539,10.189666432486817,13.203635286981378 +15.133153389303342,10.83366625007233,11.952225050993096 +15.407133219123816,11.133530487815579,10.850245415107754 +15.896164108076178,10.64916096053093,12.204139644131512 +13.595457102612382,7.6088764612818,10.941163794589421 +3.5220943489359073,2.2872647782110693,4.218875902422986 +5.04233617510738,3.0430347185993636,4.048574413924475 +4.139063726662635,2.15641602497768,3.458899230445543 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.0147975214071385,2.584507704395553,2.691083543152505 +4.610312470770154,2.539545693408826,2.397772224125576 +3.902389690851323,0.6421097329332557,3.381878054426745 +15.297486224405954,9.20284438057027,13.532599922744309 +14.873192090036214,8.698003395735924,11.828711079157623 +16.724063250092442,9.563492479288216,12.534538227344791 +16.01119225866384,8.18571110243782,13.458290493011372 +15.89640219242086,9.788823806553532,12.867667741298433 +15.470773210600354,9.597784505796458,12.103113585767007 +15.615987089917956,7.627323885242264,10.68983033841022 +15.632642776153915,10.424781935584209,13.711629363776085 +12.720126096749167,10.30721831773433,12.277646300616365 +15.382648108250892,9.546349272809987,11.30130372732267 +4.162471203931209,2.2730100450125788,2.7776710282431867 +4.884342690222756,3.270390800951625,3.9534971492455595 +4.929307512095162,2.8987625707097915,3.540494252193942 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.5306233921297716,2.5747916415377126,3.45032854089197 +5.349296333500361,1.0467043009054973,3.1980536703201365 +3.921334677948548,2.144727356759605,2.725384049397289 +15.825136541410664,9.842790400274726,12.96948748332643 +14.298530582181451,8.152962653048396,12.870921942133307 +16.02469392901207,11.675257481517756,11.761327739575842 +15.444136255682455,9.993411831218657,12.09849677838826 +15.786597986732582,9.514474456775035,12.71410145294977 +15.073227320250593,10.689626148338267,10.786052932427797 +16.130371651662887,9.832135020633645,13.617148996410773 +13.34758506407057,8.458315158931558,13.160967622753859 +15.194015166637637,8.504366884014141,10.98785625372368 +14.527125464617427,9.771814877511096,13.399099659775692 +4.391120618352721,2.0508455083054993,4.255457258020504 +2.8906801490199054,2.6388376850733004,2.858276557599494 +2.892669609642768,1.1958769314427302,2.84983056997411 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.743409835567075,2.9145315496055075,2.9353606361354787 +3.347071714789645,1.8328438717176923,3.924241759578723 +3.597651669680416,2.2935451492585845,2.562727137660362 +16.29448763706738,10.145033270990485,12.52807592470432 +14.232792203724726,12.011427477314182,11.718774691804112 +13.566371372252542,10.27926832415421,10.596479328345252 +15.148497845866995,10.994378949206602,11.048212795512809 +14.91424851824374,9.612526039207163,11.627519084348762 +15.322211616268426,9.839992761696289,12.93392197385053 +15.392499005265782,10.117105252748642,13.59998478722722 +14.838095442621729,8.62504090320437,10.808163820263799 +17.46161091163183,8.967005073098138,12.91544479158926 +14.724318160561614,9.462173624766764,10.457618571730476 +4.119866366024459,2.2527850255136865,2.360055499487934 +4.363309125799479,0.8597228868324384,3.2842658112634187 +3.7957721552861,2.0803000294145413,3.587792109668925 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.255654631030556,1.015662598503951,2.5779111126830756 +4.83359377378819,1.625867575569257,2.53929554910443 +4.008498833067411,1.3040017756771354,2.6152040418218223 +15.164040262489047,9.728119282033513,13.358657578856263 +15.292477254917952,10.059331318371257,13.632827629037832 +13.550507344386075,10.917619131883386,9.550782925538094 +16.030850487069294,11.138685690844135,9.9601875506799 +14.509243885689274,10.552390179701332,11.539764640067084 +14.86634342791043,10.11653722403454,10.691533283420876 +13.90259114310915,10.168394977040728,10.638271723417827 +13.787399847886432,10.39434354995102,11.941154937970394 +15.654290292757256,9.482616628053831,11.999634908405177 +14.973637089918455,10.530214717172614,11.344434987426363 +3.6022837177884957,2.4259393783230916,2.4648261321846427 +3.667506460671627,2.2646887784394925,2.7780711685560613 +4.889417857060966,1.9688329962243636,2.276871177062787 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.412144938031251,2.571602730739084,2.3728349317145923 +3.557206871715689,0.06258336822962861,2.896652371317224 +3.5011312577221485,1.3213449599265226,2.738245131764359 +16.98513934315606,7.202255543841634,12.698388128551402 +15.331289768260344,11.016184354233479,10.945400311980253 +16.488114829372922,9.836034498408901,10.689127407577486 +15.473354157092317,11.382694936967335,14.659663336465657 +13.560759577678352,11.643062136271258,12.634928899673628 +15.999521324264553,11.31197640835189,10.824719612448794 +14.291280973824401,9.477590825949012,11.016365675262087 +14.714612354042144,9.133059277674638,11.914388814972984 +13.833331226625674,8.841675106481079,13.110186415408112 +15.35232804558929,10.184435693368842,12.441508322625774 +3.105256682727618,0.9674163020715484,3.3782747996796565 +3.559984753005317,1.45840038632797,2.5766789152344574 +3.8692306395045417,3.8534983815315518,2.01732472589295 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.614455930979476,2.1563957208099334,1.5471334737699747 +4.895296335417692,0.9210481789784637,2.298786784060853 +4.371165918433896,2.673402623594628,3.2724884068990794 +14.487464966459202,9.570637743937016,11.168360263152518 +16.050494323306125,11.96878396319666,11.098445153693294 +14.642183145010858,8.976266916048985,12.105857187503021 +13.15434323908995,7.534689114985302,11.416199845615022 +15.595973727604415,11.025224749474035,10.153310696026514 +15.542398933581609,8.291200887620597,12.012599897933928 +15.663763699872316,9.216619978948394,11.900185553414989 +13.734022624065291,9.448691958208988,10.072590399360736 +14.95497641279255,10.055069437797894,15.253183792824418 +15.410666327834843,11.650582417358294,10.266970476288277 +3.8352640749056883,2.5048577613213387,2.9928903583937485 +3.556270889160746,1.372366074557525,2.9765705250998 +3.4301290456893523,1.2398413021630186,3.520267117986961 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.666075994322341,0.6857791780505135,3.4677414404853764 +3.860087793353132,2.6971805235923623,2.6874042671370804 +3.409694595409807,2.2037198847783364,2.079120781904585 +14.874132116641055,9.364797519630017,12.750642767623308 +16.153154380066514,9.210808010739248,9.166219746748093 +15.327575823098053,9.872685362573845,12.877029143399522 +14.138341018747683,12.272398764486471,12.612444416051424 +14.80101958725549,9.999154867943586,11.938044683587675 +15.649982383907505,11.061741704772516,14.532081788978637 +14.583794040249327,8.911830563019006,10.840020135842506 +13.64643857282716,10.396851543520599,10.413174421321614 +14.067722704779461,10.704958946621908,14.00996994904718 +14.18219920956032,9.70577374818629,13.662207110250975 +4.139049296268118,0.8136809342745625,2.6173935807530206 +2.8651105535666677,1.1390376813153524,2.635264085115016 +4.819410163476501,1.2506740827191476,3.61251162778318 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.74203055161596,0.44459982953704696,3.45935570420553 +3.7447610830438025,2.3736606614770714,2.690419965557201 +4.019558247959507,1.5219319113879815,3.5007640378904155 +14.335554409324963,10.855526828148427,10.16048602351929 +13.74839063688134,8.586732410453369,10.89254969455614 +14.528310063631395,9.618614088787966,13.164590053263796 +15.178108338525142,9.278001560427116,11.044519790729975 +14.496693411586172,11.63052447318741,12.880300901724187 +13.667694641175212,10.398500540325902,12.766651456461068 +14.530548179057552,10.976248334642476,9.895588760885307 +14.916059771745505,11.049075252236227,11.936555976190398 +14.02632321785984,10.541301020405681,12.807361220967406 +15.807664621238967,9.548075412431222,11.971990876654171 +3.721652508259602,3.053022745962101,2.3700752695188543 +5.048828958739822,2.930943435440698,3.1191342557665402 +3.2095507529504435,1.9966886707993288,2.499195471493935 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.572759990238106,2.013403002202903,2.3836586998213245 +3.7711497673976773,1.2289981660237248,2.5084017832168573 +3.627921793125723,1.0115343394848193,3.0992942318190546 +14.332042091440766,9.241643476556723,13.726442952368124 +15.26813726904337,8.58883057225916,12.247160652889784 +16.82577293265482,11.860732778382557,12.333352950212557 +14.279239892810796,7.8659189445765625,11.503146799746453 +15.219734212871426,7.776614206699197,12.764064350685327 +15.50619872644619,7.212948218127539,11.363718438493779 +15.098294215902326,11.360533779168275,13.555120026838107 +15.126607267463088,11.635600534036138,11.636561763670937 +15.80048808780022,10.58799743457937,12.517529151365984 +16.41029438656636,10.149156391631747,13.302202667671828 +3.8531215012857727,1.7581041008833753,4.1662765035057925 +3.8469255065699954,2.910027319502689,3.5881688655703585 +4.663468059731436,2.6163714240710303,4.365979495162673 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +2.98659576563062,1.8961841740329834,3.083705771691574 +3.495269644720728,1.8723551193356216,2.895381937393693 +4.4877419631626285,2.550987129542818,2.904132834388217 +15.114901943128778,10.22830585460259,13.662423890649611 +15.597574588545347,10.380905693982278,13.71779071885647 +15.29568070797905,9.98528646270851,11.145003561787638 +15.137818947899719,8.640100090787973,11.344879615091006 +15.612548244289176,10.742191452122823,11.834429729369207 +15.836466692510784,9.246570194062437,13.679671737638053 +16.011898373167718,11.014175860574124,12.46491715717879 +14.7303238167135,10.192878427676494,12.45442000860354 +14.830250684088787,7.690542969886964,11.319817055559602 +14.629325472099563,10.12250257264002,10.368077986159026 +4.117697032403664,2.091496521231004,3.4086639469368065 +3.9138578036130234,2.911001782991221,2.2988347266871867 +3.895651759787572,3.3546425947607728,2.515517840717051 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.463126258377457,0.9769229801084004,3.6512578571537815 +2.564760822894123,0.9343004400191017,3.339052343965176 +3.4764730653166045,2.014243510135608,3.1377322027555015 +17.51476557722074,12.213515156583467,13.809345054486483 +15.280418865600367,5.984574805130696,12.88876180268717 +13.943037288013874,10.124048199957185,9.588446096504086 +14.801920634745253,11.846545790795398,11.878839773736035 +14.588540185226972,10.106205115452525,12.886294484990215 +17.904138755441792,10.709680989026161,11.914957133785554 +14.711574062843454,8.457890098565898,12.553417356765527 +14.799503394415366,10.736598210675194,12.087311013050437 +13.869327353906332,8.94200691109809,12.634085477947783 +15.25364885154504,11.726821127441289,11.81462254642618 +4.3338212839736086,1.2184338472275804,2.4894322157653543 +4.593638455312248,2.0607194358312793,2.82059164963012 +4.822031137928828,1.7182405102906677,2.6542489007679806 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.7821736366212604,1.4101496765515555,3.335866618056252 +4.398203853272656,2.376202989258403,3.5461608838728518 +3.9112789354261444,2.590675992566783,1.8034988730870984 +16.133474317689252,8.112346790666614,11.676382951566332 +15.82088198195533,10.684215169543524,13.005583659779369 +15.519275102953612,11.080566893318732,12.445062937479399 +14.705281031244139,8.70423439775468,9.988035804646085 +15.702153965668753,10.625450111565382,12.077574296368752 +13.342597902376756,10.39661685158605,12.772970534043134 +14.882359546137913,11.381890054085739,13.009384298331423 +15.271478773783812,11.293221290230145,15.016070306969082 +14.67224036896178,10.739702403408678,11.038068139599131 +13.982976769467882,11.224940132881226,13.539333549855229 +4.287570002793068,1.199934999575814,3.448437062871844 +4.139694455284943,2.180902562168709,2.7716792324568575 +3.9694681254106645,2.53947156952989,3.1741431177018598 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.6923611943246324,2.0390522846234957,2.8743957511058866 +4.725575742641981,1.2844035155016584,1.8672484485808714 +3.7319354229940584,2.3060310544058344,2.4499804489776635 +15.49471382269156,7.1907414781574195,11.033761139564573 +13.553452247124657,12.00973782398149,12.75313853316796 +14.930162575567822,10.457658507925943,11.417131975198092 +13.580265803790425,9.3764061766282,9.92225095944314 +15.758603202544302,9.359887142632978,11.622254333637889 +14.731202848115855,10.544669442799943,11.365660571910947 +13.408842342418826,10.484838992377265,12.675672273735728 +15.47694316298109,12.190813182640444,13.593407945016253 +14.750747932165929,9.841299707529213,10.142220857977016 +15.445249389123635,9.690963890817997,10.545112603025057 +4.5512144766195854,2.589525395691119,4.2348657450078235 +4.45689865047636,1.38011864710659,2.375429873153904 +3.430333735251406,2.2852950706881736,2.884222855959719 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.111327243183592,2.340707341712816,2.958607184836212 +3.643916714178622,1.980818176360462,2.874098734049312 +3.799382238821259,1.948844520722079,3.293782086167564 +17.75395950396702,9.403218030394891,9.661381569363355 +15.674553311869243,11.036562278036605,10.446849114625062 +14.22183061865729,11.267816569122965,10.25262350801599 +15.188118150832299,8.865600042197327,12.412253733070724 +13.88435897816813,10.458895080782721,12.57448183708465 +13.511566735501212,9.860359045404728,9.283440764733541 +13.135797873425814,10.290852367222183,12.117488923372814 +14.886819823299561,9.967077669474403,12.824653621844247 +14.445391861794972,10.548661194907933,11.513577396790861 +15.700700072842015,11.510875893421716,11.270658860049442 +3.7826797593692465,2.2241881871748683,3.31901114005259 +3.8171551920392424,2.54995635106502,4.540242667652741 +4.3640850353329865,2.072424489376712,2.7419237131034215 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.656800257405892,3.495568572697806,2.6706859687594164 +3.8912688710386627,2.3524520919500773,2.5241571774581897 +3.9210312708509703,1.2132824972960103,3.0875759217458754 +14.376918890893617,10.102496976246806,12.900725854307854 +16.262472711910263,10.91455266257067,11.28619019713721 +12.308939140556518,9.88505169257316,11.777276881347904 +15.4864846436235,8.385761064205152,11.352495524385212 +14.263456347138213,8.154539759484498,10.808704626026097 +13.674912573345372,10.632653088574394,12.32731770477756 +14.01760403501305,7.991051786711774,13.827370325721422 +15.420656873475735,9.411096745127411,12.87249681377931 +14.786549327125565,10.426465366916139,11.807298871677842 +15.311327422406336,9.201815704555765,11.757241138976733 +4.120991063776892,1.395985927274555,3.067828867514675 +4.321900911771001,2.27429600094699,3.2008073423402346 +4.0288846996112,1.463144590137088,2.8250280552729876 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.900272237190029,1.6307384650208114,2.9927423347695155 +3.5856236712279665,3.1316102381482036,2.526306601608622 +3.489125197748964,1.2237290122884352,2.1549193265996727 +15.9109824610031,9.905700808412844,11.170462371584811 +13.294635811176791,9.863428692409343,12.26201035597221 +15.306112718885277,10.264014706128606,13.605488695113209 +14.219718681855642,7.756263309750538,11.243804448397565 +13.939064947282096,8.219138501136396,11.330259056245879 +14.52456448412311,7.833542477627527,11.918321287798834 +16.06795960504264,9.299052403286838,13.847659703968153 +16.221669892501957,10.179256721786789,12.305510201616379 +15.289650068709497,10.414928768496242,10.870713706644393 +13.59248944767552,10.041466930982759,14.528712099564258 +3.5041410073730717,0.7934335535979604,2.2260724250183923 +3.8268341132207735,1.2970979028447835,2.8666438742968654 +3.668386690432924,1.4223595780936973,3.2538945344656147 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +4.212268084674791,2.3765903093685443,3.5772941901157282 +4.447470869779648,2.514500410900322,2.753535918926288 +4.262589059072594,0.1959599222685133,2.688048133860244 +14.296759164551899,10.934901251280008,13.100882928053034 +16.204339959626207,13.303967221020365,13.38804285244884 +13.350564591375942,10.356821837792008,11.224487732578899 +15.772940731218004,11.319538717759949,14.855309504735919 +15.32574044259314,10.481122977918474,13.733253519289201 +15.773175592914502,9.639974102163345,13.655438949773078 +15.446118370802584,8.788472573247875,12.323545353645057 +14.919726525558847,11.45806258291988,12.74388182590297 +16.062905576373215,10.531367939646586,14.024839908329197 +14.329966609239547,10.453996745489409,11.569667164073383 +4.358523002772582,2.9047902173202083,3.201047090506088 +4.522043850355588,2.546457736975316,2.32466557921097 +4.620662629573732,1.693890659761069,3.297783598446412 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +3.8800560072322856,2.061812679886443,2.1878555553435595 +3.2249056515145504,2.4230106561365683,3.0429616378828106 +3.6660929224186103,2.0527349724422215,3.295630936016629 +14.811107169082419,9.445219168766743,11.34944443557662 +15.837135150351582,9.929506436590483,14.228235588111701 +15.163463933643355,9.911570168671203,13.296170766816418 +13.379498435974181,8.424151488881964,11.777628655231704 +15.09719213841926,8.616130176986438,14.650085204249619 +14.530445016376333,9.903904426859292,11.992305660835719 +12.683091646012187,9.609690309897571,12.608470521139704 +15.161572009980798,11.859169020499678,12.01609985664993 +15.464762297284825,9.619064736012247,11.70875731687824 +14.57124104343726,9.835137961764522,13.034456860078974 +4.1899513385524765,1.6634976206653975,3.1745605752098283 +3.792509447858168,2.6245613590923855,3.1228006982329486 +3.918480020019664,2.248540607461771,3.120093174275007 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +2.664266437876905,2.8297800224283907,3.119256739676787 +3.4692184692078745,1.4456596104496902,3.0419241287839136 +4.138453901033732,2.792432719946729,3.6811909803840877 +15.809152809817094,10.17944231167236,10.964183302624638 +16.80325279393437,12.333349719332059,12.031937904859547 +15.511570708593652,9.514061188666387,13.282083954647428 +14.608092201744842,9.952852053554615,11.082537718978603 +13.466861813131342,9.171857950253385,13.256681120778628 +16.772166983539307,9.672167309295238,13.455059341704882 +15.7359561104394,10.621882403425513,11.058405413614008 +13.181961618888016,10.151559505856797,13.157851667815645 +14.151819719763102,9.62911046588933,11.17733407872489 +16.18793526794129,12.528320253421509,11.418990584435582 +3.708691011418808,2.403582238819296,2.966634591414149 +3.8577463274091364,2.222328834537939,2.2717559610476474 +3.57525838776286,3.418601686317389,2.752956312576816 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 +0.0,0.0,0.0 diff --git a/datasets/m4_hourly_example.csv b/datasets/m4_hourly_example.csv new file mode 100644 index 0000000..3eafc92 --- /dev/null +++ b/datasets/m4_hourly_example.csv @@ -0,0 +1,749 @@ +values +60.0 +31.0 +42.0 +14.0 +55.0 +78.0 +154.0 +297.0 +905.0 +389.0 +301.0 +443.0 +604.0 +528.0 +512.0 +516.0 +668.0 +989.0 +552.0 +292.0 +317.0 +359.0 +181.0 +152.0 +62.0 +30.0 +17.0 +17.0 +29.0 +50.0 +156.0 +331.0 +914.0 +409.0 +310.0 +355.0 +599.0 +540.0 +458.0 +482.0 +649.0 +1024.0 +587.0 +348.0 +367.0 +328.0 +164.0 +143.0 +49.0 +23.0 +13.0 +20.0 +39.0 +43.0 +150.0 +333.0 +915.0 +439.0 +347.0 +546.0 +644.0 +690.0 +504.0 +537.0 +700.0 +1115.0 +550.0 +323.0 +316.0 +300.0 +210.0 +242.0 +143.0 +38.0 +33.0 +35.0 +52.0 +55.0 +159.0 +363.0 +848.0 +470.0 +301.0 +351.0 +554.0 +592.0 +455.0 +485.0 +573.0 +1026.0 +580.0 +340.0 +271.0 +388.0 +241.0 +202.0 +110.0 +36.0 +37.0 +19.0 +69.0 +64.0 +137.0 +337.0 +798.0 +487.0 +447.0 +536.0 +742.0 +684.0 +646.0 +624.0 +730.0 +1008.0 +646.0 +484.0 +419.0 +536.0 +430.0 +363.0 +270.0 +122.0 +92.0 +57.0 +62.0 +59.0 +61.0 +82.0 +112.0 +244.0 +364.0 +410.0 +439.0 +487.0 +576.0 +577.0 +587.0 +562.0 +539.0 +355.0 +346.0 +413.0 +436.0 +331.0 +282.0 +160.0 +101.0 +99.0 +52.0 +57.0 +38.0 +83.0 +150.0 +188.0 +271.0 +393.0 +475.0 +512.0 +536.0 +596.0 +668.0 +730.0 +530.0 +493.0 +392.0 +312.0 +382.0 +333.0 +191.0 +99.0 +41.0 +49.0 +89.0 +69.0 +60.0 +88.0 +124.0 +153.0 +287.0 +360.0 +404.0 +502.0 +540.0 +453.0 +396.0 +476.0 +340.0 +234.0 +182.0 +137.0 +89.0 +119.0 +53.0 +30.0 +13.0 +20.0 +38.0 +45.0 +112.0 +313.0 +898.0 +467.0 +296.0 +279.0 +431.0 +511.0 +415.0 +374.0 +561.0 +887.0 +522.0 +289.0 +212.0 +296.0 +131.0 +68.0 +41.0 +25.0 +14.0 +17.0 +36.0 +46.0 +110.0 +275.0 +710.0 +424.0 +227.0 +275.0 +486.0 +555.0 +389.0 +402.0 +540.0 +1001.0 +537.0 +262.0 +262.0 +259.0 +136.0 +100.0 +44.0 +15.0 +22.0 +18.0 +36.0 +48.0 +134.0 +281.0 +798.0 +390.0 +264.0 +308.0 +467.0 +825.0 +476.0 +500.0 +525.0 +919.0 +501.0 +328.0 +304.0 +315.0 +232.0 +168.0 +89.0 +28.0 +22.0 +20.0 +53.0 +69.0 +134.0 +301.0 +709.0 +386.0 +331.0 +473.0 +642.0 +581.0 +464.0 +586.0 +653.0 +923.0 +623.0 +377.0 +395.0 +404.0 +265.0 +371.0 +309.0 +113.0 +56.0 +41.0 +61.0 +65.0 +68.0 +101.0 +110.0 +185.0 +246.0 +330.0 +356.0 +375.0 +380.0 +425.0 +452.0 +414.0 +358.0 +357.0 +294.0 +315.0 +265.0 +290.0 +272.0 +150.0 +122.0 +101.0 +65.0 +73.0 +34.0 +96.0 +125.0 +176.0 +220.0 +331.0 +304.0 +352.0 +415.0 +421.0 +405.0 +342.0 +327.0 +237.0 +200.0 +235.0 +146.0 +171.0 +49.0 +35.0 +22.0 +15.0 +47.0 +57.0 +142.0 +318.0 +703.0 +418.0 +284.0 +295.0 +562.0 +626.0 +465.0 +444.0 +501.0 +1044.0 +548.0 +319.0 +252.0 +282.0 +130.0 +128.0 +49.0 +26.0 +25.0 +18.0 +45.0 +50.0 +167.0 +330.0 +741.0 +415.0 +279.0 +267.0 +447.0 +539.0 +377.0 +433.0 +563.0 +972.0 +576.0 +360.0 +302.0 +359.0 +231.0 +158.0 +55.0 +35.0 +14.0 +21.0 +31.0 +47.0 +150.0 +359.0 +790.0 +413.0 +291.0 +403.0 +549.0 +702.0 +498.0 +536.0 +543.0 +1046.0 +702.0 +558.0 +241.0 +289.0 +355.0 +190.0 +66.0 +36.0 +22.0 +24.0 +45.0 +56.0 +170.0 +355.0 +764.0 +404.0 +494.0 +342.0 +733.0 +659.0 +555.0 +529.0 +593.0 +1040.0 +568.0 +393.0 +275.0 +367.0 +166.0 +201.0 +92.0 +49.0 +29.0 +17.0 +46.0 +62.0 +121.0 +333.0 +690.0 +370.0 +300.0 +367.0 +481.0 +589.0 +456.0 +498.0 +583.0 +949.0 +644.0 +462.0 +417.0 +451.0 +378.0 +385.0 +335.0 +91.0 +95.0 +67.0 +69.0 +75.0 +66.0 +84.0 +130.0 +221.0 +293.0 +268.0 +376.0 +339.0 +477.0 +402.0 +435.0 +429.0 +386.0 +351.0 +347.0 +353.0 +388.0 +370.0 +331.0 +213.0 +139.0 +87.0 +68.0 +59.0 +56.0 +98.0 +129.0 +126.0 +253.0 +322.0 +365.0 +392.0 +450.0 +414.0 +453.0 +353.0 +336.0 +327.0 +200.0 +189.0 +165.0 +142.0 +56.0 +25.0 +18.0 +21.0 +50.0 +50.0 +134.0 +304.0 +723.0 +334.0 +230.0 +318.0 +565.0 +645.0 +459.0 +483.0 +587.0 +911.0 +581.0 +312.0 +217.0 +338.0 +163.0 +151.0 +67.0 +30.0 +30.0 +31.0 +37.0 +45.0 +152.0 +345.0 +750.0 +407.0 +282.0 +280.0 +476.0 +607.0 +486.0 +452.0 +585.0 +987.0 +531.0 +303.0 +225.0 +288.0 +213.0 +199.0 +82.0 +31.0 +24.0 +26.0 +43.0 +51.0 +143.0 +350.0 +719.0 +378.0 +262.0 +380.0 +609.0 +593.0 +536.0 +563.0 +633.0 +929.0 +577.0 +444.0 +316.0 +348.0 +254.0 +191.0 +73.0 +31.0 +40.0 +14.0 +40.0 +58.0 +156.0 +352.0 +696.0 +359.0 +276.0 +416.0 +614.0 +687.0 +508.0 +535.0 +579.0 +1026.0 +605.0 +327.0 +289.0 +353.0 +295.0 +188.0 +132.0 +39.0 +25.0 +27.0 +69.0 +67.0 +138.0 +304.0 +703.0 +373.0 +289.0 +376.0 +572.0 +605.0 +504.0 +569.0 +636.0 +1033.0 +825.0 +569.0 +413.0 +524.0 +648.0 +455.0 +325.0 +139.0 +116.0 +107.0 +83.0 +67.0 +62.0 +91.0 +107.0 +203.0 +280.0 +386.0 +410.0 +456.0 +553.0 +505.0 +535.0 +511.0 +433.0 +375.0 +401.0 +407.0 +371.0 +405.0 +309.0 +234.0 +129.0 +74.0 +74.0 +54.0 +76.0 +89.0 +136.0 +178.0 +269.0 +396.0 +458.0 +488.0 +650.0 +594.0 +466.0 +546.0 +348.0 +316.0 +295.0 +269.0 +249.0 +203.0 +63.0 +26.0 +20.0 +18.0 +51.0 +58.0 +94.0 +305.0 +713.0 +363.0 +288.0 +330.0 +570.0 +651.0 +511.0 +494.0 +633.0 +940.0 +568.0 +335.0 +301.0 +360.0 +198.0 +175.0 +72.0 +36.0 +26.0 +23.0 +37.0 +37.0 +137.0 +315.0 +723.0 +320.0 +295.0 +320.0 +563.0 +556.0 +522.0 +555.0 +571.0 +919.0 +519.0 +335.0 +277.0 +408.0 +268.0 +212.0 +113.0 +55.0 +25.0 +24.0 +42.0 +47.0 +140.0 +306.0 +763.0 +368.0 +293.0 +364.0 +602.0 +568.0 +558.0 +612.0 +580.0 +1008.0 +551.0 +350.0 +301.0 +351.0 +210.0 +186.0 +60.0 +32.0 +23.0 +24.0 diff --git a/docs/make.jl b/docs/make.jl index 4cab547..5d1ce90 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -15,7 +15,7 @@ makedocs(; format=Documenter.HTML(; mathengine=Documenter.MathJax2()), sitename="StateSpaceLearning.jl", authors="André Ramos", - pages=["Home" => "index.md", "manual.md"], + pages=["Home" => "index.md", "manual.md", "features.md", "examples.md"], ) deploydocs(; repo="github.com/LAMPSPUC/StateSpaceLearning.jl.git", push_preview=true) diff --git a/docs/src/assets/one_seas.png b/docs/src/assets/one_seas.png new file mode 100644 index 0000000..208d996 Binary files /dev/null and b/docs/src/assets/one_seas.png differ diff --git a/docs/src/assets/solar_sim_raw.png b/docs/src/assets/solar_sim_raw.png new file mode 100644 index 0000000..c4b28a6 Binary files /dev/null and b/docs/src/assets/solar_sim_raw.png differ diff --git a/docs/src/assets/solar_sim_treated.png b/docs/src/assets/solar_sim_treated.png new file mode 100644 index 0000000..a092ca0 Binary files /dev/null and b/docs/src/assets/solar_sim_treated.png differ diff --git a/docs/src/assets/two_seas.png b/docs/src/assets/two_seas.png new file mode 100644 index 0000000..a531dd1 Binary files /dev/null and b/docs/src/assets/two_seas.png differ diff --git a/docs/src/examples.md b/docs/src/examples.md new file mode 100644 index 0000000..ba1d16d --- /dev/null +++ b/docs/src/examples.md @@ -0,0 +1,117 @@ +# Examples + +In this page, we present examples of applications and use cases for the package. + +## Univariate Forecast + +Here we forecast the US airline passengers from 1949 to 1960. + +```julia +using CSV, DataFrames, Plots, StateSpaceLearning + +airp = CSV.File(StateSpaceLearning.AIR_PASSENGERS) |> DataFrame +log_air_passengers = log.(airp.passengers) +T = length(log_air_passengers) +steps_ahead = 30 + +model = StructuralModel(log_air_passengers) +fit!(model) +prediction_log = StateSpaceLearning.forecast(model, steps_ahead) # arguments are the output of the fitted model and number of steps ahead the user wants to forecast +prediction = exp.(prediction_log) + +plot_point_forecast(airp.passengers, prediction) +``` +![quick_example_airp](assets/quick_example_airp.PNG) + +```julia +N_scenarios = 1000 +simulation = StateSpaceLearning.simulate(model, steps_ahead, N_scenarios) # arguments are the output of the fitted model, number of steps ahead the user wants to forecast and number of scenario paths + +plot_scenarios(airp.passengers, exp.(simulation)) + +``` +![airp_sim](assets/airp_sim.svg) + +## Forecasting intermittent series + +The ``StateSpaceLearning.jl`` package offers a convenient approach for managing intermittent series. Within the ``simulate`` function, the ``seasonal\_innovation\_simulation`` hyperparameter can be configured to ensure that the variability in the simulations also exhibits a seasonal pattern. + +We first execute the code with the default parameters to highlight the importance of adapting the model to handle this type of time series effectively: + +```julia +using CSV, DataFrames, Plots, StateSpaceLearning + +solars = CSV.File(StateSpaceLearning.ARTIFICIAL_SOLARS) |> DataFrame +y = solars[!, "y1"] +T = length(y) +steps_ahead = 48 + +model = StructuralModel(y; freq_seasonal=24, trend=false, level=false) +fit!(model; penalize_initial_states=false) +simulation = StateSpaceLearning.simulate(model, steps_ahead, 100) #Gets a 12 steps ahead prediction +plot_scenarios(y, simulation) +``` +![solar_sim_raw](assets/solar_sim_raw.png) + +Now we present the results by setting the ``seasonal\_innovation\_simulation`` hyperparameter to 24 (given that it is a solar hourly time series). + +```julia +using CSV, DataFrames, Plots, StateSpaceLearning + +solars = CSV.File(StateSpaceLearning.ARTIFICIAL_SOLARS) |> DataFrame +y = solars[!, "y1"] +T = length(y) +steps_ahead = 48 + +model = StructuralModel(y; freq_seasonal=24, trend=false, level=false) +fit!(model; penalize_initial_states=false) +simulation = StateSpaceLearning.simulate(model, steps_ahead, 100; seasonal_innovation_simulation=24) #Gets a 12 steps ahead prediction +plot_scenarios(y, simulation) +``` +![solar_sim_treated](assets/solar_sim_treated.png) + +Thus, the model has demonstrated its capability to effectively capture the intermittent nature of the solar time series, providing a more accurate representation of its underlying characteristics. + +## Forecasting with Multiple Seasonality + +The ``StateSpaceLearning.jl`` package handles multiple seasonality by passing parameter ``freq\_seasonal`` as a vector of Int in the StructuralModel instantiation. + +We first execute the code considering a single daily seasonality (``freq\_seasonal``=24) to highlight the importance of adapting the model to handle this type of time series effectively: + +```julia +using CSV, DataFrames, Plots, StateSpaceLearning + +solars = CSV.File(StateSpaceLearning.HOURLY_M4_EXAMPLE) |> DataFrame +y = solars[!, "values"] +T = length(y) +steps_ahead = 168 + +model = StructuralModel(y; freq_seasonal=24) +fit!(model) +prediction = StateSpaceLearning.forecast(model, steps_ahead) # arguments are the output of the fitted model and number of steps ahead the user wants to forecast + +plot_point_forecast(y, prediction) +``` +![one_seas](assets/one_seas.png) + + +Note that the model successfully captured the daily seasonality but, as expected, was unable to capture the weekly seasonality. We now present the results after setting the `freq\_seasonal` hyperparameter to [24, 168], accounting for both daily and weekly seasonalities. + + +```julia +using CSV, DataFrames, Plots, StateSpaceLearning + +solars = CSV.File(StateSpaceLearning.HOURLY_M4_EXAMPLE) |> DataFrame +y = solars[!, "values"] +T = length(y) +steps_ahead = 168 + +model = StructuralModel(y; freq_seasonal=[24, 168]) +fit!(model) +prediction = StateSpaceLearning.forecast(model, steps_ahead) # arguments are the output of the fitted model and number of steps ahead the user wants to forecast + +plot_point_forecast(y, prediction) +``` +![two_seas](assets/two_seas.png) + +Note that the model was able to capture both seasonalities in this case. \ No newline at end of file diff --git a/docs/src/features.md b/docs/src/features.md new file mode 100644 index 0000000..372cb0a --- /dev/null +++ b/docs/src/features.md @@ -0,0 +1,114 @@ +# Extra Features + +In addition to forecasting and scenario simulation, ``StateSpaceLearning.jl`` provides several other functionalities, including component extraction, missing value inputation, outlier detection, and best subset selection. + +## Component Extraction + +Quick example on how to perform component extraction in time series utilizing StateSpaceLearning. + +```julia +using CSV +using DataFrames +using Plots + +airp = CSV.File(StateSpaceLearning.AIR_PASSENGERS) |> DataFrame +log_air_passengers = log.(airp.passengers) + +model = StructuralModel(log_air_passengers) +fit!(model) + +level = model.output.components["μ1"]["Values"] + model.output.components["ξ"]["Values"] +slope = model.output.components["ν1"]["Values"] + model.output.components["ζ"]["Values"] +seasonal = model.output.components["γ1_12"]["Values"] + model.output.components["ω_12"]["Values"] +trend = level + slope + +plot(trend, w=2 , color = "Black", lab = "Trend Component", legend = :outerbottom) +plot(seasonal, w=2 , color = "Black", lab = "Seasonal Component", legend = :outerbottom) + +``` + +| ![quick_example_trend](assets/trend.svg) | ![quick_example_seas](assets/seasonal.svg)| + +## Missing Value Imputation + +Quick example of completion of missing values for the air passengers time-series (artificial NaN values are added to the original time-series). + +```julia +using CSV +using DataFrames +using Plots + +airp = CSV.File(StateSpaceLearning.AIR_PASSENGERS) |> DataFrame +log_air_passengers = log.(airp.passengers) + +airpassengers = AbstractFloat.(airp.passengers) +log_air_passengers[60:72] .= NaN + +model = StructuralModel(log_air_passengers) +fit!(model) + +fitted_completed_missing_values = ones(144).*NaN; fitted_completed_missing_values[60:72] = exp.(model.output.fitted[60:72]) +real_removed_valued = ones(144).*NaN; real_removed_valued[60:72] = deepcopy(airp.passengers[60:72]) +airpassengers[60:72] .= NaN + +plot(airpassengers, w=2 , color = "Black", lab = "Historical", legend = :outerbottom) +plot!(real_removed_valued, lab = "Real Removed Values", w=2, color = "red") +plot!(fitted_completed_missing_values, lab = "Fit in Sample completed values", w=2, color = "blue") + +``` +![quick_example_completion_airp](assets/quick_example_completion_airp.PNG) + +## Outlier Detection + +Quick example of outlier detection for an altered air passengers time-series (artificial NaN values are added to the original time-series). + +```julia +using CSV +using DataFrames +using Plots + +airp = CSV.File(StateSpaceLearning.AIR_PASSENGERS) |> DataFrame +log_air_passengers = log.(airp.passengers) + +log_air_passengers[60] = 10 +log_air_passengers[30] = 1 +log_air_passengers[100] = 2 + +model = StructuralModel(log_air_passengers) +fit!(model) + +detected_outliers = findall(i -> i != 0, model.output.components["o"]["Coefs"]) + +plot(log_air_passengers, w=2 , color = "Black", lab = "Historical", legend = :outerbottom) +scatter!([detected_outliers], log_air_passengers[detected_outliers], lab = "Detected Outliers") + +``` +![quick_example_completion_airp](assets/outlier.svg) + +## Best Subset Selection + +Quick example on how to perform best subset selection in time series utilizing StateSpaceLearning. + +```julia +using StateSpaceLearning +using CSV +using DataFrames +using Random + +Random.seed!(2024) + +airp = CSV.File(StateSpaceLearning.AIR_PASSENGERS) |> DataFrame +log_air_passengers = log.(airp.passengers) +X = rand(length(log_air_passengers), 10) # Create 10 exogenous features +β = rand(3) + +y = log_air_passengers + X[:, 1:3]*β # add to the log_air_passengers series a contribution from only 3 exogenous features. + +model = StructuralModel(y; Exogenous_X = X) +fit!(model; α = 1.0, information_criteria = "bic", ϵ = 0.05, penalize_exogenous = true, penalize_initial_states = true) + +Selected_exogenous = model.output.components["Exogenous_X"]["Selected"] + +``` + +In this example, the selected exogenous features were 1, 2, 3, as expected. \ No newline at end of file diff --git a/docs/src/manual.md b/docs/src/manual.md index 4855bbc..e8d20e9 100644 --- a/docs/src/manual.md +++ b/docs/src/manual.md @@ -1,9 +1,9 @@ -# StateSpaceLearning - -StateSpaceLearning.jl is a package for modeling and forecasting time series in a high-dimension regression framework. +# Manual ## Quickstart +While StateSpaceModels.jl offers a rich array of functionalities, diverse models, and flexible interfaces, most users primarily seek to achieve core tasks: fitting a model and generating forecasts. The following example provides a concise introduction to performing these essential operations effectively. + ```julia using StateSpaceLearning @@ -21,236 +21,41 @@ prediction = StateSpaceLearning.forecast(model, 12) #Gets a 12 steps ahead predi # Scenarios Path Simulation simulation = StateSpaceLearning.simulate(model, 12, 1000) #Gets 1000 scenarios path of 12 steps ahead predictions ``` +## Models -## StructuralModel Arguments - -* `y::Vector`: Vector of data. -* `level::Bool`: Boolean where to consider intercept in the model (default: true) -* `stochastic_level::Bool`: Boolean where to consider stochastic level component in the model (default: true) -* `trend::Bool`: Boolean where to consider trend component in the model (default: true) -* `stochastic_trend::Bool`: Boolean where to consider stochastic trend component in the model (default: true) -* `seasonal::Bool`: Boolean where to consider seasonal component in the model (default: true) -* `stochastic_seasonal::Bool`: Boolean where to consider stochastic seasonal component in the model (default: true) -* `freq_seasonal::Int`: Seasonal frequency to be considered in the model (default: 12) -* `outlier::Bool`: Boolean where to consider outlier component in the model (default: true) -* `ζ_ω_threshold::Int`: Argument to stabilize `stochastic trend` and `stochastic seasonal` components (default: 12) - -## Features - -Current features include: -* Estimation -* Components decomposition -* Forecasting -* Completion of missing values -* Predefined models, including: -* Outlier detection -* Outlier robust models - -## Quick Examples - -### Fitting, forecasting and simulating -Quick example of fit and forecast for the air passengers time-series. - -```julia -using CSV -using DataFrames -using Plots - -airp = CSV.File(StateSpaceLearning.AIR_PASSENGERS) |> DataFrame -log_air_passengers = log.(airp.passengers) -steps_ahead = 30 - -model = StructuralModel(log_air_passengers) -fit!(model) -prediction_log = StateSpaceLearning.forecast(model, steps_ahead) # arguments are the output of the fitted model and number of steps ahead the user wants to forecast -prediction = exp.(prediction_log) - -plot(airp.passengers, w=2 , color = "Black", lab = "Historical", legend = :outerbottom) -plot!(vcat(ones(length(log_air_passengers)).*NaN, prediction), lab = "Forecast", w=2, color = "blue") -``` -![quick_example_airp](assets/quick_example_airp.PNG) - -```julia -N_scenarios = 1000 -simulation = StateSpaceLearning.simulate(model, steps_ahead, N_scenarios) # arguments are the output of the fitted model, number of steps ahead the user wants to forecast and number of scenario paths - -plot(airp.passengers, w=2 , color = "Black", lab = "Historical", legend = :outerbottom) -for s in 1:N_scenarios-1 - plot!(vcat(ones(length(log_air_passengers)).*NaN, exp.(simulation[:, s])), lab = "", α = 0.1 , color = "red") -end -plot!(vcat(ones(length(log_air_passengers)).*NaN, exp.(simulation[:, N_scenarios])), lab = "Scenarios Paths", α = 0.1 , color = "red") - -``` -![airp_sim](assets/airp_sim.svg) - -### Component Extraction -Quick example on how to perform component extraction in time series utilizing StateSpaceLearning. - -```julia -using CSV -using DataFrames -using Plots - -airp = CSV.File(StateSpaceLearning.AIR_PASSENGERS) |> DataFrame -log_air_passengers = log.(airp.passengers) - -model = StructuralModel(log_air_passengers) -fit!(model) - -level = model.output.components["μ1"]["Values"] + model.output.components["ξ"]["Values"] -slope = model.output.components["ν1"]["Values"] + model.output.components["ζ"]["Values"] -seasonal = model.output.components["γ1"]["Values"] + model.output.components["ω"]["Values"] -trend = level + slope - -plot(trend, w=2 , color = "Black", lab = "Trend Component", legend = :outerbottom) -plot(seasonal, w=2 , color = "Black", lab = "Seasonal Component", legend = :outerbottom) - -``` - -| ![quick_example_trend](assets/trend.svg) | ![quick_example_seas](assets/seasonal.svg)| -|:------------------------------:|:-----------------------------:| - - -### Best Subset Selection -Quick example on how to perform best subset selection in time series utilizing StateSpaceLearning. - -```julia -using StateSpaceLearning -using CSV -using DataFrames -using Random - -Random.seed!(2024) - -airp = CSV.File(StateSpaceLearning.AIR_PASSENGERS) |> DataFrame -log_air_passengers = log.(airp.passengers) -X = rand(length(log_air_passengers), 10) # Create 10 exogenous features -β = rand(3) - -y = log_air_passengers + X[:, 1:3]*β # add to the log_air_passengers series a contribution from only 3 exogenous features. - -model = StructuralModel(y; Exogenous_X = X) -fit!(model; α = 1.0, information_criteria = "bic", ϵ = 0.05, penalize_exogenous = true, penalize_initial_states = true) - -Selected_exogenous = model.output.components["Exogenous_X"]["Selected"] +The package currently supports the implementation of the StructuralModel. If you have suggestions for additional models to include, we encourage you to contribute by opening an issue or submitting a pull request. +```@docs +StateSpaceLearning.StructuralModel ``` -In this example, the selected exogenous features were 1, 2, 3, as expected. - -### Missing values imputation -Quick example of completion of missing values for the air passengers time-series (artificial NaN values are added to the original time-series). - -```julia -using CSV -using DataFrames -using Plots - -airp = CSV.File(StateSpaceLearning.AIR_PASSENGERS) |> DataFrame -log_air_passengers = log.(airp.passengers) +## Fitting -airpassengers = AbstractFloat.(airp.passengers) -log_air_passengers[60:72] .= NaN - -model = StructuralModel(log_air_passengers) -fit!(model) - -fitted_completed_missing_values = ones(144).*NaN; fitted_completed_missing_values[60:72] = exp.(model.output.fitted[60:72]) -real_removed_valued = ones(144).*NaN; real_removed_valued[60:72] = deepcopy(airp.passengers[60:72]) -airpassengers[60:72] .= NaN - -plot(airpassengers, w=2 , color = "Black", lab = "Historical", legend = :outerbottom) -plot!(real_removed_valued, lab = "Real Removed Values", w=2, color = "red") -plot!(fitted_completed_missing_values, lab = "Fit in Sample completed values", w=2, color = "blue") +The package currently only allows for the estimation procedure (based on the elastic net) presented in the paper "Time Series Analysis by State Space Learning". We allow some parameters configurations as detailed below. If you have suggestions for additional estimation procedures to include, we encourage you to contribute by opening an issue or submitting a pull request. +```@docs +StateSpaceLearning.fit! ``` -![quick_example_completion_airp](assets/quick_example_completion_airp.PNG) - -### Outlier Detection -Quick example of outlier detection for an altered air passengers time-series (artificial NaN values are added to the original time-series). -```julia -using CSV -using DataFrames -using Plots - -airp = CSV.File(StateSpaceLearning.AIR_PASSENGERS) |> DataFrame -log_air_passengers = log.(airp.passengers) - -log_air_passengers[60] = 10 -log_air_passengers[30] = 1 -log_air_passengers[100] = 2 - -model = StructuralModel(log_air_passengers) -fit!(model) +## Forecasting and Simulating -detected_outliers = findall(i -> i != 0, model.output.components["o"]["Coefs"]) - -plot(log_air_passengers, w=2 , color = "Black", lab = "Historical", legend = :outerbottom) -scatter!([detected_outliers], log_air_passengers[detected_outliers], lab = "Detected Outliers") +The package has functions to make point forecasts multiple steps ahead and to simulate scenarios based on those forecasts. These functions are implemented both for the univariate and to the multivariate cases. +```@docs +StateSpaceLearning.forecast ``` -![quick_example_completion_airp](assets/outlier.svg) - -### StateSpaceModels initialization -Quick example on how to use StateSpaceLearning to initialize StateSpaceModels - -```julia -using CSV -using DataFrames -using StateSpaceModels - -airp = CSV.File(StateSpaceLearning.AIR_PASSENGERS) |> DataFrame -log_air_passengers = log.(airp.passengers) - -model = StructuralModel(log_air_passengers) -fit!(model) - -residuals_variances = model.output.residuals_variances - -ss_model = BasicStructural(log_air_passengers, 12) -set_initial_hyperparameters!(ss_model, Dict("sigma2_ε" => residuals_variances["ε"], - "sigma2_ξ" =>residuals_variances["ξ"], - "sigma2_ζ" =>residuals_variances["ζ"], - "sigma2_ω" =>residuals_variances["ω"])) -StateSpaceModels.fit!(ss_model) +```@docs +StateSpaceLearning.simulate ``` -## Paper Results Reproducibility - -The paper has two experiments (results for the M4 competition and a simulation study). To reproduce each experiment follow the instructions below: - -### M4 Experiment - -To reproduce M4 paper results you can clone the repository and run the following commands on terminal: - -```shell -julia paper_tests/m4_test/m4_test.jl -python paper_tests/m4_test/m4_test.py +## Datasets +The package includes several datasets designed to demonstrate its functionalities and showcase the models. These datasets are stored as CSV files, and their file paths can be accessed either by their names as shown below. In the examples, we utilize DataFrames.jl and CSV.jl to illustrate how to work with these datasets. +```@docs +StateSpaceLearning.AIR_PASSENGERS ``` - -The results for SSL model in terms of MASE and sMAPE for all 48000 series will be stored in folder "paper_tests/m4_test/results_SSL". The average results of MASE, sMAPE and OWA will be saved in file "paper_tests/m4_test/metric_results/SSL_METRICS_RESULTS.csv". - -The results for SS model in terms of MASE and sMAPE for all 48000 series will be stored in folder "paper_tests/m4_test/results_SS". The average results of MASE, sMAPE and OWA will be saved in file "paper_tests/m4_test/metric_results/SS_METRICS_RESULTS.csv". - -### Simulation Experiment - -To reproduce the simulation results you can clone the repository and run the following commands on terminal: - -```shell -julia paper_tests/simulation_test/simulation.jl 0 +```@docs +StateSpaceLearning.ARTIFICIAL_SOLARS ``` - -As this test takes a long time, you may want to run it in parallel, for that you can change the last argument to be number of workers to use in the parallelization: - -```shell -julia paper_tests/simulation_test/simulation.jl 3 +```@docs +StateSpaceLearning.HOURLY_M4_EXAMPLE ``` - -The results will be saved in two separated files: "paper_tests/simulation_test/results_metrics/metrics_confusion_matrix.csv" and "paper_tests/simulation_test/results_metrics/metrics_bias_mse.csv" - - -## Contributing - -* PRs such as adding new models and fixing bugs are very welcome! -* For nontrivial changes, you'll probably want to first discuss the changes via issue. \ No newline at end of file diff --git a/ext/PlotsExt.jl b/ext/PlotsExt.jl new file mode 100644 index 0000000..8d5d412 --- /dev/null +++ b/ext/PlotsExt.jl @@ -0,0 +1,34 @@ +module PlotsExt + +using StateSpaceLearning: StateSpaceLearning + +using Plots + +function StateSpaceLearning.plot_point_forecast(y::Vector, prediction::Vector) + T = length(y) + steps_ahead = length(prediction) + p = plot(collect(1:T), y; w=2, color="Black", lab="Historical", legend=:outerbottom) + plot!(collect((T + 1):(T + steps_ahead)), prediction; lab="Forecast", w=2, color="blue") + return p +end + +function StateSpaceLearning.plot_scenarios(y::Vector, simulation::Matrix) + T = length(y) + steps_ahead, n_scenarios = size(simulation) + p = plot(collect(1:T), y; w=2, color="Black", lab="Historical", legend=:outerbottom) + for s in 1:(n_scenarios - 1) + plot!( + collect((T + 1):(T + steps_ahead)), simulation[:, s]; lab="", α=0.1, color="red" + ) + end + plot!( + collect((T + 1):(T + steps_ahead)), + simulation[:, n_scenarios]; + lab="Scenarios Paths", + α=0.1, + color="red", + ) + return p +end + +end diff --git a/paper_tests/m4_test/evaluate_model.jl b/paper_tests/m4_test/evaluate_model.jl index 1f1055a..852da58 100644 --- a/paper_tests/m4_test/evaluate_model.jl +++ b/paper_tests/m4_test/evaluate_model.jl @@ -50,7 +50,7 @@ function evaluate_SSL( DataFrame( [ [model.output.residuals_variances["ξ"]], - [model.output.residuals_variances["ω"]], + [model.output.residuals_variances["ω_12"]], [model.output.residuals_variances["ε"]], [model.output.residuals_variances["ζ"]], ], diff --git a/paper_tests/m4_test/m4_test.py b/paper_tests/m4_test/m4_test.py index 246c386..cf8836c 100644 --- a/paper_tests/m4_test/m4_test.py +++ b/paper_tests/m4_test/m4_test.py @@ -52,7 +52,7 @@ def evaluate_ss(input, sample_size, init, hyperparameters_inicialization): results = [] results_init = [] for i in range(0, 48000): - hyperparameters_inicialization = [ssl_init_df.loc[i]["ϵ"], ssl_init_df.loc[i]["ξ"],ssl_init_df.loc[i]["ζ"],ssl_init_df.loc[i]["ω"]] + hyperparameters_inicialization = [ssl_init_df.loc[i]["ϵ"], ssl_init_df.loc[i]["ξ"],ssl_init_df.loc[i]["ζ"],ssl_init_df.loc[i]["ω_12"]] results.append(evaluate_ss(dict_vec[i], 2794, False, hyperparameters_inicialization)) results_init.append(evaluate_ss(dict_vec[i], 2794, True, hyperparameters_inicialization)) diff --git a/src/StateSpaceLearning.jl b/src/StateSpaceLearning.jl index 2f7069b..047fe6a 100644 --- a/src/StateSpaceLearning.jl +++ b/src/StateSpaceLearning.jl @@ -11,7 +11,8 @@ include("estimation_procedure.jl") include("utils.jl") include("datasets.jl") include("fit_forecast.jl") +include("plots.jl") -export fit!, forecast, simulate, StructuralModel +export fit!, forecast, simulate, StructuralModel, plot_point_forecast, plot_scenarios end # module StateSpaceLearning diff --git a/src/datasets.jl b/src/datasets.jl index fe058fa..0230a1f 100644 --- a/src/datasets.jl +++ b/src/datasets.jl @@ -4,9 +4,27 @@ The absolute path for the `AIR_PASSENGERS` dataset stored inside StateSpaceLearning.jl. This dataset provides monthly totals of a US airline passengers from 1949 to 1960. -See more on [Airline passengers](@ref) - # References * https://www.stata-press.com/data/r12/ts.html """ const AIR_PASSENGERS = joinpath(dirname(@__DIR__()), "datasets", "airpassengers.csv") + +@doc raw""" + ARTIFICIAL_SOLARS + +The absolute path for the `ARTIFICIAL_SOLARS` dataset stored inside StateSpaceLearning.jl. +This dataset provides an hourly Multivariate Time Series for 3 artificial solar power plants. + +""" +const ARTIFICIAL_SOLARS = joinpath(dirname(@__DIR__()), "datasets", "artificial_solars.csv") + +@doc raw""" + HOURLY_M4_EXAMPLE + +The absolute path for the `HOURLY_M4_EXAMPLE` dataset stored inside StateSpaceLearning.jl. +This dataset provides an hourly Time Series from the M4 competition dataset. + +# References + * https://github.com/Mcompetitions/M4-methods +""" +const HOURLY_M4_EXAMPLE = joinpath(dirname(@__DIR__()), "datasets", "m4_hourly_example.csv") diff --git a/src/estimation_procedure.jl b/src/estimation_procedure.jl index 20785eb..8f2cc12 100644 --- a/src/estimation_procedure.jl +++ b/src/estimation_procedure.jl @@ -326,7 +326,10 @@ function estimation_procedure( for key in keys(components_indexes) if key != "initial_states" && key != "μ1" component = components_indexes[key] - if key != "Exogenous_X" && key != "o" && !(key in ["ν1", "γ1"]) + if key != "Exogenous_X" && + key != "o" && + !(key in ["ν1"]) && + !(occursin("γ", key)) κ = count(i -> i != 0, coefs[component]) < 1 ? 0 : std(coefs[component]) if hasintercept ts_penalty_factor[component .- 1] .= (1 / (κ + ϵ)) diff --git a/src/fit_forecast.jl b/src/fit_forecast.jl index c69490e..62478a2 100644 --- a/src/fit_forecast.jl +++ b/src/fit_forecast.jl @@ -1,22 +1,31 @@ -""" -function fit!(model::StateSpaceLearningModel, +@doc raw""" +Fits the StateSpaceLearning model using specified parameters and estimation procedures. After fitting, the model output can be accessed in model.output + +fit!(model::StateSpaceLearningModel, α::AbstractFloat = 0.1, - information_criteria::String = "aic", + information\_criteria::String = "aic", ϵ::AbstractFloat = 0.05, - penalize_exogenous::Bool = true, - penalize_initial_states::Bool = true, + penalize\_exogenous::Bool = true, + penalize\_initial\_states::Bool = true, ) - Fits the StateSpaceLearning model using specified parameters and estimation procedures. +# Arguments +- model::StateSpaceLearningModel: Model to be fitted. +- α::AbstractFloat: Elastic net mixing parameter (default: 0.1). +- information\_criteria::String: Method for hyperparameter selection (default: "aic"). +- ϵ::AbstractFloat: Non negative value to handle 0 coefs on the first lasso step (default: 0.05). +- penalize\_exogenous::Bool: If true, penalize exogenous variables (default: true). +- penalize\_initial\_states::Bool: If true, penalize initial states (default: true). + +# Example +```julia +y = rand(100) +model = StructuralModel(y) +fit!(model) +output = model.output +``` - # Arguments - model::StateSpaceLearningModel: Model to be fitted. - α::AbstractFloat: Elastic net mixing parameter (default: 0.1). - information_criteria::String: Method for hyperparameter selection (default: "aic"). - ϵ::AbstractFloat: Non negative value to handle 0 coefs on the first lasso step (default: 0.05). - penalize_exogenous::Bool: If true, penalize exogenous variables (default: true). - penalize_initial_states::Bool: If true, penalize initial states (default: true). """ function fit!( model::StateSpaceLearningModel; @@ -75,25 +84,34 @@ function fit!( return model.output = output end -""" - forecast(model::StateSpaceLearningModel, steps_ahead::Int; Exogenous_Forecast::Union{Matrix{Fl}, Missing}=missing)::Vector{AbstractFloat} where Fl +@doc raw""" +Returns the forecast for a given number of steps ahead using the provided StateSpaceLearning output and exogenous forecast data. - Returns the forecast for a given number of steps ahead using the provided StateSpaceLearning output and exogenous forecast data. +forecast(model::StateSpaceLearningModel, steps\_ahead::Int; Exogenous\_Forecast::Union{Matrix{Fl}, Missing}=missing)::Vector{AbstractFloat} where Fl - # Arguments - - `model::StateSpaceLearningModel`: Model obtained from fitting. - - `steps_ahead::Int`: Number of steps ahead for forecasting. - - `Exogenous_Forecast::Matrix{Fl}`: Exogenous variables forecast (default: zeros(steps_ahead, 0)) +# Arguments +- `model::StateSpaceLearningModel`: Model obtained from fitting. +- `steps_ahead::Int`: Number of steps ahead for forecasting. +- `Exogenous_Forecast::Matrix{Fl}`: Exogenous variables forecast (default: zeros(steps_ahead, 0)) - # Returns - - `Union{Matrix{AbstractFloat}, Vector{AbstractFloat}}`: Matrix or vector of matrices containing forecasted values. +# Returns +- `Union{Matrix{AbstractFloat}, Vector{AbstractFloat}}`: Matrix or vector of matrices containing forecasted values. +# Example +```julia +y = rand(100) +model = StructuralModel(y) +fit!(model) +steps_ahead = 12 +point_prediction = forecast(model, steps_ahead) +``` """ function forecast( model::StateSpaceLearningModel, steps_ahead::Int; Exogenous_Forecast::Matrix{Fl}=zeros(steps_ahead, 0), )::Union{Matrix{<:AbstractFloat},Vector{<:AbstractFloat}} where {Fl<:AbstractFloat} + @assert isfitted(model) "Model must be fitted before simulation" exog_idx = if typeof(model.output) == Output model.output.components["Exogenous_X"]["Indexes"] else @@ -132,20 +150,40 @@ function forecast( end end -""" -simulate(model::StateSpaceLearningModel, steps_ahead::Int, N_scenarios::Int; - Exogenous_Forecast::Matrix{Fl}=zeros(steps_ahead, 0))::Matrix{AbstractFloat} where Fl - - Generate simulations for a given number of steps ahead using the provided StateSpaceLearning output and exogenous forecast data. - - # Arguments - - `model::StateSpaceLearningModel`: Model obtained from fitting. - - `steps_ahead::Int`: Number of steps ahead for simulation. - - `N_scenarios::Int`: Number of scenarios to simulate (default: 1000). - - `Exogenous_Forecast::Matrix{Fl}`: Exogenous variables forecast (default: zeros(steps_ahead, 0)) - - # Returns - - `Union{Vector{Matrix{AbstractFloat}}, Matrix{AbstractFloat}}`: Matrix or vector of matrices containing simulated values. +@doc raw""" +Generate simulations for a given number of steps ahead using the provided StateSpaceLearning output and exogenous forecast data. + +simulate(model::StateSpaceLearningModel, steps\_ahead::Int, N\_scenarios::Int; + Exogenous\_Forecast::Matrix{Fl}=zeros(steps_ahead, 0))::Matrix{AbstractFloat} where Fl + +# Arguments +- `model::StateSpaceLearningModel`: Model obtained from fitting. +- `steps_ahead::Int`: Number of steps ahead for simulation. +- `N_scenarios::Int`: Number of scenarios to simulate (default: 1000). +- `Exogenous_Forecast::Matrix{Fl}`: Exogenous variables forecast (default: zeros(steps_ahead, 0)) + +# Returns +- `Union{Vector{Matrix{AbstractFloat}}, Matrix{AbstractFloat}}`: Matrix or vector of matrices containing simulated values. + +# Example (Univariate Case) +```julia +y = rand(100) +model = StructuralModel(y) +fit!(model) +steps_ahead = 12 +N_scenarios = 1000 +simulation = simulate(model, steps_ahead, N_scenarios) +``` + +# Example (Multivariate Case) +```julia +y = rand(100, 3) +model = StructuralModel(y) +fit!(model) +steps_ahead = 12 +N_scenarios = 1000 +simulation = simulate(model, steps_ahead, N_scenarios) +``` """ function simulate( model::StateSpaceLearningModel, @@ -156,6 +194,7 @@ function simulate( )::Union{Vector{Matrix{<:AbstractFloat}},Matrix{<:AbstractFloat}} where {Fl<:AbstractFloat} @assert seasonal_innovation_simulation >= 0 "seasonal_innovation_simulation must be a non-negative integer" @assert seasonal_innovation_simulation >= 0 "seasonal_innovation_simulation must be a non-negative integer" + @assert isfitted(model) "Model must be fitted before simulation" prediction = StateSpaceLearning.forecast( model, steps_ahead; Exogenous_Forecast=Exogenous_Forecast diff --git a/src/models/structural_model.jl b/src/models/structural_model.jl index bdb6a70..c7f301a 100644 --- a/src/models/structural_model.jl +++ b/src/models/structural_model.jl @@ -1,3 +1,54 @@ +@doc raw""" +Instantiates a Structural State Space Learning model. + + StructuralModel( + y::Union{Vector,Matrix}; + level::Bool=true, + stochastic_level::Bool=true, + trend::Bool=true, + stochastic_trend::Bool=true, + seasonal::Bool=true, + stochastic_seasonal::Bool=true, + freq_seasonal::Union{Int, Vector{Int}}=12, + outlier::Bool=true, + ζ_ω_threshold::Int=12, + Exogenous_X::Matrix=if typeof(y) <: Vector + zeros(length(y), 0) + else + zeros(size(y, 1), 0) + end, + ) + +A Structural State Space Learning model that can have level, stochastic_level, trend, stochastic_trend, seasonal, stochastic_seasonal, outlier and Exogenous components. Each component should be specified by Booleans. + +These models take the general form: + +```math +\begin{gather*} + \begin{aligned} + y_1 &= \mu_1 + \gamma_1 + X_1\beta + \sum_{\tau=1}^1D_{\tau,1} \,o_\tau + \varepsilon_1\\ + y_2 &= \mu_1 + \xi_2 + \nu_1 + \gamma_2 + X_2\beta + \sum_{\tau=1}^2D_{\tau,2} \,o_\tau + \varepsilon_2 \\ + y_t &= \mu_1 + \sum_{\tau=2}^{t}\xi_\tau + (t-1)\nu_1 + \sum_{\tau=2}^{t-1}(t-\tau)\zeta_\tau + \gamma_{m_t} + X_t\beta + \sum_{\tau=1}^tD_{\tau,t} \,o_\tau + \varepsilon_t, \quad \forall t = \{3, \ldots, s\} \label{cor_t2}\\ + y_t &= \mu_1 + \sum_{\tau=2}^{t}\xi_\tau + (t-1)\nu_1 + \sum_{\tau=2}^{t-1}(t-\tau)\zeta_\tau + \gamma_{m_{t}} + \sum_{\tau \in M_{t}}(\omega_{{\tau}} - \omega_{\tau-1})+ X_t\beta + \sum_{\tau=1}^tD_{\tau,t} \,o_\tau + \varepsilon_t, \quad \forall t=s+1,\ldots,T \\ + % \zeta_t, \xi_t, \omega_t =0, \; \forall \; t > T + \end{aligned} +\end{gather*} +``` + +The notation is as follows: ``y_t`` represents the observation vector at time ``t``, ``\mu_1`` denotes the initial level component (intercept), and ``\xi_t`` refers to the stochastic level component. Similarly, ``\nu_1`` corresponds to the deterministic slope component, and ``\zeta_t`` represents the stochastic slope component. The seasonal effects are described by ``\gamma_{m_t}`` for the deterministic seasonal component and ``\omega_{\tau}`` for the stochastic seasonal component. + +The exogenous component is represented by ``X``, with ``\beta`` as the associated coefficients. Outlier effects are captured by the dummy outlier matrix ``D`` and its corresponding coefficients ``o``. Finally, ``\varepsilon_t`` denotes the irregular term. + +# References + * Ramos, André, & Valladão, Davi, & Street, Alexandre. + Time Series Analysis by State Space Learning + +# Example +```julia +y = rand(100) +model = StructuralModel(y) +``` +""" mutable struct StructuralModel <: StateSpaceLearningModel y::Union{Vector,Matrix} X::Matrix @@ -7,35 +58,35 @@ mutable struct StructuralModel <: StateSpaceLearningModel stochastic_trend::Bool seasonal::Bool stochastic_seasonal::Bool - freq_seasonal::Int + freq_seasonal::Union{Int,Vector{Int}} outlier::Bool ζ_ω_threshold::Int n_exogenous::Int output::Union{Vector{Output},Output,Nothing} function StructuralModel( - y::Union{Vector{Fl},Matrix{Fl}}; + y::Union{Vector,Matrix}; level::Bool=true, stochastic_level::Bool=true, trend::Bool=true, stochastic_trend::Bool=true, seasonal::Bool=true, stochastic_seasonal::Bool=true, - freq_seasonal::Int=12, + freq_seasonal::Union{Int,Vector{Int}}=12, outlier::Bool=true, ζ_ω_threshold::Int=12, - Exogenous_X::Matrix{Fl}=if typeof(y) <: Vector + Exogenous_X::Matrix=if typeof(y) <: Vector zeros(length(y), 0) else zeros(size(y, 1), 0) end, - ) where {Fl} + ) n_exogenous = size(Exogenous_X, 2) @assert !has_intercept(Exogenous_X) "Exogenous matrix must not have an intercept column" if typeof(y) <: Vector - @assert seasonal ? length(y) > freq_seasonal : true "Time series must be longer than the seasonal period" + @assert seasonal ? length(y) > minimum(freq_seasonal) : true "Time series must be longer than the seasonal period" else - @assert seasonal ? size(y, 1) > freq_seasonal : true "Time series must be longer than the seasonal period" + @assert seasonal ? size(y, 1) > minimum(freq_seasonal) : true "Time series must be longer than the seasonal period" end X = create_X( level, @@ -49,7 +100,6 @@ mutable struct StructuralModel <: StateSpaceLearningModel ζ_ω_threshold, Exogenous_X, ) - return new( y, X, @@ -161,7 +211,7 @@ function create_ζ(T::Int, steps_ahead::Int, ζ_ω_threshold::Int)::Matrix end """ -create_ω(T::Int, s::Int, steps_ahead::Int)::Matrix +create_ω(T::Int, freq_seasonal::Int, steps_ahead::Int, ζ_ω_threshold::Int)::Matrix Creates a matrix of innovations ω based on the input sizes, and the desired steps ahead (this is necessary for the forecast function). @@ -192,13 +242,15 @@ function create_ω(T::Int, freq_seasonal::Int, steps_ahead::Int, ζ_ω_threshold end """ - create_initial_states_Matrix(T::Int, s::Int, steps_ahead::Int, level::Bool, trend::Bool, seasonal::Bool)::Matrix + create_initial_states_Matrix( + T::Int, freq_seasonal::Union{Int, Vector{Int}}, steps_ahead::Int, level::Bool, trend::Bool, seasonal::Bool +)::Matrix Creates an initial states matrix based on the input parameters. # Arguments - `T::Int`: Length of the original time series. - - `freq_seasonal::Int`: Seasonal period. + - `freq_seasonal::Union{Int, Vector{Int}}`: Seasonal period. - `steps_ahead::Int`: Number of steps ahead. - `level::Bool`: Flag for considering level component. - `trend::Bool`: Flag for considering trend component. @@ -209,7 +261,12 @@ end """ function create_initial_states_Matrix( - T::Int, freq_seasonal::Int, steps_ahead::Int, level::Bool, trend::Bool, seasonal::Bool + T::Int, + freq_seasonal::Union{Int,Vector{Int}}, + steps_ahead::Int, + level::Bool, + trend::Bool, + seasonal::Bool, )::Matrix initial_states_matrix = zeros(T + steps_ahead, 0) if level @@ -226,11 +283,13 @@ function create_initial_states_Matrix( end if seasonal - γ1_matrix = zeros(T + steps_ahead, freq_seasonal) - for t in 1:(T + steps_ahead) - γ1_matrix[t, t % freq_seasonal == 0 ? freq_seasonal : t % freq_seasonal] = 1.0 + for s in freq_seasonal + γ1_matrix = zeros(T + steps_ahead, s) + for t in 1:(T + steps_ahead) + γ1_matrix[t, t % s == 0 ? s : t % s] = 1.0 + end + initial_states_matrix = hcat(initial_states_matrix, γ1_matrix) end - return hcat(initial_states_matrix, γ1_matrix) end return initial_states_matrix @@ -244,7 +303,7 @@ create_X( stochastic_trend::Bool, seasonal::Bool, stochastic_seasonal::Bool, - freq_seasonal::Int, + freq_seasonal::Union{Int, Vector{Int}}, outlier::Bool, ζ_ω_threshold::Int, Exogenous_X::Matrix{Fl}, @@ -261,7 +320,7 @@ create_X( - `stochastic_trend::Bool`: Flag for considering stochastic trend component. - `seasonal::Bool`: Flag for considering seasonal component. - `stochastic_seasonal::Bool`: Flag for considering stochastic seasonal component. - - `freq_seasonal::Int`: Seasonal period. + - `freq_seasonal::Union{Int, Vector{Int}}`: Seasonal period. - `outlier::Bool`: Flag for considering outlier component. - `ζ_ω_threshold::Int`: Stabilize parameter ζ. - `Exogenous_X::Matrix{Fl}`: Exogenous variables matrix. @@ -278,7 +337,7 @@ function create_X( stochastic_trend::Bool, seasonal::Bool, stochastic_seasonal::Bool, - freq_seasonal::Int, + freq_seasonal::Union{Int,Vector{Int}}, outlier::Bool, ζ_ω_threshold::Int, Exogenous_X::Matrix{Fl}, @@ -293,10 +352,12 @@ function create_X( else zeros(T + steps_ahead, 0) end - ω_matrix = if stochastic_seasonal - create_ω(T, freq_seasonal, steps_ahead, ζ_ω_threshold) - else - zeros(T + steps_ahead, 0) + + ω_matrix = zeros(T + steps_ahead, 0) + if stochastic_seasonal + for s in freq_seasonal + ω_matrix = hcat(ω_matrix, create_ω(T, s, steps_ahead, ζ_ω_threshold)) + end end o_matrix = outlier ? create_o_matrix(T, steps_ahead) : zeros(T + steps_ahead, 0) @@ -347,12 +408,16 @@ function get_components_indexes(model::StructuralModel)::Dict ν1_indexes = Int[] end + γ_indexes = Vector{Int}[] if model.seasonal - γ1_indexes = collect((FINAL_INDEX + 1):(FINAL_INDEX + model.freq_seasonal)) - initial_states_indexes = vcat(initial_states_indexes, γ1_indexes) - FINAL_INDEX += length(γ1_indexes) + for s in model.freq_seasonal + γ_s_indexes = collect((FINAL_INDEX + 1):(FINAL_INDEX + s)) + initial_states_indexes = vcat(initial_states_indexes, γ_s_indexes) + FINAL_INDEX += length(γ_s_indexes) + push!(γ_indexes, γ_s_indexes) + end else - γ1_indexes = Int[] + push!(γ_indexes, Int[]) end if model.stochastic_level @@ -371,15 +436,17 @@ function get_components_indexes(model::StructuralModel)::Dict ζ_indexes = Int[] end + ω_indexes = Vector{Int}[] if model.stochastic_seasonal - ω_indexes = collect( - (FINAL_INDEX + 1):(FINAL_INDEX + ω_size( - T, model.freq_seasonal, model.ζ_ω_threshold - )), - ) - FINAL_INDEX += length(ω_indexes) + for s in model.freq_seasonal + ω_s_indexes = collect( + (FINAL_INDEX + 1):(FINAL_INDEX + ω_size(T, s, model.ζ_ω_threshold)) + ) + FINAL_INDEX += length(ω_s_indexes) + push!(ω_indexes, ω_s_indexes) + end else - ω_indexes = Int[] + push!(ω_indexes, Int[]) end if model.outlier @@ -391,17 +458,22 @@ function get_components_indexes(model::StructuralModel)::Dict exogenous_indexes = collect((FINAL_INDEX + 1):(FINAL_INDEX + model.n_exogenous)) - return Dict( + components_indexes_dict = Dict( "μ1" => μ1_indexes, "ν1" => ν1_indexes, - "γ1" => γ1_indexes, "ξ" => ξ_indexes, "ζ" => ζ_indexes, - "ω" => ω_indexes, "o" => o_indexes, "Exogenous_X" => exogenous_indexes, "initial_states" => initial_states_indexes, ) + + for (i, s) in enumerate(model.freq_seasonal) + components_indexes_dict["γ1_$s"] = γ_indexes[i] + components_indexes_dict["ω_$s"] = ω_indexes[i] + end + + return components_indexes_dict end """ @@ -504,7 +576,9 @@ function get_model_innovations(model::StructuralModel) end if model.stochastic_seasonal - push!(model_innovations, "ω") + for s in model.freq_seasonal + push!(model_innovations, "ω_$s") + end end return model_innovations end @@ -529,8 +603,9 @@ function get_innovation_simulation_X( return create_ξ(length(model.y) + steps_ahead + 1, 0) elseif innovation == "ζ" return create_ζ(length(model.y) + steps_ahead + 1, 0, 1) - elseif innovation == "ω" - return create_ω(length(model.y) + steps_ahead + 1, model.freq_seasonal, 0, 1) + elseif occursin("ω_", innovation) + s = parse(Int, split(innovation, "_")[2]) + return create_ω(length(model.y) + steps_ahead + 1, s, 0, 1) end end diff --git a/src/plots.jl b/src/plots.jl new file mode 100644 index 0000000..1adaca3 --- /dev/null +++ b/src/plots.jl @@ -0,0 +1,7 @@ +function plot_point_forecast() + return nothing +end + +function plot_scenarios() + return nothing +end diff --git a/test/fit_forecast.jl b/test/fit_forecast.jl index 25849e3..06827c9 100644 --- a/test/fit_forecast.jl +++ b/test/fit_forecast.jl @@ -228,6 +228,12 @@ end 6.253, 6.384, ] + + model4 = StateSpaceLearning.StructuralModel(y3; freq_seasonal=[12, 36]) + StateSpaceLearning.fit!(model4) + forecast4 = trunc.(StateSpaceLearning.forecast(model4, 18); digits=3) + + @test length(forecast4) == 18 end @testset "Function: simulate" begin diff --git a/test/models/structural_model.jl b/test/models/structural_model.jl index 8c1be6d..382aba7 100644 --- a/test/models/structural_model.jl +++ b/test/models/structural_model.jl @@ -315,7 +315,7 @@ end models = [Basic_Structural, Local_Level, Local_Linear_Trend1, Local_Linear_Trend2] empty_keys_vec = [ - [], ["ν1", "ζ", "γ₁", "ω"], ["γ₁", "ω", "o"], ["γ₁", "ω", "o", "Exogenous_X"] + [], ["ν1", "ζ", "γ₁", "ω_2"], ["γ₁", "ω_2", "o"], ["γ₁", "ω_2", "o", "Exogenous_X"] ] exogs = [Exogenous_X1, Exogenous_X1, Exogenous_X1, Exogenous_X2] @@ -352,6 +352,19 @@ end ζ_ω_threshold=0, Exogenous_X=Exogenous_X2, ) + Basic_Structural2 = StateSpaceLearning.StructuralModel( + rand(10); + level=true, + stochastic_level=true, + trend=true, + stochastic_trend=true, + seasonal=true, + stochastic_seasonal=true, + freq_seasonal=[2, 5], + outlier=true, + ζ_ω_threshold=0, + Exogenous_X=Exogenous_X2, + ) Local_Level = StateSpaceLearning.StructuralModel( rand(10); level=true, @@ -379,15 +392,17 @@ end Exogenous_X=Exogenous_X2, ) - models = [Basic_Structural, Local_Level, Local_Linear_Trend] + models = [Basic_Structural, Basic_Structural2, Local_Level, Local_Linear_Trend] - params_vec = [["ξ", "ζ", "ω", "ε"], ["ξ", "ε"], ["ξ", "ζ", "ε"]] + params_vec = [ + ["ξ", "ζ", "ω_2", "ε"], ["ξ", "ζ", "ω_2", "ω_5", "ε"], ["ξ", "ε"], ["ξ", "ζ", "ε"] + ] for idx in eachindex(models) model = models[idx] components_indexes = StateSpaceLearning.get_components_indexes(model) variances = StateSpaceLearning.get_variances( - model, rand(100), rand(39), components_indexes + model, rand(100), rand(100), components_indexes ) @test all([key in keys(variances) for key in params_vec[idx]]) end @@ -446,10 +461,25 @@ end ζ_ω_threshold=0, Exogenous_X=zeros(10, 0), ) + model5 = StateSpaceLearning.StructuralModel( + rand(10); + level=true, + stochastic_level=true, + trend=true, + stochastic_trend=false, + seasonal=true, + stochastic_seasonal=true, + freq_seasonal=[2, 5], + outlier=true, + ζ_ω_threshold=0, + Exogenous_X=zeros(10, 0), + ) models = [model1, model2, model3, model4] - keys_vec = [["ξ", "ζ", "ω"], ["ζ", "ω"], ["ξ", "ω"], ["ξ", "ζ"]] + keys_vec = [ + ["ξ", "ζ", "ω_2"], ["ζ", "ω_2"], ["ξ", "ω_2"], ["ξ", "ζ"], ["ξ", "ω_2", "ω_5"] + ] for idx in eachindex(models) model = models[idx] @@ -461,7 +491,7 @@ end @testset "Function: get_innovation_simulation_X" begin innovation1 = "ξ" innovation2 = "ζ" - innovation3 = "ω" + innovation3 = "ω_2" model = StateSpaceLearning.StructuralModel( rand(3); diff --git a/test/utils.jl b/test/utils.jl index 3765d55..42ccfc8 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -108,7 +108,7 @@ end @testset "Function: fill_innovation_coefs" begin model = StateSpaceLearning.StructuralModel(rand(100)) StateSpaceLearning.fit!(model) - components = ["ξ", "ζ", "ω"] + components = ["ξ", "ζ", "ω_12"] valid_indexes = model.output.valid_indexes @@ -128,7 +128,7 @@ end model = StateSpaceLearning.StructuralModel(rand(100, 3)) StateSpaceLearning.fit!(model) - components = ["ξ", "ζ", "ω"] + components = ["ξ", "ζ", "ω_12"] valid_indexes = model.output[1].valid_indexes