first commit
This commit is contained in:
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
11
.idea/TimeSeriesAnalysis.iml
generated
Normal file
11
.idea/TimeSeriesAnalysis.iml
generated
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv1" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.13 (TimeSeriesAnalysis)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.13 (TimeSeriesAnalysis)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.13 (TimeSeriesAnalysis)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/TimeSeriesAnalysis.iml" filepath="$PROJECT_DIR$/.idea/TimeSeriesAnalysis.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
145
Uploads/airline_passengers.csv
Normal file
145
Uploads/airline_passengers.csv
Normal file
@ -0,0 +1,145 @@
|
||||
"Month","Thousands of Passengers"
|
||||
"1949-01",112
|
||||
"1949-02",118
|
||||
"1949-03",132
|
||||
"1949-04",129
|
||||
"1949-05",121
|
||||
"1949-06",135
|
||||
"1949-07",148
|
||||
"1949-08",148
|
||||
"1949-09",136
|
||||
"1949-10",119
|
||||
"1949-11",104
|
||||
"1949-12",118
|
||||
"1950-01",115
|
||||
"1950-02",126
|
||||
"1950-03",141
|
||||
"1950-04",135
|
||||
"1950-05",125
|
||||
"1950-06",149
|
||||
"1950-07",170
|
||||
"1950-08",170
|
||||
"1950-09",158
|
||||
"1950-10",133
|
||||
"1950-11",114
|
||||
"1950-12",140
|
||||
"1951-01",145
|
||||
"1951-02",150
|
||||
"1951-03",178
|
||||
"1951-04",163
|
||||
"1951-05",172
|
||||
"1951-06",178
|
||||
"1951-07",199
|
||||
"1951-08",199
|
||||
"1951-09",184
|
||||
"1951-10",162
|
||||
"1951-11",146
|
||||
"1951-12",166
|
||||
"1952-01",171
|
||||
"1952-02",180
|
||||
"1952-03",193
|
||||
"1952-04",181
|
||||
"1952-05",183
|
||||
"1952-06",218
|
||||
"1952-07",230
|
||||
"1952-08",242
|
||||
"1952-09",209
|
||||
"1952-10",191
|
||||
"1952-11",172
|
||||
"1952-12",194
|
||||
"1953-01",196
|
||||
"1953-02",196
|
||||
"1953-03",236
|
||||
"1953-04",235
|
||||
"1953-05",229
|
||||
"1953-06",243
|
||||
"1953-07",264
|
||||
"1953-08",272
|
||||
"1953-09",237
|
||||
"1953-10",211
|
||||
"1953-11",180
|
||||
"1953-12",201
|
||||
"1954-01",204
|
||||
"1954-02",188
|
||||
"1954-03",235
|
||||
"1954-04",227
|
||||
"1954-05",234
|
||||
"1954-06",264
|
||||
"1954-07",302
|
||||
"1954-08",293
|
||||
"1954-09",259
|
||||
"1954-10",229
|
||||
"1954-11",203
|
||||
"1954-12",229
|
||||
"1955-01",242
|
||||
"1955-02",233
|
||||
"1955-03",267
|
||||
"1955-04",269
|
||||
"1955-05",270
|
||||
"1955-06",315
|
||||
"1955-07",364
|
||||
"1955-08",347
|
||||
"1955-09",312
|
||||
"1955-10",274
|
||||
"1955-11",237
|
||||
"1955-12",278
|
||||
"1956-01",284
|
||||
"1956-02",277
|
||||
"1956-03",317
|
||||
"1956-04",313
|
||||
"1956-05",318
|
||||
"1956-06",374
|
||||
"1956-07",413
|
||||
"1956-08",405
|
||||
"1956-09",355
|
||||
"1956-10",306
|
||||
"1956-11",271
|
||||
"1956-12",306
|
||||
"1957-01",315
|
||||
"1957-02",301
|
||||
"1957-03",356
|
||||
"1957-04",348
|
||||
"1957-05",355
|
||||
"1957-06",422
|
||||
"1957-07",465
|
||||
"1957-08",467
|
||||
"1957-09",404
|
||||
"1957-10",347
|
||||
"1957-11",305
|
||||
"1957-12",336
|
||||
"1958-01",340
|
||||
"1958-02",318
|
||||
"1958-03",362
|
||||
"1958-04",348
|
||||
"1958-05",363
|
||||
"1958-06",435
|
||||
"1958-07",491
|
||||
"1958-08",505
|
||||
"1958-09",404
|
||||
"1958-10",359
|
||||
"1958-11",310
|
||||
"1958-12",337
|
||||
"1959-01",360
|
||||
"1959-02",342
|
||||
"1959-03",406
|
||||
"1959-04",396
|
||||
"1959-05",420
|
||||
"1959-06",472
|
||||
"1959-07",548
|
||||
"1959-08",559
|
||||
"1959-09",463
|
||||
"1959-10",407
|
||||
"1959-11",362
|
||||
"1959-12",405
|
||||
"1960-01",417
|
||||
"1960-02",391
|
||||
"1960-03",419
|
||||
"1960-04",461
|
||||
"1960-05",472
|
||||
"1960-06",535
|
||||
"1960-07",622
|
||||
"1960-08",606
|
||||
"1960-09",508
|
||||
"1960-10",461
|
||||
"1960-11",390
|
||||
"1960-12",432
|
||||
|
145
Uploads/processed_airline_passengers.csv
Normal file
145
Uploads/processed_airline_passengers.csv
Normal file
@ -0,0 +1,145 @@
|
||||
Month,Thousands of Passengers,Trend,Seasonality,Residuals
|
||||
1949-01-01,112,,-24.74873737373736,
|
||||
1949-02-01,118,,-36.18813131313131,
|
||||
1949-03-01,132,,-2.2411616161616195,
|
||||
1949-04-01,129,,-8.036616161616166,
|
||||
1949-05-01,121,,-4.5063131313131395,
|
||||
1949-06-01,135,,35.40277777777778,
|
||||
1949-07-01,148,126.79166666666666,63.83080808080808,-42.62247474747474
|
||||
1949-08-01,148,127.25,62.82323232323231,-42.07323232323231
|
||||
1949-09-01,136,127.95833333333331,16.52020202020202,-8.478535353535335
|
||||
1949-10-01,119,128.58333333333331,-20.642676767676765,11.05934343434345
|
||||
1949-11-01,104,129.0,-53.593434343434346,28.593434343434346
|
||||
1949-12-01,118,129.75,-28.619949494949505,16.869949494949505
|
||||
1950-01-01,115,131.25,-24.74873737373736,8.49873737373736
|
||||
1950-02-01,126,133.08333333333331,-36.18813131313131,29.104797979797993
|
||||
1950-03-01,141,134.91666666666666,-2.2411616161616195,8.324494949494962
|
||||
1950-04-01,135,136.41666666666666,-8.036616161616166,6.619949494949509
|
||||
1950-05-01,125,137.41666666666666,-4.5063131313131395,-7.910353535353518
|
||||
1950-06-01,149,138.75,35.40277777777778,-25.15277777777778
|
||||
1950-07-01,170,140.91666666666666,63.83080808080808,-34.74747474747474
|
||||
1950-08-01,170,143.16666666666666,62.82323232323231,-35.98989898989897
|
||||
1950-09-01,158,145.70833333333331,16.52020202020202,-4.228535353535335
|
||||
1950-10-01,133,148.41666666666666,-20.642676767676765,5.226010101010107
|
||||
1950-11-01,114,151.54166666666666,-53.593434343434346,16.05176767676769
|
||||
1950-12-01,140,154.70833333333331,-28.619949494949505,13.911616161616191
|
||||
1951-01-01,145,157.125,-24.74873737373736,12.62373737373736
|
||||
1951-02-01,150,159.54166666666666,-36.18813131313131,26.64646464646465
|
||||
1951-03-01,178,161.83333333333331,-2.2411616161616195,18.407828282828305
|
||||
1951-04-01,163,164.125,-8.036616161616166,6.911616161616166
|
||||
1951-05-01,172,166.66666666666666,-4.5063131313131395,9.839646464646481
|
||||
1951-06-01,178,169.08333333333331,35.40277777777778,-26.486111111111093
|
||||
1951-07-01,199,171.25,63.83080808080808,-36.08080808080808
|
||||
1951-08-01,199,173.58333333333331,62.82323232323231,-37.406565656565625
|
||||
1951-09-01,184,175.45833333333331,16.52020202020202,-7.978535353535335
|
||||
1951-10-01,162,176.83333333333331,-20.642676767676765,5.80934343434345
|
||||
1951-11-01,146,178.04166666666666,-53.593434343434346,21.55176767676769
|
||||
1951-12-01,166,180.16666666666663,-28.619949494949505,14.453282828282877
|
||||
1952-01-01,171,183.12499999999997,-24.74873737373736,12.623737373737388
|
||||
1952-02-01,180,186.20833333333331,-36.18813131313131,29.979797979797993
|
||||
1952-03-01,193,189.04166666666663,-2.2411616161616195,6.199494949494991
|
||||
1952-04-01,181,191.29166666666666,-8.036616161616166,-2.255050505050491
|
||||
1952-05-01,183,193.58333333333331,-4.5063131313131395,-6.077020202020175
|
||||
1952-06-01,218,195.83333333333331,35.40277777777778,-13.236111111111093
|
||||
1952-07-01,230,198.04166666666663,63.83080808080808,-31.872474747474712
|
||||
1952-08-01,242,199.75,62.82323232323231,-20.57323232323231
|
||||
1952-09-01,209,202.20833333333331,16.52020202020202,-9.728535353535335
|
||||
1952-10-01,191,206.25,-20.642676767676765,5.392676767676765
|
||||
1952-11-01,172,210.41666666666666,-53.593434343434346,15.176767676767689
|
||||
1952-12-01,194,213.375,-28.619949494949505,9.244949494949505
|
||||
1953-01-01,196,215.83333333333331,-24.74873737373736,4.915404040404045
|
||||
1953-02-01,196,218.5,-36.18813131313131,13.688131313131308
|
||||
1953-03-01,236,220.91666666666666,-2.2411616161616195,17.324494949494962
|
||||
1953-04-01,235,222.91666666666666,-8.036616161616166,20.11994949494951
|
||||
1953-05-01,229,224.08333333333331,-4.5063131313131395,9.422979797979824
|
||||
1953-06-01,243,224.70833333333331,35.40277777777778,-17.111111111111093
|
||||
1953-07-01,264,225.33333333333331,63.83080808080808,-25.164141414141397
|
||||
1953-08-01,272,225.33333333333331,62.82323232323231,-16.156565656565625
|
||||
1953-09-01,237,224.95833333333331,16.52020202020202,-4.478535353535335
|
||||
1953-10-01,211,224.58333333333331,-20.642676767676765,7.05934343434345
|
||||
1953-11-01,180,224.45833333333331,-53.593434343434346,9.135101010101032
|
||||
1953-12-01,201,225.54166666666666,-28.619949494949505,4.078282828282848
|
||||
1954-01-01,204,227.99999999999997,-24.74873737373736,0.7487373737373879
|
||||
1954-02-01,188,230.45833333333331,-36.18813131313131,-6.270202020202007
|
||||
1954-03-01,235,232.25,-2.2411616161616195,4.9911616161616195
|
||||
1954-04-01,227,233.91666666666666,-8.036616161616166,1.119949494949509
|
||||
1954-05-01,234,235.62499999999997,-4.5063131313131395,2.881313131313168
|
||||
1954-06-01,264,237.75,35.40277777777778,-9.152777777777779
|
||||
1954-07-01,302,240.49999999999997,63.83080808080808,-2.3308080808080547
|
||||
1954-08-01,293,243.95833333333331,62.82323232323231,-13.781565656565625
|
||||
1954-09-01,259,247.16666666666666,16.52020202020202,-4.686868686868678
|
||||
1954-10-01,229,250.25,-20.642676767676765,-0.6073232323232354
|
||||
1954-11-01,203,253.5,-53.593434343434346,3.093434343434346
|
||||
1954-12-01,229,257.125,-28.619949494949505,0.49494949494950546
|
||||
1955-01-01,242,261.83333333333326,-24.74873737373736,4.915404040404102
|
||||
1955-02-01,233,266.66666666666663,-36.18813131313131,2.521464646464679
|
||||
1955-03-01,267,271.125,-2.2411616161616195,-1.8838383838383805
|
||||
1955-04-01,269,275.2083333333333,-8.036616161616166,1.8282828282828518
|
||||
1955-05-01,270,278.5,-4.5063131313131395,-3.9936868686868605
|
||||
1955-06-01,315,281.9583333333333,35.40277777777778,-2.361111111111093
|
||||
1955-07-01,364,285.75,63.83080808080808,14.419191919191917
|
||||
1955-08-01,347,289.3333333333333,62.82323232323231,-5.1565656565656255
|
||||
1955-09-01,312,293.25,16.52020202020202,2.2297979797979792
|
||||
1955-10-01,274,297.16666666666663,-20.642676767676765,-2.523989898989864
|
||||
1955-11-01,237,301.0,-53.593434343434346,-10.406565656565654
|
||||
1955-12-01,278,305.4583333333333,-28.619949494949505,1.161616161616191
|
||||
1956-01-01,284,309.9583333333333,-24.74873737373736,-1.209595959595955
|
||||
1956-02-01,277,314.41666666666663,-36.18813131313131,-1.228535353535321
|
||||
1956-03-01,317,318.625,-2.2411616161616195,0.6161616161616195
|
||||
1956-04-01,313,321.75,-8.036616161616166,-0.7133838383838338
|
||||
1956-05-01,318,324.5,-4.5063131313131395,-1.9936868686868605
|
||||
1956-06-01,374,327.0833333333333,35.40277777777778,11.513888888888907
|
||||
1956-07-01,413,329.54166666666663,63.83080808080808,19.627525252525288
|
||||
1956-08-01,405,331.8333333333333,62.82323232323231,10.343434343434375
|
||||
1956-09-01,355,334.4583333333333,16.52020202020202,4.021464646464665
|
||||
1956-10-01,306,337.54166666666663,-20.642676767676765,-10.898989898989864
|
||||
1956-11-01,271,340.54166666666663,-53.593434343434346,-15.948232323232283
|
||||
1956-12-01,306,344.0833333333333,-28.619949494949505,-9.463383838383809
|
||||
1957-01-01,315,348.25,-24.74873737373736,-8.50126262626264
|
||||
1957-02-01,301,353.0,-36.18813131313131,-15.811868686868692
|
||||
1957-03-01,356,357.62499999999994,-2.2411616161616195,0.6161616161616763
|
||||
1957-04-01,348,361.375,-8.036616161616166,-5.338383838383834
|
||||
1957-05-01,355,364.5,-4.5063131313131395,-4.9936868686868605
|
||||
1957-06-01,422,367.16666666666663,35.40277777777778,19.430555555555593
|
||||
1957-07-01,465,369.4583333333333,63.83080808080808,31.710858585858603
|
||||
1957-08-01,467,371.2083333333333,62.82323232323231,32.968434343434375
|
||||
1957-09-01,404,372.16666666666663,16.52020202020202,15.31313131313135
|
||||
1957-10-01,347,372.41666666666663,-20.642676767676765,-4.773989898989864
|
||||
1957-11-01,305,372.75,-53.593434343434346,-14.156565656565654
|
||||
1957-12-01,336,373.625,-28.619949494949505,-9.005050505050495
|
||||
1958-01-01,340,375.25,-24.74873737373736,-10.50126262626264
|
||||
1958-02-01,318,377.91666666666663,-36.18813131313131,-23.72853535353532
|
||||
1958-03-01,362,379.5,-2.2411616161616195,-15.25883838383838
|
||||
1958-04-01,348,380.0,-8.036616161616166,-23.963383838383834
|
||||
1958-05-01,363,380.70833333333337,-4.5063131313131395,-13.202020202020233
|
||||
1958-06-01,435,380.9583333333333,35.40277777777778,18.638888888888907
|
||||
1958-07-01,491,381.8333333333333,63.83080808080808,45.3358585858586
|
||||
1958-08-01,505,383.66666666666663,62.82323232323231,58.51010101010106
|
||||
1958-09-01,404,386.5,16.52020202020202,0.9797979797979792
|
||||
1958-10-01,359,390.3333333333333,-20.642676767676765,-10.69065656565655
|
||||
1958-11-01,310,394.7083333333333,-53.593434343434346,-31.11489898989897
|
||||
1958-12-01,337,398.625,-28.619949494949505,-33.00505050505049
|
||||
1959-01-01,360,402.5416666666666,-24.74873737373736,-17.792929292929212
|
||||
1959-02-01,342,407.16666666666663,-36.18813131313131,-28.97853535353532
|
||||
1959-03-01,406,411.875,-2.2411616161616195,-3.6338383838383805
|
||||
1959-04-01,396,416.33333333333326,-8.036616161616166,-12.296717171717091
|
||||
1959-05-01,420,420.49999999999994,-4.5063131313131395,4.006313131313196
|
||||
1959-06-01,472,425.5,35.40277777777778,11.097222222222221
|
||||
1959-07-01,548,430.70833333333326,63.83080808080808,53.46085858585866
|
||||
1959-08-01,559,435.125,62.82323232323231,61.05176767676769
|
||||
1959-09-01,463,437.7083333333333,16.52020202020202,8.771464646464665
|
||||
1959-10-01,407,440.9583333333333,-20.642676767676765,-13.31565656565655
|
||||
1959-11-01,362,445.8333333333333,-53.593434343434346,-30.23989898989897
|
||||
1959-12-01,405,450.625,-28.619949494949505,-17.005050505050495
|
||||
1960-01-01,417,456.33333333333326,-24.74873737373736,-14.584595959595898
|
||||
1960-02-01,391,461.37499999999994,-36.18813131313131,-34.186868686868635
|
||||
1960-03-01,419,465.2083333333333,-2.2411616161616195,-43.967171717171695
|
||||
1960-04-01,461,469.3333333333333,-8.036616161616166,-0.2967171717171482
|
||||
1960-05-01,472,472.75,-4.5063131313131395,3.7563131313131395
|
||||
1960-06-01,535,475.04166666666663,35.40277777777778,24.555555555555593
|
||||
1960-07-01,622,,63.83080808080808,
|
||||
1960-08-01,606,,62.82323232323231,
|
||||
1960-09-01,508,,16.52020202020202,
|
||||
1960-10-01,461,,-20.642676767676765,
|
||||
1960-11-01,390,,-53.593434343434346,
|
||||
1960-12-01,432,,-28.619949494949505,
|
||||
|
285
app.py
Normal file
285
app.py
Normal file
@ -0,0 +1,285 @@
|
||||
from flask import Flask, request, render_template, send_file, session
|
||||
import pandas as pd
|
||||
import io
|
||||
import os
|
||||
from statsmodels.tsa.seasonal import seasonal_decompose
|
||||
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
|
||||
import pmdarima as pm
|
||||
import plotly.express as px
|
||||
import plotly.graph_objects as go
|
||||
from plotly.subplots import make_subplots
|
||||
import plotly.io as pio
|
||||
from werkzeug.utils import secure_filename
|
||||
import matplotlib
|
||||
|
||||
matplotlib.use('Agg') # Use non-interactive backend
|
||||
import matplotlib.pyplot as plt
|
||||
import io
|
||||
import base64
|
||||
import numpy as np
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['UPLOAD_FOLDER'] = 'Uploads'
|
||||
app.config['ALLOWED_EXTENSIONS'] = {'csv', 'xls', 'xlsx'}
|
||||
app.secret_key = 'your-secret-key' # Required for session management
|
||||
|
||||
# Ensure upload folder exists
|
||||
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
||||
|
||||
|
||||
def allowed_file(filename):
|
||||
return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']
|
||||
|
||||
|
||||
def create_acf_pacf_plots(data):
|
||||
# Create ACF and PACF plots using matplotlib
|
||||
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))
|
||||
|
||||
plot_acf(data, ax=ax1, lags=40)
|
||||
ax1.set_title('Autocorrelation Function')
|
||||
|
||||
plot_pacf(data, ax=ax2, lags=40)
|
||||
ax2.set_title('Partial Autocorrelation Function')
|
||||
|
||||
# Convert matplotlib plot to Plotly
|
||||
buf = io.BytesIO()
|
||||
plt.savefig(buf, format='png')
|
||||
plt.close(fig)
|
||||
buf.seek(0)
|
||||
img_str = base64.b64encode(buf.getvalue()).decode('utf-8')
|
||||
|
||||
# Create Plotly figure with image
|
||||
fig_plotly = go.Figure()
|
||||
fig_plotly.add_layout_image(
|
||||
dict(
|
||||
source=f'data:image/png;base64,{img_str}',
|
||||
x=0,
|
||||
y=1,
|
||||
xref="paper",
|
||||
yref="paper",
|
||||
sizex=1,
|
||||
sizey=1,
|
||||
sizing="stretch",
|
||||
opacity=1,
|
||||
layer="below"
|
||||
)
|
||||
)
|
||||
fig_plotly.update_layout(
|
||||
height=600,
|
||||
showlegend=False,
|
||||
xaxis=dict(visible=False),
|
||||
yaxis=dict(visible=False)
|
||||
)
|
||||
return pio.to_html(fig_plotly, full_html=False)
|
||||
|
||||
|
||||
def process_time_series(filepath, do_decomposition, do_forecasting, do_acf_pacf, train_percent, forecast_periods):
|
||||
try:
|
||||
# Read file
|
||||
if filepath.endswith('.csv'):
|
||||
df = pd.read_csv(filepath)
|
||||
else:
|
||||
df = pd.read_excel(filepath)
|
||||
|
||||
# Ensure datetime column exists
|
||||
date_col = df.columns[0] # Assume first column is date
|
||||
value_col = df.columns[1] # Assume second column is value
|
||||
df[date_col] = pd.to_datetime(df[date_col])
|
||||
df.set_index(date_col, inplace=True)
|
||||
|
||||
# Initialize variables
|
||||
plot_html = None
|
||||
forecast_html = None
|
||||
acf_pacf_html = None
|
||||
summary = df[value_col].describe().to_dict()
|
||||
arima_params = None
|
||||
seasonal_params = None
|
||||
train_size = None
|
||||
test_size = None
|
||||
|
||||
# Save processed data
|
||||
processed_df = df.copy()
|
||||
|
||||
# Time series decomposition
|
||||
if do_decomposition:
|
||||
decomposition = seasonal_decompose(df[value_col], model='additive', period=12)
|
||||
fig = make_subplots(rows=4, cols=1,
|
||||
subplot_titles=('Original Series', 'Trend', 'Seasonality', 'Residuals'))
|
||||
|
||||
fig.add_trace(go.Scatter(x=df.index, y=df[value_col], name='Original'), row=1, col=1)
|
||||
fig.add_trace(go.Scatter(x=df.index, y=decomposition.trend, name='Trend'), row=2, col=1)
|
||||
fig.add_trace(go.Scatter(x=df.index, y=decomposition.seasonal, name='Seasonality'), row=3, col=1)
|
||||
fig.add_trace(go.Scatter(x=df.index, y=decomposition.resid, name='Residuals'), row=4, col=1)
|
||||
|
||||
fig.update_layout(height=800, showlegend=True)
|
||||
plot_html = pio.to_html(fig, full_html=False)
|
||||
|
||||
processed_df['Trend'] = decomposition.trend
|
||||
processed_df['Seasonality'] = decomposition.seasonal
|
||||
processed_df['Residuals'] = decomposition.resid
|
||||
|
||||
# Forecasting
|
||||
if do_forecasting:
|
||||
# Split data into train and test
|
||||
train_size = int(len(df) * train_percent)
|
||||
test_size = len(df) - train_size
|
||||
train_data = df[value_col].iloc[:train_size]
|
||||
test_data = df[value_col].iloc[train_size:] if test_size > 0 else pd.Series()
|
||||
|
||||
# Auto ARIMA for best parameters
|
||||
model = pm.auto_arima(train_data,
|
||||
seasonal=True,
|
||||
m=12,
|
||||
start_p=0, start_q=0,
|
||||
max_p=3, max_q=3,
|
||||
start_P=0, start_Q=0,
|
||||
max_P=2, max_Q=2,
|
||||
d=1, D=1,
|
||||
trace=False,
|
||||
error_action='ignore',
|
||||
suppress_warnings=True,
|
||||
stepwise=True)
|
||||
|
||||
# Fit ARIMA with best parameters
|
||||
model_fit = model.fit(train_data)
|
||||
forecast = model_fit.predict(n_periods=forecast_periods)
|
||||
|
||||
# Get ARIMA parameters
|
||||
arima_params = model.order
|
||||
seasonal_params = model.seasonal_order
|
||||
|
||||
# Forecast plot
|
||||
forecast_dates = pd.date_range(start=df.index[-1], periods=forecast_periods + 1,
|
||||
freq=df.index.inferred_freq)[1:]
|
||||
forecast_fig = go.Figure()
|
||||
forecast_fig.add_trace(go.Scatter(x=df.index, y=df[value_col], name='Historical'))
|
||||
if test_size > 0:
|
||||
forecast_fig.add_trace(
|
||||
go.Scatter(x=df.index[train_size:], y=test_data, name='Test Data', line=dict(color='green')))
|
||||
forecast_fig.add_trace(go.Scatter(x=forecast_dates, y=forecast, name='Forecast', line=dict(dash='dash')))
|
||||
forecast_fig.update_layout(title=f'Forecast (ARIMA{arima_params}, Seasonal{seasonal_params})', height=400)
|
||||
forecast_html = pio.to_html(forecast_fig, full_html=False)
|
||||
|
||||
# ACF/PACF plots
|
||||
if do_acf_pacf:
|
||||
acf_pacf_html = create_acf_pacf_plots(df[value_col])
|
||||
|
||||
# Save processed data
|
||||
processed_df.to_csv(os.path.join(app.config['UPLOAD_FOLDER'], 'processed_' + os.path.basename(filepath)))
|
||||
|
||||
return {
|
||||
'plot_html': plot_html,
|
||||
'forecast_html': forecast_html,
|
||||
'acf_pacf_html': acf_pacf_html,
|
||||
'summary': summary,
|
||||
'filename': 'processed_' + os.path.basename(filepath),
|
||||
'arima_params': arima_params,
|
||||
'seasonal_params': seasonal_params,
|
||||
'train_size': train_size,
|
||||
'test_size': test_size
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return {'error': str(e)}
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
|
||||
@app.route('/upload', methods=['POST'])
|
||||
def upload_file():
|
||||
if 'file' not in request.files:
|
||||
return render_template('index.html', error='No file part')
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return render_template('index.html', error='No selected file')
|
||||
|
||||
if file and allowed_file(file.filename):
|
||||
filename = secure_filename(file.filename)
|
||||
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||
file.save(filepath)
|
||||
session['filepath'] = filepath # Store filepath in session
|
||||
|
||||
# Get user selections
|
||||
do_decomposition = 'decomposition' in request.form
|
||||
do_forecasting = 'forecasting' in request.form
|
||||
do_acf_pacf = 'acf_pacf' in request.form
|
||||
train_percent = float(request.form.get('train_percent', 80)) / 100
|
||||
test_percent = float(request.form.get('test_percent', 20)) / 100
|
||||
|
||||
# Validate train/test percentages
|
||||
if abs(train_percent + test_percent - 1.0) > 0.01: # Allow small float precision errors
|
||||
return render_template('index.html', error='Train and test percentages must sum to 100%')
|
||||
|
||||
session['do_decomposition'] = do_decomposition
|
||||
session['do_forecasting'] = do_forecasting
|
||||
session['do_acf_pacf'] = do_acf_pacf
|
||||
|
||||
result = process_time_series(filepath, do_decomposition, do_forecasting, do_acf_pacf, train_percent,
|
||||
forecast_periods=int(request.form.get('forecast_periods', 12)))
|
||||
|
||||
if 'error' in result:
|
||||
return render_template('index.html', error=result['error'])
|
||||
|
||||
return render_template('results.html',
|
||||
do_decomposition=do_decomposition,
|
||||
do_forecasting=do_forecasting,
|
||||
do_acf_pacf=do_acf_pacf,
|
||||
train_percent=train_percent * 100,
|
||||
test_percent=test_percent * 100,
|
||||
forecast_periods=int(request.form.get('forecast_periods', 12)),
|
||||
**result)
|
||||
|
||||
|
||||
@app.route('/reforecast', methods=['POST'])
|
||||
def reforecast():
|
||||
filepath = session.get('filepath')
|
||||
if not filepath or not os.path.exists(filepath):
|
||||
return render_template('index.html', error='Session expired or file not found. Please upload the file again.')
|
||||
|
||||
# Get user selections from reforecast form
|
||||
train_percent = float(request.form.get('train_percent', 80)) / 100
|
||||
test_percent = float(request.form.get('test_percent', 20)) / 100
|
||||
forecast_periods = int(request.form.get('forecast_periods', 12))
|
||||
|
||||
# Validate train/test percentages
|
||||
if abs(train_percent + test_percent - 1.0) > 0.01: # Allow small float precision errors
|
||||
return render_template('index.html', error='Train and test percentages must sum to 100%')
|
||||
|
||||
# Get original selections from session or defaults
|
||||
do_decomposition = session.get('do_decomposition', False)
|
||||
do_forecasting = True # Since this is a reforecast
|
||||
do_acf_pacf = session.get('do_acf_pacf', False)
|
||||
|
||||
result = process_time_series(filepath, do_decomposition, do_forecasting, do_acf_pacf, train_percent,
|
||||
forecast_periods)
|
||||
|
||||
if 'error' in result:
|
||||
return render_template('index.html', error=result['error'])
|
||||
|
||||
# Update session with new parameters
|
||||
session['train_percent'] = train_percent
|
||||
session['test_percent'] = test_percent
|
||||
session['forecast_periods'] = forecast_periods
|
||||
|
||||
return render_template('results.html',
|
||||
do_decomposition=do_decomposition,
|
||||
do_forecasting=do_forecasting,
|
||||
do_acf_pacf=do_acf_pacf,
|
||||
train_percent=train_percent * 100,
|
||||
test_percent=test_percent * 100,
|
||||
forecast_periods=forecast_periods,
|
||||
**result)
|
||||
|
||||
|
||||
@app.route('/download/<filename>')
|
||||
def download_file(filename):
|
||||
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||
return send_file(filepath, as_attachment=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
76
templates/index.html
Normal file
76
templates/index.html
Normal file
@ -0,0 +1,76 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Time Series Analysis</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5">
|
||||
<h1 class="mb-4">Time Series Analysis App</h1>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Upload Time Series Data</h5>
|
||||
<p class="card-text">Upload a CSV or Excel file with time series data. First column should be dates, second column should be values.</p>
|
||||
<form method="post" enctype="multipart/form-data" action="/upload">
|
||||
<div class="mb-3">
|
||||
<input type="file" class="form-control" name="file" accept=".csv,.xls,.xlsx">
|
||||
</div>
|
||||
<h6 class="mt-3">Select Analyses:</h6>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="decomposition" id="decomposition" checked>
|
||||
<label class="form-check-label" for="decomposition">
|
||||
Time Series Decomposition (Trend, Seasonality, Residuals)
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="forecasting" id="forecasting" checked>
|
||||
<label class="form-check-label" for="forecasting">
|
||||
Forecasting
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="acf_pacf" id="acf_pacf" checked>
|
||||
<label class="form-check-label" for="acf_pacf">
|
||||
ACF and PACF Plots
|
||||
</label>
|
||||
</div>
|
||||
<div class="mt-3" id="forecast_options" style="display: none;">
|
||||
<h6>Forecasting Options:</h6>
|
||||
<div class="mb-3">
|
||||
<label for="train_percent" class="form-label">Training Data Percentage (50-95%):</label>
|
||||
<input type="number" class="form-control" name="train_percent" id="train_percent" value="80" min="50" max="95" step="1">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="test_percent" class="form-label">Test Data Percentage (5-50%):</label>
|
||||
<input type="number" class="form-control" name="test_percent" id="test_percent" value="20" min="5" max="50" step="1">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="forecast_periods" class="form-label">Number of Periods to Forecast (1-24):</label>
|
||||
<input type="number" class="form-control" name="forecast_periods" id="forecast_periods" value="12" min="1" max="24" step="1">
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mt-3">Analyze</button>
|
||||
</form>
|
||||
{% if error %}
|
||||
<div class="alert alert-danger mt-3">{{ error }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Show/hide forecasting options based on checkbox
|
||||
document.getElementById('forecasting').addEventListener('change', function() {
|
||||
document.getElementById('forecast_options').style.display = this.checked ? 'block' : 'none';
|
||||
});
|
||||
// Ensure train and test percentages sum to 100
|
||||
const trainInput = document.getElementById('train_percent');
|
||||
const testInput = document.getElementById('test_percent');
|
||||
trainInput.addEventListener('input', function() {
|
||||
testInput.value = (100 - parseFloat(this.value)).toFixed(0);
|
||||
});
|
||||
testInput.addEventListener('input', function() {
|
||||
trainInput.value = (100 - parseFloat(this.value)).toFixed(0);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
87
templates/results.html
Normal file
87
templates/results.html
Normal file
@ -0,0 +1,87 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Analysis Results</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="https://cdn.plot.ly/plotly-2.20.0.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container mt-5">
|
||||
<h1 class="mb-4">Time Series Analysis Results</h1>
|
||||
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Summary Statistics</h5>
|
||||
<table class="table">
|
||||
{% for key, value in summary.items() %}
|
||||
<tr>
|
||||
<td>{{ key }}</td>
|
||||
<td>{{ value|round(2) }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if do_decomposition %}
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Time Series Decomposition</h5>
|
||||
{{ plot_html | safe }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if do_forecasting %}
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Forecast (ARIMA{{ arima_params }}, Seasonal{{ seasonal_params }})</h5>
|
||||
<form method="post" action="/reforecast">
|
||||
<div class="mb-3">
|
||||
<label for="train_percent" class="form-label">Training Data Percentage (50-95%):</label>
|
||||
<input type="number" class="form-control" name="train_percent" id="train_percent" value="{{ train_percent }}" min="50" max="95" step="1">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="test_percent" class="form-label">Test Data Percentage (5-50%):</label>
|
||||
<input type="number" class="form-control" name="test_percent" id="test_percent" value="{{ test_percent }}" min="5" max="50" step="1">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="forecast_periods" class="form-label">Number of Periods to Forecast (1-24):</label>
|
||||
<input type="number" class="form-control" name="forecast_periods" id="forecast_periods" value="{{ forecast_periods }}" min="1" max="24" step="1">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Re-run Forecast</button>
|
||||
</form>
|
||||
<hr>
|
||||
<p>Training Data: {{ train_percent }}% ({{ train_size }} observations)</p>
|
||||
<p>Test Data: {{ test_percent }}% ({{ test_size }} observations)</p>
|
||||
<p>Forecast Periods: {{ forecast_periods }}</p>
|
||||
{{ forecast_html | safe }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if do_acf_pacf %}
|
||||
<div class="card mb-4">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">ACF and PACF Plots</h5>
|
||||
{{ acf_pacf_html | safe }}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<a href="/download/{{ filename }}" class="btn btn-primary">Download Processed Data</a>
|
||||
<a href="/" class="btn btn-secondary">Upload Another File</a>
|
||||
</div>
|
||||
<script>
|
||||
// Ensure train and test percentages sum to 100
|
||||
const trainInput = document.getElementById('train_percent');
|
||||
const testInput = document.getElementById('test_percent');
|
||||
trainInput.addEventListener('input', function() {
|
||||
testInput.value = (100 - parseFloat(this.value)).toFixed(0);
|
||||
});
|
||||
testInput.addEventListener('input', function() {
|
||||
trainInput.value = (100 - parseFloat(this.value)).toFixed(0);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
145
uploads/airline_passengers.csv
Normal file
145
uploads/airline_passengers.csv
Normal file
@ -0,0 +1,145 @@
|
||||
"Month","Thousands of Passengers"
|
||||
"1949-01",112
|
||||
"1949-02",118
|
||||
"1949-03",132
|
||||
"1949-04",129
|
||||
"1949-05",121
|
||||
"1949-06",135
|
||||
"1949-07",148
|
||||
"1949-08",148
|
||||
"1949-09",136
|
||||
"1949-10",119
|
||||
"1949-11",104
|
||||
"1949-12",118
|
||||
"1950-01",115
|
||||
"1950-02",126
|
||||
"1950-03",141
|
||||
"1950-04",135
|
||||
"1950-05",125
|
||||
"1950-06",149
|
||||
"1950-07",170
|
||||
"1950-08",170
|
||||
"1950-09",158
|
||||
"1950-10",133
|
||||
"1950-11",114
|
||||
"1950-12",140
|
||||
"1951-01",145
|
||||
"1951-02",150
|
||||
"1951-03",178
|
||||
"1951-04",163
|
||||
"1951-05",172
|
||||
"1951-06",178
|
||||
"1951-07",199
|
||||
"1951-08",199
|
||||
"1951-09",184
|
||||
"1951-10",162
|
||||
"1951-11",146
|
||||
"1951-12",166
|
||||
"1952-01",171
|
||||
"1952-02",180
|
||||
"1952-03",193
|
||||
"1952-04",181
|
||||
"1952-05",183
|
||||
"1952-06",218
|
||||
"1952-07",230
|
||||
"1952-08",242
|
||||
"1952-09",209
|
||||
"1952-10",191
|
||||
"1952-11",172
|
||||
"1952-12",194
|
||||
"1953-01",196
|
||||
"1953-02",196
|
||||
"1953-03",236
|
||||
"1953-04",235
|
||||
"1953-05",229
|
||||
"1953-06",243
|
||||
"1953-07",264
|
||||
"1953-08",272
|
||||
"1953-09",237
|
||||
"1953-10",211
|
||||
"1953-11",180
|
||||
"1953-12",201
|
||||
"1954-01",204
|
||||
"1954-02",188
|
||||
"1954-03",235
|
||||
"1954-04",227
|
||||
"1954-05",234
|
||||
"1954-06",264
|
||||
"1954-07",302
|
||||
"1954-08",293
|
||||
"1954-09",259
|
||||
"1954-10",229
|
||||
"1954-11",203
|
||||
"1954-12",229
|
||||
"1955-01",242
|
||||
"1955-02",233
|
||||
"1955-03",267
|
||||
"1955-04",269
|
||||
"1955-05",270
|
||||
"1955-06",315
|
||||
"1955-07",364
|
||||
"1955-08",347
|
||||
"1955-09",312
|
||||
"1955-10",274
|
||||
"1955-11",237
|
||||
"1955-12",278
|
||||
"1956-01",284
|
||||
"1956-02",277
|
||||
"1956-03",317
|
||||
"1956-04",313
|
||||
"1956-05",318
|
||||
"1956-06",374
|
||||
"1956-07",413
|
||||
"1956-08",405
|
||||
"1956-09",355
|
||||
"1956-10",306
|
||||
"1956-11",271
|
||||
"1956-12",306
|
||||
"1957-01",315
|
||||
"1957-02",301
|
||||
"1957-03",356
|
||||
"1957-04",348
|
||||
"1957-05",355
|
||||
"1957-06",422
|
||||
"1957-07",465
|
||||
"1957-08",467
|
||||
"1957-09",404
|
||||
"1957-10",347
|
||||
"1957-11",305
|
||||
"1957-12",336
|
||||
"1958-01",340
|
||||
"1958-02",318
|
||||
"1958-03",362
|
||||
"1958-04",348
|
||||
"1958-05",363
|
||||
"1958-06",435
|
||||
"1958-07",491
|
||||
"1958-08",505
|
||||
"1958-09",404
|
||||
"1958-10",359
|
||||
"1958-11",310
|
||||
"1958-12",337
|
||||
"1959-01",360
|
||||
"1959-02",342
|
||||
"1959-03",406
|
||||
"1959-04",396
|
||||
"1959-05",420
|
||||
"1959-06",472
|
||||
"1959-07",548
|
||||
"1959-08",559
|
||||
"1959-09",463
|
||||
"1959-10",407
|
||||
"1959-11",362
|
||||
"1959-12",405
|
||||
"1960-01",417
|
||||
"1960-02",391
|
||||
"1960-03",419
|
||||
"1960-04",461
|
||||
"1960-05",472
|
||||
"1960-06",535
|
||||
"1960-07",622
|
||||
"1960-08",606
|
||||
"1960-09",508
|
||||
"1960-10",461
|
||||
"1960-11",390
|
||||
"1960-12",432
|
||||
|
145
uploads/processed_airline_passengers.csv
Normal file
145
uploads/processed_airline_passengers.csv
Normal file
@ -0,0 +1,145 @@
|
||||
Month,Thousands of Passengers
|
||||
1949-01-01,112
|
||||
1949-02-01,118
|
||||
1949-03-01,132
|
||||
1949-04-01,129
|
||||
1949-05-01,121
|
||||
1949-06-01,135
|
||||
1949-07-01,148
|
||||
1949-08-01,148
|
||||
1949-09-01,136
|
||||
1949-10-01,119
|
||||
1949-11-01,104
|
||||
1949-12-01,118
|
||||
1950-01-01,115
|
||||
1950-02-01,126
|
||||
1950-03-01,141
|
||||
1950-04-01,135
|
||||
1950-05-01,125
|
||||
1950-06-01,149
|
||||
1950-07-01,170
|
||||
1950-08-01,170
|
||||
1950-09-01,158
|
||||
1950-10-01,133
|
||||
1950-11-01,114
|
||||
1950-12-01,140
|
||||
1951-01-01,145
|
||||
1951-02-01,150
|
||||
1951-03-01,178
|
||||
1951-04-01,163
|
||||
1951-05-01,172
|
||||
1951-06-01,178
|
||||
1951-07-01,199
|
||||
1951-08-01,199
|
||||
1951-09-01,184
|
||||
1951-10-01,162
|
||||
1951-11-01,146
|
||||
1951-12-01,166
|
||||
1952-01-01,171
|
||||
1952-02-01,180
|
||||
1952-03-01,193
|
||||
1952-04-01,181
|
||||
1952-05-01,183
|
||||
1952-06-01,218
|
||||
1952-07-01,230
|
||||
1952-08-01,242
|
||||
1952-09-01,209
|
||||
1952-10-01,191
|
||||
1952-11-01,172
|
||||
1952-12-01,194
|
||||
1953-01-01,196
|
||||
1953-02-01,196
|
||||
1953-03-01,236
|
||||
1953-04-01,235
|
||||
1953-05-01,229
|
||||
1953-06-01,243
|
||||
1953-07-01,264
|
||||
1953-08-01,272
|
||||
1953-09-01,237
|
||||
1953-10-01,211
|
||||
1953-11-01,180
|
||||
1953-12-01,201
|
||||
1954-01-01,204
|
||||
1954-02-01,188
|
||||
1954-03-01,235
|
||||
1954-04-01,227
|
||||
1954-05-01,234
|
||||
1954-06-01,264
|
||||
1954-07-01,302
|
||||
1954-08-01,293
|
||||
1954-09-01,259
|
||||
1954-10-01,229
|
||||
1954-11-01,203
|
||||
1954-12-01,229
|
||||
1955-01-01,242
|
||||
1955-02-01,233
|
||||
1955-03-01,267
|
||||
1955-04-01,269
|
||||
1955-05-01,270
|
||||
1955-06-01,315
|
||||
1955-07-01,364
|
||||
1955-08-01,347
|
||||
1955-09-01,312
|
||||
1955-10-01,274
|
||||
1955-11-01,237
|
||||
1955-12-01,278
|
||||
1956-01-01,284
|
||||
1956-02-01,277
|
||||
1956-03-01,317
|
||||
1956-04-01,313
|
||||
1956-05-01,318
|
||||
1956-06-01,374
|
||||
1956-07-01,413
|
||||
1956-08-01,405
|
||||
1956-09-01,355
|
||||
1956-10-01,306
|
||||
1956-11-01,271
|
||||
1956-12-01,306
|
||||
1957-01-01,315
|
||||
1957-02-01,301
|
||||
1957-03-01,356
|
||||
1957-04-01,348
|
||||
1957-05-01,355
|
||||
1957-06-01,422
|
||||
1957-07-01,465
|
||||
1957-08-01,467
|
||||
1957-09-01,404
|
||||
1957-10-01,347
|
||||
1957-11-01,305
|
||||
1957-12-01,336
|
||||
1958-01-01,340
|
||||
1958-02-01,318
|
||||
1958-03-01,362
|
||||
1958-04-01,348
|
||||
1958-05-01,363
|
||||
1958-06-01,435
|
||||
1958-07-01,491
|
||||
1958-08-01,505
|
||||
1958-09-01,404
|
||||
1958-10-01,359
|
||||
1958-11-01,310
|
||||
1958-12-01,337
|
||||
1959-01-01,360
|
||||
1959-02-01,342
|
||||
1959-03-01,406
|
||||
1959-04-01,396
|
||||
1959-05-01,420
|
||||
1959-06-01,472
|
||||
1959-07-01,548
|
||||
1959-08-01,559
|
||||
1959-09-01,463
|
||||
1959-10-01,407
|
||||
1959-11-01,362
|
||||
1959-12-01,405
|
||||
1960-01-01,417
|
||||
1960-02-01,391
|
||||
1960-03-01,419
|
||||
1960-04-01,461
|
||||
1960-05-01,472
|
||||
1960-06-01,535
|
||||
1960-07-01,622
|
||||
1960-08-01,606
|
||||
1960-09-01,508
|
||||
1960-10-01,461
|
||||
1960-11-01,390
|
||||
1960-12-01,432
|
||||
|
Reference in New Issue
Block a user