Kolesnikov Dmitry commited on
Commit
7c4a2f3
·
1 Parent(s): b34a74f

debug: Доработки через дипсик

Browse files
_lab3_input_tmp.csv CHANGED
@@ -1,821 +1,821 @@
1
- index,timestamp,DailyNewCases,ActiveCases,DailyNewDeaths
2
- 0,2020-02-15 00:00:00+03:00,0.0,0.0,0.0
3
- 1,2020-02-16 00:00:00+03:00,0.0,0.0,0.0
4
- 2,2020-02-17 00:00:00+03:00,0.0,0.0,0.0
5
- 3,2020-02-18 00:00:00+03:00,0.0,0.0,0.0
6
- 4,2020-02-19 00:00:00+03:00,0.0,0.0,0.0
7
- 5,2020-02-20 00:00:00+03:00,0.0,0.0,0.0
8
- 6,2020-02-21 00:00:00+03:00,0.0,0.0,0.0
9
- 7,2020-02-22 00:00:00+03:00,0.0,0.0,0.0
10
- 8,2020-02-23 00:00:00+03:00,0.0,0.0,0.0
11
- 9,2020-02-24 00:00:00+03:00,0.0,0.0,0.0
12
- 10,2020-02-25 00:00:00+03:00,0.0,0.0,0.0
13
- 11,2020-02-26 00:00:00+03:00,0.0,0.0,0.0
14
- 12,2020-02-27 00:00:00+03:00,0.0,0.0,0.0
15
- 13,2020-02-28 00:00:00+03:00,0.0,0.0,0.0
16
- 14,2020-02-29 00:00:00+03:00,0.0,0.0,0.0
17
- 15,2020-03-01 00:00:00+03:00,0.0,0.0,0.0
18
- 16,2020-03-02 00:00:00+03:00,1.0,1.0,0.0
19
- 17,2020-03-03 00:00:00+03:00,0.0,1.0,0.0
20
- 18,2020-03-04 00:00:00+03:00,0.0,1.0,0.0
21
- 19,2020-03-05 00:00:00+03:00,4.0,5.0,0.0
22
- 20,2020-03-06 00:00:00+03:00,6.0,11.0,0.0
23
- 21,2020-03-07 00:00:00+03:00,1.0,11.0,0.0
24
- 22,2020-03-08 00:00:00+03:00,3.0,14.0,0.0
25
- 23,2020-03-09 00:00:00+03:00,3.0,17.0,0.0
26
- 24,2020-03-10 00:00:00+03:00,0.0,17.0,0.0
27
- 25,2020-03-11 00:00:00+03:00,8.0,25.0,0.0
28
- 26,2020-03-12 00:00:00+03:00,6.0,31.0,0.0
29
- 27,2020-03-13 00:00:00+03:00,11.0,37.0,0.0
30
- 28,2020-03-14 00:00:00+03:00,14.0,51.0,0.0
31
- 29,2020-03-15 00:00:00+03:00,4.0,55.0,0.0
32
- 30,2020-03-16 00:00:00+03:00,30.0,85.0,0.0
33
- 31,2020-03-17 00:00:00+03:00,21.0,106.0,0.0
34
- 32,2020-03-18 00:00:00+03:00,33.0,139.0,0.0
35
- 33,2020-03-19 00:00:00+03:00,52.0,190.0,1.0
36
- 34,2020-03-20 00:00:00+03:00,54.0,240.0,0.0
37
- 35,2020-03-21 00:00:00+03:00,53.0,289.0,0.0
38
- 36,2020-03-22 00:00:00+03:00,61.0,350.0,0.0
39
- 37,2020-03-23 00:00:00+03:00,71.0,420.0,0.0
40
- 38,2020-03-24 00:00:00+03:00,57.0,472.0,0.0
41
- 39,2020-03-25 00:00:00+03:00,163.0,626.0,2.0
42
- 40,2020-03-26 00:00:00+03:00,182.0,799.0,0.0
43
- 41,2020-03-27 00:00:00+03:00,196.0,987.0,1.0
44
- 42,2020-03-28 00:00:00+03:00,228.0,1211.0,0.0
45
- 43,2020-03-29 00:00:00+03:00,270.0,1462.0,4.0
46
- 44,2020-03-30 00:00:00+03:00,302.0,1761.0,1.0
47
- 45,2020-03-31 00:00:00+03:00,501.0,2199.0,8.0
48
- 46,2020-04-01 00:00:00+03:00,440.0,2563.0,7.0
49
- 47,2020-04-02 00:00:00+03:00,771.0,3283.0,6.0
50
- 48,2020-04-03 00:00:00+03:00,601.0,3834.0,4.0
51
- 49,2020-04-04 00:00:00+03:00,582.0,4355.0,9.0
52
- 50,2020-04-05 00:00:00+03:00,658.0,4989.0,2.0
53
- 51,2020-04-06 00:00:00+03:00,954.0,5890.0,2.0
54
- 52,2020-04-07 00:00:00+03:00,1154.0,6945.0,11.0
55
- 53,2020-04-08 00:00:00+03:00,1175.0,8029.0,5.0
56
- 54,2020-04-09 00:00:00+03:00,1459.0,9357.0,13.0
57
- 55,2020-04-10 00:00:00+03:00,1786.0,11028.0,18.0
58
- 56,2020-04-11 00:00:00+03:00,1667.0,12433.0,12.0
59
- 57,2020-04-12 00:00:00+03:00,2186.0,14349.0,24.0
60
- 58,2020-04-13 00:00:00+03:00,2558.0,16710.0,18.0
61
- 59,2020-04-14 00:00:00+03:00,2774.0,19238.0,22.0
62
- 60,2020-04-15 00:00:00+03:00,3388.0,22306.0,28.0
63
- 61,2020-04-16 00:00:00+03:00,3448.0,25402.0,34.0
64
- 62,2020-04-17 00:00:00+03:00,4070.0,29145.0,41.0
65
- 63,2020-04-18 00:00:00+03:00,4785.0,33423.0,40.0
66
- 64,2020-04-19 00:00:00+03:00,6060.0,39201.0,48.0
67
- 65,2020-04-20 00:00:00+03:00,4268.0,43270.0,44.0
68
- 66,2020-04-21 00:00:00+03:00,5642.0,48434.0,51.0
69
- 67,2020-04-22 00:00:00+03:00,5236.0,53066.0,57.0
70
- 68,2020-04-23 00:00:00+03:00,4774.0,57327.0,42.0
71
- 69,2020-04-24 00:00:00+03:00,5849.0,62439.0,60.0
72
- 70,2020-04-25 00:00:00+03:00,5966.0,67657.0,66.0
73
- 71,2020-04-26 00:00:00+03:00,6361.0,73435.0,66.0
74
- 72,2020-04-27 00:00:00+03:00,6198.0,79007.0,47.0
75
- 73,2020-04-28 00:00:00+03:00,6411.0,84235.0,73.0
76
- 74,2020-04-29 00:00:00+03:00,5841.0,88141.0,105.0
77
- 75,2020-04-30 00:00:00+03:00,7099.0,93806.0,101.0
78
- 76,2020-05-01 00:00:00+03:00,7933.0,100042.0,96.0
79
- 77,2020-05-02 00:00:00+03:00,9623.0,107819.0,53.0
80
- 78,2020-05-03 00:00:00+03:00,10633.0,116768.0,58.0
81
- 79,2020-05-04 00:00:00+03:00,10581.0,125817.0,76.0
82
- 80,2020-05-05 00:00:00+03:00,10102.0,134054.0,95.0
83
- 81,2020-05-06 00:00:00+03:00,10559.0,143065.0,86.0
84
- 82,2020-05-07 00:00:00+03:00,11231.0,151732.0,88.0
85
- 83,2020-05-08 00:00:00+03:00,10699.0,159528.0,98.0
86
- 84,2020-05-09 00:00:00+03:00,10817.0,164933.0,104.0
87
- 85,2020-05-10 00:00:00+03:00,11012.0,173467.0,88.0
88
- 86,2020-05-11 00:00:00+03:00,11656.0,179534.0,94.0
89
- 87,2020-05-12 00:00:00+03:00,10899.0,186615.0,107.0
90
- 88,2020-05-13 00:00:00+03:00,10028.0,192056.0,96.0
91
- 89,2020-05-14 00:00:00+03:00,9974.0,196410.0,93.0
92
- 90,2020-05-15 00:00:00+03:00,10598.0,202199.0,113.0
93
- 91,2020-05-16 00:00:00+03:00,9200.0,206340.0,119.0
94
- 92,2020-05-17 00:00:00+03:00,9709.0,211748.0,94.0
95
- 93,2020-05-18 00:00:00+03:00,8926.0,217747.0,91.0
96
- 94,2020-05-19 00:00:00+03:00,9263.0,220974.0,115.0
97
- 95,2020-05-20 00:00:00+03:00,8764.0,220341.0,135.0
98
- 96,2020-05-21 00:00:00+03:00,8849.0,221774.0,127.0
99
- 97,2020-05-22 00:00:00+03:00,8894.0,223374.0,150.0
100
- 98,2020-05-23 00:00:00+03:00,9434.0,224558.0,139.0
101
- 99,2020-05-24 00:00:00+03:00,8599.0,227641.0,153.0
102
- 100,2020-05-25 00:00:00+03:00,8946.0,230996.0,92.0
103
- 101,2020-05-26 00:00:00+03:00,8915.0,227406.0,174.0
104
- 102,2020-05-27 00:00:00+03:00,8338.0,224504.0,161.0
105
- 103,2020-05-28 00:00:00+03:00,8371.0,223916.0,174.0
106
- 104,2020-05-29 00:00:00+03:00,8572.0,223992.0,232.0
107
- 105,2020-05-30 00:00:00+03:00,8952.0,224551.0,181.0
108
- 106,2020-05-31 00:00:00+03:00,9268.0,229267.0,138.0
109
- 107,2020-06-01 00:00:00+03:00,9035.0,234146.0,162.0
110
- 108,2020-06-02 00:00:00+03:00,8863.0,231719.0,182.0
111
- 109,2020-06-03 00:00:00+03:00,8536.0,231105.0,178.0
112
- 110,2020-06-04 00:00:00+03:00,8831.0,231101.0,169.0
113
- 111,2020-06-05 00:00:00+03:00,8726.0,231626.0,144.0
114
- 112,2020-06-06 00:00:00+03:00,8855.0,231576.0,197.0
115
- 113,2020-06-07 00:00:00+03:00,8984.0,235083.0,134.0
116
- 114,2020-06-08 00:00:00+03:00,8985.0,239999.0,112.0
117
- 115,2020-06-09 00:00:00+03:00,8595.0,236714.0,171.0
118
- 116,2020-06-10 00:00:00+03:00,8404.0,234516.0,216.0
119
- 117,2020-06-11 00:00:00+03:00,8779.0,234754.0,174.0
120
- 118,2020-06-12 00:00:00+03:00,8987.0,235338.0,183.0
121
- 119,2020-06-13 00:00:00+03:00,8706.0,238659.0,114.0
122
- 120,2020-06-14 00:00:00+03:00,8835.0,241966.0,119.0
123
- 121,2020-06-15 00:00:00+03:00,8246.0,245580.0,143.0
124
- 122,2020-06-16 00:00:00+03:00,8248.0,243868.0,193.0
125
- 123,2020-06-17 00:00:00+03:00,7843.0,241481.0,194.0
126
- 124,2020-06-18 00:00:00+03:00,7790.0,239468.0,182.0
127
- 125,2020-06-19 00:00:00+03:00,7972.0,236816.0,181.0
128
- 126,2020-06-20 00:00:00+03:00,7889.0,234358.0,161.0
129
- 127,2020-06-21 00:00:00+03:00,7728.0,236858.0,109.0
130
- 128,2020-06-22 00:00:00+03:00,7600.0,239658.0,95.0
131
- 129,2020-06-23 00:00:00+03:00,7425.0,234917.0,153.0
132
- 130,2020-06-24 00:00:00+03:00,7176.0,229546.0,154.0
133
- 131,2020-06-25 00:00:00+03:00,7113.0,230225.0,92.0
134
- 132,2020-06-26 00:00:00+03:00,6800.0,227861.0,176.0
135
- 133,2020-06-27 00:00:00+03:00,6852.0,225325.0,188.0
136
- 134,2020-06-28 00:00:00+03:00,6791.0,226277.0,104.0
137
- 135,2020-06-29 00:00:00+03:00,6719.0,228560.0,93.0
138
- 136,2020-06-30 00:00:00+03:00,6693.0,225879.0,154.0
139
- 137,2020-07-01 00:00:00+03:00,6556.0,221938.0,216.0
140
- 138,2020-07-02 00:00:00+03:00,6760.0,222504.0,147.0
141
- 139,2020-07-03 00:00:00+03:00,6718.0,220131.0,176.0
142
- 140,2020-07-04 00:00:00+03:00,6632.0,217609.0,168.0
143
- 141,2020-07-05 00:00:00+03:00,6736.0,220340.0,134.0
144
- 142,2020-07-06 00:00:00+03:00,6611.0,223237.0,135.0
145
- 143,2020-07-07 00:00:00+03:00,6368.0,219856.0,198.0
146
- 144,2020-07-08 00:00:00+03:00,6562.0,217614.0,173.0
147
- 145,2020-07-09 00:00:00+03:00,6509.0,215142.0,176.0
148
- 146,2020-07-10 00:00:00+03:00,6635.0,213851.0,174.0
149
- 147,2020-07-11 00:00:00+03:00,6611.0,211896.0,188.0
150
- 148,2020-07-12 00:00:00+03:00,6615.0,214766.0,130.0
151
- 149,2020-07-13 00:00:00+03:00,6537.0,218239.0,104.0
152
- 150,2020-07-14 00:00:00+03:00,6248.0,215508.0,175.0
153
- 151,2020-07-15 00:00:00+03:00,6422.0,211350.0,156.0
154
- 152,2020-07-16 00:00:00+03:00,6428.0,209168.0,167.0
155
- 153,2020-07-17 00:00:00+03:00,6406.0,207707.0,186.0
156
- 154,2020-07-18 00:00:00+03:00,6234.0,206327.0,124.0
157
- 155,2020-07-19 00:00:00+03:00,6109.0,208860.0,95.0
158
- 156,2020-07-20 00:00:00+03:00,5940.0,211457.0,85.0
159
- 157,2020-07-21 00:00:00+03:00,5842.0,208364.0,153.0
160
- 158,2020-07-22 00:00:00+03:00,5862.0,204392.0,165.0
161
- 159,2020-07-23 00:00:00+03:00,5848.0,201816.0,147.0
162
- 160,2020-07-24 00:00:00+03:00,5811.0,199029.0,154.0
163
- 161,2020-07-25 00:00:00+03:00,5871.0,196388.0,146.0
164
- 162,2020-07-26 00:00:00+03:00,5765.0,198966.0,77.0
165
- 163,2020-07-27 00:00:00+03:00,5635.0,201437.0,85.0
166
- 164,2020-07-28 00:00:00+03:00,5395.0,197794.0,150.0
167
- 165,2020-07-29 00:00:00+03:00,5475.0,194984.0,169.0
168
- 166,2020-07-30 00:00:00+03:00,5509.0,191042.0,129.0
169
- 167,2020-07-31 00:00:00+03:00,5482.0,187608.0,161.0
170
- 168,2020-08-01 00:00:00+03:00,5462.0,184861.0,95.0
171
- 169,2020-08-02 00:00:00+03:00,5427.0,186569.0,70.0
172
- 170,2020-08-03 00:00:00+03:00,5394.0,188464.0,79.0
173
- 171,2020-08-04 00:00:00+03:00,5159.0,185601.0,144.0
174
- 172,2020-08-05 00:00:00+03:00,5204.0,183111.0,139.0
175
- 173,2020-08-06 00:00:00+03:00,5267.0,180931.0,116.0
176
- 174,2020-08-07 00:00:00+03:00,5241.0,178818.0,119.0
177
- 175,2020-08-08 00:00:00+03:00,5212.0,177286.0,129.0
178
- 176,2020-08-09 00:00:00+03:00,5189.0,179183.0,77.0
179
- 177,2020-08-10 00:00:00+03:00,5118.0,180972.0,70.0
180
- 178,2020-08-11 00:00:00+03:00,4945.0,179293.0,130.0
181
- 179,2020-08-12 00:00:00+03:00,5102.0,177143.0,129.0
182
- 180,2020-08-13 00:00:00+03:00,5057.0,175978.0,124.0
183
- 181,2020-08-14 00:00:00+03:00,5065.0,174361.0,114.0
184
- 182,2020-08-15 00:00:00+03:00,5061.0,172856.0,119.0
185
- 183,2020-08-16 00:00:00+03:00,4969.0,174200.0,68.0
186
- 184,2020-08-17 00:00:00+03:00,4892.0,175904.0,55.0
187
- 185,2020-08-18 00:00:00+03:00,4748.0,173993.0,132.0
188
- 186,2020-08-19 00:00:00+03:00,4828.0,171909.0,117.0
189
- 187,2020-08-20 00:00:00+03:00,4785.0,170494.0,110.0
190
- 188,2020-08-21 00:00:00+03:00,4870.0,169457.0,90.0
191
- 189,2020-08-22 00:00:00+03:00,4921.0,168110.0,121.0
192
- 190,2020-08-23 00:00:00+03:00,4852.0,169727.0,73.0
193
- 191,2020-08-24 00:00:00+03:00,4744.0,171950.0,65.0
194
- 192,2020-08-25 00:00:00+03:00,4696.0,169874.0,120.0
195
- 193,2020-08-26 00:00:00+03:00,4676.0,168032.0,115.0
196
- 194,2020-08-27 00:00:00+03:00,4711.0,166211.0,121.0
197
- 195,2020-08-28 00:00:00+03:00,4829.0,165025.0,110.0
198
- 196,2020-08-29 00:00:00+03:00,4941.0,163938.0,111.0
199
- 197,2020-08-30 00:00:00+03:00,4980.0,166251.0,68.0
200
- 198,2020-08-31 00:00:00+03:00,4993.0,168756.0,83.0
201
- 199,2020-09-01 00:00:00+03:00,4729.0,167044.0,123.0
202
- 200,2020-09-02 00:00:00+03:00,4952.0,166417.0,115.0
203
- 201,2020-09-03 00:00:00+03:00,4995.0,165532.0,114.0
204
- 202,2020-09-04 00:00:00+03:00,5110.0,164709.0,121.0
205
- 203,2020-09-05 00:00:00+03:00,5205.0,164425.0,110.0
206
- 204,2020-09-06 00:00:00+03:00,5195.0,166736.0,61.0
207
- 205,2020-09-07 00:00:00+03:00,5185.0,169542.0,51.0
208
- 206,2020-09-08 00:00:00+03:00,5099.0,167747.0,122.0
209
- 207,2020-09-09 00:00:00+03:00,5218.0,166414.0,142.0
210
- 208,2020-09-10 00:00:00+03:00,5363.0,165734.0,128.0
211
- 209,2020-09-11 00:00:00+03:00,5504.0,165402.0,102.0
212
- 210,2020-09-12 00:00:00+03:00,5488.0,165343.0,119.0
213
- 211,2020-09-13 00:00:00+03:00,5449.0,168008.0,94.0
214
- 212,2020-09-14 00:00:00+03:00,5509.0,170985.0,57.0
215
- 213,2020-09-15 00:00:00+03:00,5529.0,170759.0,150.0
216
- 214,2020-09-16 00:00:00+03:00,5670.0,170488.0,132.0
217
- 215,2020-09-17 00:00:00+03:00,5762.0,170352.0,144.0
218
- 216,2020-09-18 00:00:00+03:00,5905.0,170784.0,134.0
219
- 217,2020-09-19 00:00:00+03:00,6065.0,171450.0,144.0
220
- 218,2020-09-20 00:00:00+03:00,6148.0,174624.0,79.0
221
- 219,2020-09-21 00:00:00+03:00,6196.0,178133.0,71.0
222
- 220,2020-09-22 00:00:00+03:00,6215.0,178212.0,160.0
223
- 221,2020-09-23 00:00:00+03:00,6431.0,178743.0,150.0
224
- 222,2020-09-24 00:00:00+03:00,6595.0,179059.0,149.0
225
- 223,2020-09-25 00:00:00+03:00,7212.0,181846.0,108.0
226
- 224,2020-09-26 00:00:00+03:00,7523.0,183196.0,169.0
227
- 225,2020-09-27 00:00:00+03:00,7867.0,187896.0,99.0
228
- 226,2020-09-28 00:00:00+03:00,8135.0,193268.0,61.0
229
- 227,2020-09-29 00:00:00+03:00,8232.0,194861.0,160.0
230
- 228,2020-09-30 00:00:00+03:00,8481.0,197307.0,177.0
231
- 229,2020-10-01 00:00:00+03:00,8945.0,200098.0,169.0
232
- 230,2020-10-02 00:00:00+03:00,9412.0,203270.0,186.0
233
- 231,2020-10-03 00:00:00+03:00,9859.0,207392.0,174.0
234
- 232,2020-10-04 00:00:00+03:00,10499.0,214500.0,107.0
235
- 233,2020-10-05 00:00:00+03:00,10888.0,222090.0,117.0
236
- 234,2020-10-06 00:00:00+03:00,11615.0,227265.0,188.0
237
- 235,2020-10-07 00:00:00+03:00,11115.0,231479.0,202.0
238
- 236,2020-10-08 00:00:00+03:00,11493.0,235727.0,191.0
239
- 237,2020-10-09 00:00:00+03:00,12126.0,240560.0,201.0
240
- 238,2020-10-10 00:00:00+03:00,12846.0,246428.0,197.0
241
- 239,2020-10-11 00:00:00+03:00,13634.0,255679.0,143.0
242
- 240,2020-10-12 00:00:00+03:00,13592.0,265353.0,125.0
243
- 241,2020-10-13 00:00:00+03:00,13868.0,271427.0,244.0
244
- 242,2020-10-14 00:00:00+03:00,14231.0,277499.0,239.0
245
- 243,2020-10-15 00:00:00+03:00,13754.0,282575.0,286.0
246
- 244,2020-10-16 00:00:00+03:00,15150.0,289008.0,232.0
247
- 245,2020-10-17 00:00:00+03:00,14922.0,295034.0,279.0
248
- 246,2020-10-18 00:00:00+03:00,15099.0,304571.0,185.0
249
- 247,2020-10-19 00:00:00+03:00,15982.0,315046.0,179.0
250
- 248,2020-10-20 00:00:00+03:00,16319.0,321392.0,269.0
251
- 249,2020-10-21 00:00:00+03:00,15700.0,325823.0,317.0
252
- 250,2020-10-22 00:00:00+03:00,15971.0,330076.0,290.0
253
- 251,2020-10-23 00:00:00+03:00,17340.0,335870.0,283.0
254
- 252,2020-10-24 00:00:00+03:00,16521.0,340528.0,296.0
255
- 253,2020-10-25 00:00:00+03:00,16710.0,349305.0,229.0
256
- 254,2020-10-26 00:00:00+03:00,17347.0,358859.0,219.0
257
- 255,2020-10-27 00:00:00+03:00,16550.0,362245.0,320.0
258
- 256,2020-10-28 00:00:00+03:00,16202.0,365740.0,346.0
259
- 257,2020-10-29 00:00:00+03:00,17717.0,368351.0,366.0
260
- 258,2020-10-30 00:00:00+03:00,18283.0,371760.0,355.0
261
- 259,2020-10-31 00:00:00+03:00,18140.0,374712.0,334.0
262
- 260,2020-11-01 00:00:00+03:00,18665.0,382873.0,245.0
263
- 261,2020-11-02 00:00:00+03:00,18257.0,390532.0,238.0
264
- 262,2020-11-03 00:00:00+03:00,18648.0,393494.0,355.0
265
- 263,2020-11-04 00:00:00+03:00,19768.0,397306.0,389.0
266
- 264,2020-11-05 00:00:00+03:00,19404.0,404180.0,292.0
267
- 265,2020-11-06 00:00:00+03:00,20582.0,407429.0,378.0
268
- 266,2020-11-07 00:00:00+03:00,20396.0,410658.0,364.0
269
- 267,2020-11-08 00:00:00+03:00,20498.0,419378.0,286.0
270
- 268,2020-11-09 00:00:00+03:00,21798.0,430198.0,256.0
271
- 269,2020-11-10 00:00:00+03:00,20977.0,435207.0,368.0
272
- 270,2020-11-11 00:00:00+03:00,19851.0,436010.0,432.0
273
- 271,2020-11-12 00:00:00+03:00,21608.0,438368.0,439.0
274
- 272,2020-11-13 00:00:00+03:00,21983.0,441205.0,411.0
275
- 273,2020-11-14 00:00:00+03:00,22702.0,444890.0,391.0
276
- 274,2020-11-15 00:00:00+03:00,22572.0,452654.0,352.0
277
- 275,2020-11-16 00:00:00+03:00,22778.0,461265.0,303.0
278
- 276,2020-11-17 00:00:00+03:00,22410.0,461178.0,442.0
279
- 277,2020-11-18 00:00:00+03:00,20985.0,456528.0,456.0
280
- 278,2020-11-19 00:00:00+03:00,23610.0,454102.0,463.0
281
- 279,2020-11-20 00:00:00+03:00,24318.0,453201.0,461.0
282
- 280,2020-11-21 00:00:00+03:00,24822.0,451535.0,467.0
283
- 281,2020-11-22 00:00:00+03:00,24581.0,457707.0,401.0
284
- 282,2020-11-23 00:00:00+03:00,25173.0,466517.0,361.0
285
- 283,2020-11-24 00:00:00+03:00,24326.0,467126.0,491.0
286
- 284,2020-11-25 00:00:00+03:00,23675.0,464546.0,507.0
287
- 285,2020-11-26 00:00:00+03:00,25487.0,464436.0,524.0
288
- 286,2020-11-27 00:00:00+03:00,27543.0,464801.0,496.0
289
- 287,2020-11-28 00:00:00+03:00,27100.0,464095.0,510.0
290
- 288,2020-11-29 00:00:00+03:00,26683.0,468332.0,459.0
291
- 289,2020-11-30 00:00:00+03:00,26338.0,477055.0,368.0
292
- 290,2020-12-01 00:00:00+03:00,26402.0,478125.0,569.0
293
- 291,2020-12-02 00:00:00+03:00,25345.0,475999.0,589.0
294
- 292,2020-12-03 00:00:00+03:00,28145.0,474088.0,554.0
295
- 293,2020-12-04 00:00:00+03:00,27403.0,472021.0,569.0
296
- 294,2020-12-05 00:00:00+03:00,28782.0,472651.0,508.0
297
- 295,2020-12-06 00:00:00+03:00,29039.0,479891.0,457.0
298
- 296,2020-12-07 00:00:00+03:00,28142.0,488727.0,456.0
299
- 297,2020-12-08 00:00:00+03:00,26097.0,489324.0,562.0
300
- 298,2020-12-09 00:00:00+03:00,26190.0,488689.0,559.0
301
- 299,2020-12-10 00:00:00+03:00,27927.0,490177.0,562.0
302
- 300,2020-12-11 00:00:00+03:00,28585.0,491978.0,613.0
303
- 301,2020-12-12 00:00:00+03:00,28137.0,493437.0,560.0
304
- 302,2020-12-13 00:00:00+03:00,28080.0,500752.0,488.0
305
- 303,2020-12-14 00:00:00+03:00,27328.0,509068.0,450.0
306
- 304,2020-12-15 00:00:00+03:00,26689.0,510367.0,577.0
307
- 305,2020-12-16 00:00:00+03:00,26509.0,509790.0,596.0
308
- 306,2020-12-17 00:00:00+03:00,28214.0,510977.0,587.0
309
- 307,2020-12-18 00:00:00+03:00,28552.0,512825.0,611.0
310
- 308,2020-12-19 00:00:00+03:00,28209.0,514340.0,585.0
311
- 309,2020-12-20 00:00:00+03:00,28948.0,521862.0,511.0
312
- 310,2020-12-21 00:00:00+03:00,29350.0,531014.0,493.0
313
- 311,2020-12-22 00:00:00+03:00,28776.0,535071.0,561.0
314
- 312,2020-12-23 00:00:00+03:00,27250.0,537325.0,549.0
315
- 313,2020-12-24 00:00:00+03:00,29935.0,539735.0,635.0
316
- 314,2020-12-25 00:00:00+03:00,29018.0,540793.0,563.0
317
- 315,2020-12-26 00:00:00+03:00,29258.0,541299.0,567.0
318
- 316,2020-12-27 00:00:00+03:00,28284.0,544641.0,552.0
319
- 317,2020-12-28 00:00:00+03:00,27787.0,551461.0,487.0
320
- 318,2020-12-29 00:00:00+03:00,27002.0,553027.0,562.0
321
- 319,2020-12-30 00:00:00+03:00,26513.0,549706.0,599.0
322
- 320,2020-12-31 00:00:00+03:00,27747.0,547938.0,593.0
323
- 321,2021-01-01 00:00:00+03:00,27039.0,548643.0,536.0
324
- 322,2021-01-02 00:00:00+03:00,26301.0,555600.0,447.0
325
- 323,2021-01-03 00:00:00+03:00,24150.0,559399.0,504.0
326
- 324,2021-01-04 00:00:00+03:00,23351.0,561114.0,482.0
327
- 325,2021-01-05 00:00:00+03:00,24246.0,562210.0,518.0
328
- 326,2021-01-06 00:00:00+03:00,24217.0,562927.0,445.0
329
- 327,2021-01-07 00:00:00+03:00,23541.0,562233.0,506.0
330
- 328,2021-01-08 00:00:00+03:00,23652.0,563754.0,454.0
331
- 329,2021-01-09 00:00:00+03:00,23309.0,562913.0,470.0
332
- 330,2021-01-10 00:00:00+03:00,22851.0,561228.0,456.0
333
- 331,2021-01-11 00:00:00+03:00,23315.0,562321.0,436.0
334
- 332,2021-01-12 00:00:00+03:00,22934.0,559969.0,531.0
335
- 333,2021-01-13 00:00:00+03:00,22850.0,553595.0,566.0
336
- 334,2021-01-14 00:00:00+03:00,24763.0,549832.0,570.0
337
- 335,2021-01-15 00:00:00+03:00,24715.0,546356.0,555.0
338
- 336,2021-01-16 00:00:00+03:00,24092.0,542547.0,590.0
339
- 337,2021-01-17 00:00:00+03:00,23586.0,542212.0,481.0
340
- 338,2021-01-18 00:00:00+03:00,22857.0,546265.0,471.0
341
- 339,2021-01-19 00:00:00+03:00,21734.0,544151.0,586.0
342
- 340,2021-01-20 00:00:00+03:00,21152.0,539416.0,597.0
343
- 341,2021-01-21 00:00:00+03:00,21887.0,533789.0,612.0
344
- 342,2021-01-22 00:00:00+03:00,21513.0,527404.0,580.0
345
- 343,2021-01-23 00:00:00+03:00,20921.0,519987.0,559.0
346
- 344,2021-01-24 00:00:00+03:00,21127.0,518178.0,491.0
347
- 345,2021-01-25 00:00:00+03:00,19290.0,518009.0,456.0
348
- 346,2021-01-26 00:00:00+03:00,18241.0,511888.0,564.0
349
- 347,2021-01-27 00:00:00+03:00,17741.0,501113.0,594.0
350
- 348,2021-01-28 00:00:00+03:00,19138.0,492901.0,575.0
351
- 349,2021-01-29 00:00:00+03:00,19238.0,485401.0,534.0
352
- 350,2021-01-30 00:00:00+03:00,19032.0,479419.0,512.0
353
- 351,2021-01-31 00:00:00+03:00,18359.0,477253.0,485.0
354
- 352,2021-02-01 00:00:00+03:00,17648.0,476295.0,437.0
355
- 353,2021-02-02 00:00:00+03:00,16643.0,470027.0,539.0
356
- 354,2021-02-03 00:00:00+03:00,16474.0,461153.0,526.0
357
- 355,2021-02-04 00:00:00+03:00,16714.0,452800.0,521.0
358
- 356,2021-02-05 00:00:00+03:00,16688.0,445379.0,527.0
359
- 357,2021-02-06 00:00:00+03:00,16627.0,438678.0,497.0
360
- 358,2021-02-07 00:00:00+03:00,16048.0,434410.0,432.0
361
- 359,2021-02-08 00:00:00+03:00,15916.0,434038.0,407.0
362
- 360,2021-02-09 00:00:00+03:00,15019.0,426732.0,530.0
363
- 361,2021-02-10 00:00:00+03:00,14494.0,418115.0,536.0
364
- 362,2021-02-11 00:00:00+03:00,15038.0,410639.0,553.0
365
- 363,2021-02-12 00:00:00+03:00,15089.0,404501.0,507.0
366
- 364,2021-02-13 00:00:00+03:00,14861.0,400095.0,502.0
367
- 365,2021-02-14 00:00:00+03:00,14185.0,398656.0,430.0
368
- 366,2021-02-15 00:00:00+03:00,14207.0,398534.0,394.0
369
- 367,2021-02-16 00:00:00+03:00,13233.0,393681.0,459.0
370
- 368,2021-02-17 00:00:00+03:00,12828.0,388123.0,467.0
371
- 369,2021-02-18 00:00:00+03:00,13447.0,382360.0,480.0
372
- 370,2021-02-19 00:00:00+03:00,13433.0,376686.0,470.0
373
- 371,2021-02-20 00:00:00+03:00,12953.0,371675.0,480.0
374
- 372,2021-02-21 00:00:00+03:00,12742.0,367988.0,417.0
375
- 373,2021-02-22 00:00:00+03:00,12604.0,367312.0,337.0
376
- 374,2021-02-23 00:00:00+03:00,11823.0,365762.0,417.0
377
- 375,2021-02-24 00:00:00+03:00,11749.0,364910.0,383.0
378
- 376,2021-02-25 00:00:00+03:00,11198.0,359560.0,446.0
379
- 377,2021-02-26 00:00:00+03:00,11086.0,354496.0,428.0
380
- 378,2021-02-27 00:00:00+03:00,11534.0,349571.0,439.0
381
- 379,2021-02-28 00:00:00+03:00,11359.0,348160.0,379.0
382
- 380,2021-03-01 00:00:00+03:00,11571.0,348121.0,333.0
383
- 381,2021-03-02 00:00:00+03:00,10565.0,343279.0,441.0
384
- 382,2021-03-03 00:00:00+03:00,10535.0,337668.0,452.0
385
- 383,2021-03-04 00:00:00+03:00,11385.0,332455.0,475.0
386
- 384,2021-03-05 00:00:00+03:00,11024.0,327553.0,462.0
387
- 385,2021-03-06 00:00:00+03:00,11022.0,323107.0,441.0
388
- 386,2021-03-07 00:00:00+03:00,10595.0,321758.0,368.0
389
- 387,2021-03-08 00:00:00+03:00,10253.0,321310.0,379.0
390
- 388,2021-03-09 00:00:00+03:00,9445.0,320488.0,336.0
391
- 389,2021-03-10 00:00:00+03:00,9079.0,315751.0,466.0
392
- 390,2021-03-11 00:00:00+03:00,9270.0,310556.0,459.0
393
- 391,2021-03-12 00:00:00+03:00,9794.0,306368.0,486.0
394
- 392,2021-03-13 00:00:00+03:00,9908.0,302933.0,475.0
395
- 393,2021-03-14 00:00:00+03:00,10083.0,303209.0,395.0
396
- 394,2021-03-15 00:00:00+03:00,9437.0,303975.0,404.0
397
- 395,2021-03-16 00:00:00+03:00,9393.0,302281.0,443.0
398
- 396,2021-03-17 00:00:00+03:00,8998.0,300097.0,427.0
399
- 397,2021-03-18 00:00:00+03:00,9803.0,297379.0,460.0
400
- 398,2021-03-19 00:00:00+03:00,9699.0,294298.0,443.0
401
- 399,2021-03-20 00:00:00+03:00,9632.0,292259.0,392.0
402
- 400,2021-03-21 00:00:00+03:00,9299.0,292444.0,371.0
403
- 401,2021-03-22 00:00:00+03:00,9284.0,293577.0,361.0
404
- 402,2021-03-23 00:00:00+03:00,8457.0,290747.0,427.0
405
- 403,2021-03-24 00:00:00+03:00,8861.0,288852.0,401.0
406
- 404,2021-03-25 00:00:00+03:00,9221.0,286799.0,393.0
407
- 405,2021-03-26 00:00:00+03:00,9167.0,284681.0,405.0
408
- 406,2021-03-27 00:00:00+03:00,8885.0,282842.0,387.0
409
- 407,2021-03-28 00:00:00+03:00,9088.0,282964.0,336.0
410
- 408,2021-03-29 00:00:00+03:00,8711.0,284102.0,293.0
411
- 409,2021-03-30 00:00:00+03:00,8277.0,282382.0,409.0
412
- 410,2021-03-31 00:00:00+03:00,8275.0,280073.0,408.0
413
- 411,2021-04-01 00:00:00+03:00,9169.0,278612.0,383.0
414
- 412,2021-04-02 00:00:00+03:00,8792.0,277172.0,400.0
415
- 413,2021-04-03 00:00:00+03:00,9021.0,276191.0,384.0
416
- 414,2021-04-04 00:00:00+03:00,8817.0,276439.0,357.0
417
- 415,2021-04-05 00:00:00+03:00,8646.0,277690.0,343.0
418
- 416,2021-04-06 00:00:00+03:00,8328.0,276727.0,389.0
419
- 417,2021-04-07 00:00:00+03:00,8294.0,275202.0,374.0
420
- 418,2021-04-08 00:00:00+03:00,8672.0,273951.0,365.0
421
- 419,2021-04-09 00:00:00+03:00,9150.0,273037.0,402.0
422
- 420,2021-04-10 00:00:00+03:00,8704.0,271760.0,402.0
423
- 421,2021-04-11 00:00:00+03:00,8702.0,272895.0,337.0
424
- 422,2021-04-12 00:00:00+03:00,8320.0,274282.0,277.0
425
- 423,2021-04-13 00:00:00+03:00,8173.0,272506.0,338.0
426
- 424,2021-04-14 00:00:00+03:00,8326.0,270986.0,399.0
427
- 425,2021-04-15 00:00:00+03:00,8944.0,269307.0,398.0
428
- 426,2021-04-16 00:00:00+03:00,8995.0,268796.0,397.0
429
- 427,2021-04-17 00:00:00+03:00,9321.0,268887.0,398.0
430
- 428,2021-04-18 00:00:00+03:00,8632.0,269739.0,389.0
431
- 429,2021-04-19 00:00:00+03:00,8589.0,271164.0,346.0
432
- 430,2021-04-20 00:00:00+03:00,8164.0,269318.0,379.0
433
- 431,2021-04-21 00:00:00+03:00,8271.0,267546.0,399.0
434
- 432,2021-04-22 00:00:00+03:00,8996.0,267211.0,397.0
435
- 433,2021-04-23 00:00:00+03:00,8840.0,266246.0,398.0
436
- 434,2021-04-24 00:00:00+03:00,8828.0,265421.0,399.0
437
- 435,2021-04-25 00:00:00+03:00,8780.0,266329.0,332.0
438
- 436,2021-04-26 00:00:00+03:00,8803.0,268145.0,356.0
439
- 437,2021-04-27 00:00:00+03:00,8053.0,267767.0,392.0
440
- 438,2021-04-28 00:00:00+03:00,7848.0,266808.0,387.0
441
- 439,2021-04-29 00:00:00+03:00,9284.0,267286.0,364.0
442
- 440,2021-04-30 00:00:00+03:00,8731.0,267214.0,397.0
443
- 441,2021-05-01 00:00:00+03:00,9270.0,267455.0,392.0
444
- 442,2021-05-02 00:00:00+03:00,8697.0,268471.0,342.0
445
- 443,2021-05-03 00:00:00+03:00,8489.0,270257.0,336.0
446
- 444,2021-05-04 00:00:00+03:00,7770.0,270935.0,337.0
447
- 445,2021-05-05 00:00:00+03:00,7975.0,271044.0,360.0
448
- 446,2021-05-06 00:00:00+03:00,7639.0,270544.0,351.0
449
- 447,2021-05-07 00:00:00+03:00,8386.0,270532.0,376.0
450
- 448,2021-05-08 00:00:00+03:00,8329.0,270236.0,370.0
451
- 449,2021-05-09 00:00:00+03:00,8419.0,270804.0,334.0
452
- 450,2021-05-10 00:00:00+03:00,8465.0,272174.0,321.0
453
- 451,2021-05-11 00:00:00+03:00,8115.0,272951.0,329.0
454
- 452,2021-05-12 00:00:00+03:00,8217.0,272199.0,355.0
455
- 453,2021-05-13 00:00:00+03:00,8380.0,270838.0,392.0
456
- 454,2021-05-14 00:00:00+03:00,9462.0,270151.0,393.0
457
- 455,2021-05-15 00:00:00+03:00,8790.0,268711.0,364.0
458
- 456,2021-05-16 00:00:00+03:00,8554.0,268301.0,391.0
459
- 457,2021-05-17 00:00:00+03:00,9328.0,270108.0,340.0
460
- 458,2021-05-18 00:00:00+03:00,8183.0,268955.0,364.0
461
- 459,2021-05-19 00:00:00+03:00,7920.0,266924.0,390.0
462
- 460,2021-05-20 00:00:00+03:00,9232.0,265777.0,396.0
463
- 461,2021-05-21 00:00:00+03:00,8937.0,264986.0,378.0
464
- 462,2021-05-22 00:00:00+03:00,8709.0,263964.0,386.0
465
- 463,2021-05-23 00:00:00+03:00,8951.0,265261.0,357.0
466
- 464,2021-05-24 00:00:00+03:00,8406.0,266898.0,319.0
467
- 465,2021-05-25 00:00:00+03:00,7884.0,265646.0,393.0
468
- 466,2021-05-26 00:00:00+03:00,8373.0,264478.0,406.0
469
- 467,2021-05-27 00:00:00+03:00,9039.0,263356.0,402.0
470
- 468,2021-05-28 00:00:00+03:00,9252.0,262819.0,404.0
471
- 469,2021-05-29 00:00:00+03:00,9289.0,262457.0,401.0
472
- 470,2021-05-30 00:00:00+03:00,9694.0,264410.0,355.0
473
- 471,2021-05-31 00:00:00+03:00,8475.0,265831.0,339.0
474
- 472,2021-06-01 00:00:00+03:00,9500.0,265965.0,372.0
475
- 473,2021-06-02 00:00:00+03:00,8832.0,265383.0,394.0
476
- 474,2021-06-03 00:00:00+03:00,8933.0,264540.0,393.0
477
- 475,2021-06-04 00:00:00+03:00,8947.0,264580.0,377.0
478
- 476,2021-06-05 00:00:00+03:00,9145.0,264761.0,399.0
479
- 477,2021-06-06 00:00:00+03:00,9163.0,266204.0,351.0
480
- 478,2021-06-07 00:00:00+03:00,9429.0,268547.0,330.0
481
- 479,2021-06-08 00:00:00+03:00,9977.0,269262.0,379.0
482
- 480,2021-06-09 00:00:00+03:00,10407.0,269456.0,399.0
483
- 481,2021-06-10 00:00:00+03:00,11699.0,270676.0,383.0
484
- 482,2021-06-11 00:00:00+03:00,12505.0,272597.0,396.0
485
- 483,2021-06-12 00:00:00+03:00,13510.0,275722.0,399.0
486
- 484,2021-06-13 00:00:00+03:00,14723.0,280922.0,357.0
487
- 485,2021-06-14 00:00:00+03:00,13721.0,285960.0,371.0
488
- 486,2021-06-15 00:00:00+03:00,14185.0,291169.0,379.0
489
- 487,2021-06-16 00:00:00+03:00,13397.0,293914.0,396.0
490
- 488,2021-06-17 00:00:00+03:00,14057.0,296350.0,416.0
491
- 489,2021-06-18 00:00:00+03:00,17262.0,302205.0,453.0
492
- 490,2021-06-19 00:00:00+03:00,17906.0,308961.0,466.0
493
- 491,2021-06-20 00:00:00+03:00,17611.0,317493.0,450.0
494
- 492,2021-06-21 00:00:00+03:00,17378.0,326070.0,440.0
495
- 493,2021-06-22 00:00:00+03:00,16715.0,331122.0,546.0
496
- 494,2021-06-23 00:00:00+03:00,17594.0,335508.0,548.0
497
- 495,2021-06-24 00:00:00+03:00,20182.0,341617.0,568.0
498
- 496,2021-06-25 00:00:00+03:00,20393.0,347385.0,601.0
499
- 497,2021-06-26 00:00:00+03:00,21665.0,354084.0,619.0
500
- 498,2021-06-27 00:00:00+03:00,20538.0,361295.0,599.0
501
- 499,2021-06-28 00:00:00+03:00,21650.0,369708.0,611.0
502
- 500,2021-06-29 00:00:00+03:00,20616.0,374975.0,652.0
503
- 501,2021-06-30 00:00:00+03:00,21042.0,378992.0,669.0
504
- 502,2021-07-01 00:00:00+03:00,23543.0,384935.0,672.0
505
- 503,2021-07-02 00:00:00+03:00,23218.0,389277.0,679.0
506
- 504,2021-07-03 00:00:00+03:00,24439.0,395120.0,697.0
507
- 505,2021-07-04 00:00:00+03:00,25142.0,404115.0,663.0
508
- 506,2021-07-05 00:00:00+03:00,24353.0,413274.0,654.0
509
- 507,2021-07-06 00:00:00+03:00,23378.0,417504.0,737.0
510
- 508,2021-07-07 00:00:00+03:00,23962.0,420674.0,725.0
511
- 509,2021-07-08 00:00:00+03:00,24818.0,423422.0,734.0
512
- 510,2021-07-09 00:00:00+03:00,25766.0,426630.0,726.0
513
- 511,2021-07-10 00:00:00+03:00,25082.0,433210.0,752.0
514
- 512,2021-07-11 00:00:00+03:00,25033.0,440112.0,749.0
515
- 513,2021-07-12 00:00:00+03:00,25140.0,448113.0,710.0
516
- 514,2021-07-13 00:00:00+03:00,24702.0,452469.0,780.0
517
- 515,2021-07-14 00:00:00+03:00,23827.0,454241.0,786.0
518
- 516,2021-07-15 00:00:00+03:00,25293.0,457250.0,791.0
519
- 517,2021-07-16 00:00:00+03:00,25704.0,460223.0,799.0
520
- 518,2021-07-17 00:00:00+03:00,25116.0,463115.0,787.0
521
- 519,2021-07-18 00:00:00+03:00,25018.0,468483.0,764.0
522
- 520,2021-07-19 00:00:00+03:00,24633.0,473633.0,719.0
523
- 521,2021-07-20 00:00:00+03:00,23770.0,474401.0,784.0
524
- 522,2021-07-21 00:00:00+03:00,23704.0,474738.0,783.0
525
- 523,2021-07-22 00:00:00+03:00,24471.0,475753.0,796.0
526
- 524,2021-07-23 00:00:00+03:00,23811.0,476222.0,795.0
527
- 525,2021-07-24 00:00:00+03:00,23947.0,477418.0,799.0
528
- 526,2021-07-25 00:00:00+03:00,24072.0,482033.0,779.0
529
- 527,2021-07-26 00:00:00+03:00,23239.0,488345.0,727.0
530
- 528,2021-07-27 00:00:00+03:00,23032.0,490482.0,779.0
531
- 529,2021-07-28 00:00:00+03:00,22420.0,491525.0,798.0
532
- 530,2021-07-29 00:00:00+03:00,23270.0,493162.0,799.0
533
- 531,2021-07-30 00:00:00+03:00,23564.0,495447.0,794.0
534
- 532,2021-07-31 00:00:00+03:00,23807.0,498691.0,792.0
535
- 533,2021-08-01 00:00:00+03:00,22804.0,503435.0,789.0
536
- 534,2021-08-02 00:00:00+03:00,23508.0,511265.0,785.0
537
- 535,2021-08-03 00:00:00+03:00,22010.0,513524.0,788.0
538
- 536,2021-08-04 00:00:00+03:00,22589.0,515227.0,790.0
539
- 537,2021-08-05 00:00:00+03:00,23120.0,517183.0,794.0
540
- 538,2021-08-06 00:00:00+03:00,22660.0,518910.0,792.0
541
- 539,2021-08-07 00:00:00+03:00,22320.0,520952.0,793.0
542
- 540,2021-08-08 00:00:00+03:00,22866.0,527362.0,787.0
543
- 541,2021-08-09 00:00:00+03:00,22160.0,534279.0,769.0
544
- 542,2021-08-10 00:00:00+03:00,21378.0,536136.0,792.0
545
- 543,2021-08-11 00:00:00+03:00,21571.0,536841.0,799.0
546
- 544,2021-08-12 00:00:00+03:00,21932.0,537770.0,808.0
547
- 545,2021-08-13 00:00:00+03:00,22277.0,539864.0,815.0
548
- 546,2021-08-14 00:00:00+03:00,22144.0,541639.0,819.0
549
- 547,2021-08-15 00:00:00+03:00,21624.0,546021.0,816.0
550
- 548,2021-08-16 00:00:00+03:00,20765.0,550379.0,806.0
551
- 549,2021-08-17 00:00:00+03:00,20958.0,552125.0,805.0
552
- 550,2021-08-18 00:00:00+03:00,20914.0,551527.0,799.0
553
- 551,2021-08-19 00:00:00+03:00,21058.0,547777.0,791.0
554
- 552,2021-08-20 00:00:00+03:00,20992.0,547633.0,785.0
555
- 553,2021-08-21 00:00:00+03:00,21000.0,547189.0,797.0
556
- 554,2021-08-22 00:00:00+03:00,20564.0,551577.0,762.0
557
- 555,2021-08-23 00:00:00+03:00,19454.0,554854.0,776.0
558
- 556,2021-08-24 00:00:00+03:00,18833.0,554257.0,794.0
559
- 557,2021-08-25 00:00:00+03:00,19536.0,553330.0,809.0
560
- 558,2021-08-26 00:00:00+03:00,19630.0,552479.0,820.0
561
- 559,2021-08-27 00:00:00+03:00,19509.0,551973.0,798.0
562
- 560,2021-08-28 00:00:00+03:00,19492.0,551255.0,799.0
563
- 561,2021-08-29 00:00:00+03:00,19286.0,552940.0,797.0
564
- 562,2021-08-30 00:00:00+03:00,18325.0,556293.0,792.0
565
- 563,2021-08-31 00:00:00+03:00,17813.0,554687.0,795.0
566
- 564,2021-09-01 00:00:00+03:00,18368.0,553940.0,790.0
567
- 565,2021-09-02 00:00:00+03:00,18985.0,553458.0,798.0
568
- 566,2021-09-03 00:00:00+03:00,18856.0,552825.0,799.0
569
- 567,2021-09-04 00:00:00+03:00,18780.0,552072.0,796.0
570
- 568,2021-09-05 00:00:00+03:00,18645.0,554668.0,793.0
571
- 569,2021-09-06 00:00:00+03:00,17856.0,557458.0,790.0
572
- 570,2021-09-07 00:00:00+03:00,17425.0,556845.0,795.0
573
- 571,2021-09-08 00:00:00+03:00,18024.0,555810.0,797.0
574
- 572,2021-09-09 00:00:00+03:00,18380.0,553757.0,794.0
575
- 573,2021-09-10 00:00:00+03:00,18341.0,554188.0,789.0
576
- 574,2021-09-11 00:00:00+03:00,18891.0,554395.0,796.0
577
- 575,2021-09-12 00:00:00+03:00,18554.0,557664.0,788.0
578
- 576,2021-09-13 00:00:00+03:00,18178.0,562654.0,719.0
579
- 577,2021-09-14 00:00:00+03:00,17837.0,563803.0,781.0
580
- 578,2021-09-15 00:00:00+03:00,18841.0,564813.0,792.0
581
- 579,2021-09-16 00:00:00+03:00,19594.0,566287.0,794.0
582
- 580,2021-09-17 00:00:00+03:00,19905.0,568782.0,791.0
583
- 581,2021-09-18 00:00:00+03:00,20329.0,572065.0,799.0
584
- 582,2021-09-19 00:00:00+03:00,20174.0,578028.0,793.0
585
- 583,2021-09-20 00:00:00+03:00,19744.0,585002.0,778.0
586
- 584,2021-09-21 00:00:00+03:00,19179.0,587932.0,812.0
587
- 585,2021-09-22 00:00:00+03:00,19706.0,590719.0,817.0
588
- 586,2021-09-23 00:00:00+03:00,21438.0,594770.0,820.0
589
- 587,2021-09-24 00:00:00+03:00,21379.0,599493.0,828.0
590
- 588,2021-09-25 00:00:00+03:00,22041.0,604387.0,822.0
591
- 589,2021-09-26 00:00:00+03:00,22498.0,612409.0,805.0
592
- 590,2021-09-27 00:00:00+03:00,22236.0,620353.0,779.0
593
- 591,2021-09-28 00:00:00+03:00,21559.0,623692.0,852.0
594
- 592,2021-09-29 00:00:00+03:00,22430.0,626809.0,857.0
595
- 593,2021-09-30 00:00:00+03:00,23888.0,631004.0,867.0
596
- 594,2021-10-01 00:00:00+03:00,24522.0,634684.0,887.0
597
- 595,2021-10-02 00:00:00+03:00,25219.0,641165.0,886.0
598
- 596,2021-10-03 00:00:00+03:00,25769.0,650653.0,890.0
599
- 597,2021-10-04 00:00:00+03:00,25781.0,661025.0,883.0
600
- 598,2021-10-05 00:00:00+03:00,25110.0,666672.0,895.0
601
- 599,2021-10-06 00:00:00+03:00,25133.0,671035.0,929.0
602
- 600,2021-10-07 00:00:00+03:00,27550.0,677331.0,924.0
603
- 601,2021-10-08 00:00:00+03:00,27246.0,683075.0,936.0
604
- 602,2021-10-09 00:00:00+03:00,29362.0,690420.0,968.0
605
- 603,2021-10-10 00:00:00+03:00,28647.0,700831.0,962.0
606
- 604,2021-10-11 00:00:00+03:00,29409.0,713823.0,957.0
607
- 605,2021-10-12 00:00:00+03:00,28190.0,720334.0,973.0
608
- 606,2021-10-13 00:00:00+03:00,28717.0,726266.0,984.0
609
- 607,2021-10-14 00:00:00+03:00,31299.0,734909.0,986.0
610
- 608,2021-10-15 00:00:00+03:00,32196.0,743839.0,998.0
611
- 609,2021-10-16 00:00:00+03:00,33208.0,754162.0,1002.0
612
- 610,2021-10-17 00:00:00+03:00,34303.0,768751.0,997.0
613
- 611,2021-10-18 00:00:00+03:00,34325.0,785647.0,998.0
614
- 612,2021-10-19 00:00:00+03:00,33740.0,794946.0,1015.0
615
- 613,2021-10-20 00:00:00+03:00,34073.0,802760.0,1028.0
616
- 614,2021-10-21 00:00:00+03:00,36339.0,812168.0,1036.0
617
- 615,2021-10-22 00:00:00+03:00,37141.0,822792.0,1064.0
618
- 616,2021-10-23 00:00:00+03:00,37678.0,833318.0,1075.0
619
- 617,2021-10-24 00:00:00+03:00,35660.0,845122.0,1072.0
620
- 618,2021-10-25 00:00:00+03:00,37930.0,861293.0,1069.0
621
- 619,2021-10-26 00:00:00+03:00,36446.0,869660.0,1106.0
622
- 620,2021-10-27 00:00:00+03:00,36582.0,875968.0,1123.0
623
- 621,2021-10-28 00:00:00+03:00,40096.0,885587.0,1159.0
624
- 622,2021-10-29 00:00:00+03:00,39849.0,893811.0,1163.0
625
- 623,2021-10-30 00:00:00+03:00,40251.0,903993.0,1160.0
626
- 624,2021-10-31 00:00:00+03:00,40993.0,916713.0,1158.0
627
- 625,2021-11-01 00:00:00+03:00,40402.0,932773.0,1155.0
628
- 626,2021-11-02 00:00:00+03:00,39008.0,939698.0,1178.0
629
- 627,2021-11-03 00:00:00+03:00,40443.0,946145.0,1189.0
630
- 628,2021-11-04 00:00:00+03:00,40217.0,953239.0,1195.0
631
- 629,2021-11-05 00:00:00+03:00,40735.0,964177.0,1192.0
632
- 630,2021-11-06 00:00:00+03:00,41335.0,975123.0,1188.0
633
- 631,2021-11-07 00:00:00+03:00,39165.0,986303.0,1179.0
634
- 632,2021-11-08 00:00:00+03:00,39400.0,998931.0,1190.0
635
- 633,2021-11-09 00:00:00+03:00,39160.0,1004844.0,1211.0
636
- 634,2021-11-10 00:00:00+03:00,38058.0,1007098.0,1239.0
637
- 635,2021-11-11 00:00:00+03:00,40759.0,1013464.0,1237.0
638
- 636,2021-11-12 00:00:00+03:00,40123.0,1018707.0,1235.0
639
- 637,2021-11-13 00:00:00+03:00,39256.0,1022920.0,1241.0
640
- 638,2021-11-14 00:00:00+03:00,38823.0,1030703.0,1219.0
641
- 639,2021-11-15 00:00:00+03:00,38420.0,1040210.0,1211.0
642
- 640,2021-11-16 00:00:00+03:00,36818.0,1041627.0,1240.0
643
- 641,2021-11-17 00:00:00+03:00,36626.0,1040618.0,1247.0
644
- 642,2021-11-18 00:00:00+03:00,37374.0,1040327.0,1251.0
645
- 643,2021-11-19 00:00:00+03:00,37156.0,1039225.0,1254.0
646
- 644,2021-11-20 00:00:00+03:00,37120.0,1038919.0,1254.0
647
- 645,2021-11-21 00:00:00+03:00,36970.0,1042133.0,1252.0
648
- 646,2021-11-22 00:00:00+03:00,35681.0,1047860.0,1241.0
649
- 647,2021-11-23 00:00:00+03:00,33996.0,1044562.0,1243.0
650
- 648,2021-11-24 00:00:00+03:00,33558.0,1040198.0,1240.0
651
- 649,2021-11-25 00:00:00+03:00,33796.0,1034306.0,1238.0
652
- 650,2021-11-26 00:00:00+03:00,34690.0,1031616.0,1235.0
653
- 651,2021-11-27 00:00:00+03:00,33946.0,1027829.0,1239.0
654
- 652,2021-11-28 00:00:00+03:00,33548.0,1029507.0,1224.0
655
- 653,2021-11-29 00:00:00+03:00,33860.0,1034458.0,1209.0
656
- 654,2021-11-30 00:00:00+03:00,32648.0,1032435.0,1229.0
657
- 655,2021-12-01 00:00:00+03:00,32837.0,1028367.0,1226.0
658
- 656,2021-12-02 00:00:00+03:00,33389.0,1025350.0,1221.0
659
- 657,2021-12-03 00:00:00+03:00,32930.0,1020549.0,1217.0
660
- 658,2021-12-04 00:00:00+03:00,32974.0,1017126.0,1215.0
661
- 659,2021-12-05 00:00:00+03:00,32602.0,1017929.0,1206.0
662
- 660,2021-12-06 00:00:00+03:00,32136.0,1020811.0,1184.0
663
- 661,2021-12-07 00:00:00+03:00,31096.0,1016110.0,1182.0
664
- 662,2021-12-08 00:00:00+03:00,30752.0,1008707.0,1179.0
665
- 663,2021-12-09 00:00:00+03:00,30209.0,1001941.0,1181.0
666
- 664,2021-12-10 00:00:00+03:00,30873.0,995981.0,1176.0
667
- 665,2021-12-11 00:00:00+03:00,30288.0,988652.0,1171.0
668
- 666,2021-12-12 00:00:00+03:00,29929.0,986058.0,1132.0
669
- 667,2021-12-13 00:00:00+03:00,29558.0,985934.0,1121.0
670
- 668,2021-12-14 00:00:00+03:00,28343.0,979048.0,1145.0
671
- 669,2021-12-15 00:00:00+03:00,28363.0,970636.0,1142.0
672
- 670,2021-12-16 00:00:00+03:00,28486.0,960834.0,1133.0
673
- 671,2021-12-17 00:00:00+03:00,27743.0,950060.0,1080.0
674
- 672,2021-12-18 00:00:00+03:00,27434.0,938377.0,1076.0
675
- 673,2021-12-19 00:00:00+03:00,27967.0,932666.0,1023.0
676
- 674,2021-12-20 00:00:00+03:00,27022.0,928610.0,1019.0
677
- 675,2021-12-21 00:00:00+03:00,25907.0,913271.0,1027.0
678
- 676,2021-12-22 00:00:00+03:00,25264.0,895193.0,1020.0
679
- 677,2021-12-23 00:00:00+03:00,25667.0,878213.0,1002.0
680
- 678,2021-12-24 00:00:00+03:00,24703.0,860705.0,998.0
681
- 679,2021-12-25 00:00:00+03:00,24946.0,842563.0,981.0
682
- 680,2021-12-26 00:00:00+03:00,23721.0,828031.0,968.0
683
- 681,2021-12-27 00:00:00+03:00,23210.0,816589.0,937.0
684
- 682,2021-12-28 00:00:00+03:00,21922.0,793615.0,935.0
685
- 683,2021-12-29 00:00:00+03:00,21119.0,771026.0,932.0
686
- 684,2021-12-30 00:00:00+03:00,21073.0,748169.0,926.0
687
- 685,2021-12-31 00:00:00+03:00,20638.0,727203.0,912.0
688
- 686,2022-01-01 00:00:00+03:00,19751.0,712963.0,847.0
689
- 687,2022-01-02 00:00:00+03:00,18233.0,703409.0,811.0
690
- 688,2022-01-03 00:00:00+03:00,16343.0,694880.0,835.0
691
- 689,2022-01-04 00:00:00+03:00,15903.0,682878.0,834.0
692
- 690,2022-01-05 00:00:00+03:00,15772.0,672241.0,828.0
693
- 691,2022-01-06 00:00:00+03:00,15316.0,663806.0,802.0
694
- 692,2022-01-07 00:00:00+03:00,16735.0,657719.0,787.0
695
- 693,2022-01-08 00:00:00+03:00,16568.0,653042.0,796.0
696
- 694,2022-01-09 00:00:00+03:00,16246.0,647774.0,763.0
697
- 695,2022-01-10 00:00:00+03:00,15830.0,642973.0,741.0
698
- 696,2022-01-11 00:00:00+03:00,17525.0,634499.0,783.0
699
- 697,2022-01-12 00:00:00+03:00,17946.0,625354.0,745.0
700
- 698,2022-01-13 00:00:00+03:00,21155.0,619785.0,740.0
701
- 699,2022-01-14 00:00:00+03:00,23820.0,617914.0,739.0
702
- 700,2022-01-15 00:00:00+03:00,27179.0,617786.0,723.0
703
- 701,2022-01-16 00:00:00+03:00,29230.0,623599.0,686.0
704
- 702,2022-01-17 00:00:00+03:00,30726.0,633899.0,670.0
705
- 703,2022-01-18 00:00:00+03:00,31252.0,639899.0,688.0
706
- 704,2022-01-19 00:00:00+03:00,33899.0,650180.0,698.0
707
- 705,2022-01-20 00:00:00+03:00,38850.0,663868.0,684.0
708
- 706,2022-01-21 00:00:00+03:00,49513.0,687970.0,692.0
709
- 707,2022-01-22 00:00:00+03:00,49485.82,718976.0,681.0
710
- 708,2022-01-23 00:00:00+03:00,49458.64,758457.0,679.0
711
- 709,2022-01-24 00:00:00+03:00,49431.46,801197.0,655.0
712
- 710,2022-01-25 00:00:00+03:00,49404.28,841921.0,681.0
713
- 711,2022-01-26 00:00:00+03:00,49377.1,887759.0,657.0
714
- 712,2022-01-27 00:00:00+03:00,49349.92,946156.0,665.0
715
- 713,2022-01-28 00:00:00+03:00,49322.74,1014017.0,673.0
716
- 714,2022-01-29 00:00:00+03:00,49295.56,1014783.3,668.0
717
- 715,2022-01-30 00:00:00+03:00,49268.38,1015549.6,617.0
718
- 716,2022-01-31 00:00:00+03:00,49241.2,1016315.9,621.0
719
- 717,2022-02-01 00:00:00+03:00,49214.02,1017082.2,663.0
720
- 718,2022-02-02 00:00:00+03:00,49186.84,1017848.5,678.0
721
- 719,2022-02-03 00:00:00+03:00,49159.66,1018614.8,667.0
722
- 720,2022-02-04 00:00:00+03:00,49132.48,1019381.1,682.0
723
- 721,2022-02-05 00:00:00+03:00,49105.3,1020147.4,714.0
724
- 722,2022-02-06 00:00:00+03:00,49078.12,1020913.7,661.0
725
- 723,2022-02-07 00:00:00+03:00,49050.94,1021680.0,609.0
726
- 724,2022-02-08 00:00:00+03:00,49023.76,1022446.3,698.0
727
- 725,2022-02-09 00:00:00+03:00,48996.58,1023212.6,669.0
728
- 726,2022-02-10 00:00:00+03:00,48969.4,1023978.9,701.0
729
- 727,2022-02-11 00:00:00+03:00,48942.22,1024745.2,722.0
730
- 728,2022-02-12 00:00:00+03:00,48915.04,1025511.5,729.0
731
- 729,2022-02-13 00:00:00+03:00,48887.86,1026277.8,706.0
732
- 730,2022-02-14 00:00:00+03:00,48860.68,1027044.1,683.0
733
- 731,2022-02-15 00:00:00+03:00,48833.5,1027810.4,704.0
734
- 732,2022-02-16 00:00:00+03:00,48806.32,1028576.7,748.0
735
- 733,2022-02-17 00:00:00+03:00,48779.14,1029343.0,790.0
736
- 734,2022-02-18 00:00:00+03:00,48751.96,1030109.3,784.0
737
- 735,2022-02-19 00:00:00+03:00,48724.78,1030875.6,798.0
738
- 736,2022-02-20 00:00:00+03:00,48697.6,1031641.9,745.0
739
- 737,2022-02-21 00:00:00+03:00,48670.42,1032408.2,735.0
740
- 738,2022-02-22 00:00:00+03:00,48643.24,1033174.5,796.0
741
- 739,2022-02-23 00:00:00+03:00,48616.06,1033940.8,785.0
742
- 740,2022-02-24 00:00:00+03:00,48588.88,1034707.1,762.0
743
- 741,2022-02-25 00:00:00+03:00,48561.7,1035473.4,787.0
744
- 742,2022-02-26 00:00:00+03:00,48534.52,1036239.7,793.0
745
- 743,2022-02-27 00:00:00+03:00,48507.34,1037006.0,769.0
746
- 744,2022-02-28 00:00:00+03:00,48480.16,1037772.3,733.0
747
- 745,2022-03-01 00:00:00+03:00,48452.98,1038538.6,786.0
748
- 746,2022-03-02 00:00:00+03:00,48425.8,1039304.9,784.0
749
- 747,2022-03-03 00:00:00+03:00,48398.62,1040071.2,781.0
750
- 748,2022-03-04 00:00:00+03:00,48371.44,1040837.5,776.0
751
- 749,2022-03-05 00:00:00+03:00,48344.26,1041603.8,750.0
752
- 750,2022-03-06 00:00:00+03:00,48317.08,1042370.1,744.0
753
- 751,2022-03-07 00:00:00+03:00,48289.9,1043136.4,668.0
754
- 752,2022-03-08 00:00:00+03:00,48262.72,1043902.7,652.0
755
- 753,2022-03-09 00:00:00+03:00,48235.54,1044669.0,645.0
756
- 754,2022-03-10 00:00:00+03:00,48208.36,1045435.3,665.0
757
- 755,2022-03-11 00:00:00+03:00,48181.18,1046201.6,674.0
758
- 756,2022-03-12 00:00:00+03:00,48154.0,1046967.9,630.0
759
- 757,2022-03-13 00:00:00+03:00,44989.0,1047734.2,596.0
760
- 758,2022-03-14 00:00:00+03:00,41055.0,1048500.5,533.0
761
- 759,2022-03-15 00:00:00+03:00,36678.0,1049266.8,558.0
762
- 760,2022-03-16 00:00:00+03:00,36519.0,1050033.1,576.0
763
- 761,2022-03-17 00:00:00+03:00,34819.0,1050799.4,561.0
764
- 762,2022-03-18 00:00:00+03:00,34442.0,1051565.7,524.0
765
- 763,2022-03-19 00:00:00+03:00,32958.0,1052332.0,495.0
766
- 764,2022-03-20 00:00:00+03:00,31035.0,1008258.0,434.0
767
- 765,2022-03-21 00:00:00+03:00,28709.0,974620.0,409.0
768
- 766,2022-03-22 00:00:00+03:00,26394.0,925622.0,472.0
769
- 767,2022-03-23 00:00:00+03:00,26826.0,881397.0,429.0
770
- 768,2022-03-24 00:00:00+03:00,25387.0,839890.0,418.0
771
- 769,2022-03-25 00:00:00+03:00,25382.0,803014.0,398.0
772
- 770,2022-03-26 00:00:00+03:00,24072.0,765758.0,395.0
773
- 771,2022-03-27 00:00:00+03:00,23280.0,741160.0,338.0
774
- 772,2022-03-28 00:00:00+03:00,21101.0,726180.0,335.0
775
- 773,2022-03-29 00:00:00+03:00,19660.0,698272.0,339.0
776
- 774,2022-03-30 00:00:00+03:00,20145.0,666980.0,352.0
777
- 775,2022-03-31 00:00:00+03:00,19277.0,635416.0,345.0
778
- 776,2022-04-01 00:00:00+03:00,19164.0,608240.0,342.0
779
- 777,2022-04-02 00:00:00+03:00,17949.0,581302.0,340.0
780
- 778,2022-04-03 00:00:00+03:00,16828.0,562131.0,304.0
781
- 779,2022-04-04 00:00:00+03:00,15291.0,544285.0,287.0
782
- 780,2022-04-05 00:00:00+03:00,13947.0,520457.0,316.0
783
- 781,2022-04-06 00:00:00+03:00,14661.0,499521.0,291.0
784
- 782,2022-04-07 00:00:00+03:00,14355.0,478285.0,287.0
785
- 783,2022-04-08 00:00:00+03:00,14311.0,454632.0,280.0
786
- 784,2022-04-09 00:00:00+03:00,13573.0,427817.0,288.0
787
- 785,2022-04-10 00:00:00+03:00,13056.0,411242.0,259.0
788
- 786,2022-04-11 00:00:00+03:00,11855.0,396094.0,248.0
789
- 787,2022-04-12 00:00:00+03:00,10910.0,375452.0,281.0
790
- 788,2022-04-13 00:00:00+03:00,11754.0,358804.0,267.0
791
- 789,2022-04-14 00:00:00+03:00,11348.0,348045.0,254.0
792
- 790,2022-04-15 00:00:00+03:00,11432.0,339693.0,261.0
793
- 791,2022-04-16 00:00:00+03:00,11095.0,331542.0,240.0
794
- 792,2022-04-17 00:00:00+03:00,10263.0,325076.0,233.0
795
- 793,2022-04-18 00:00:00+03:00,9434.0,319973.0,213.0
796
- 794,2022-04-19 00:00:00+03:00,8640.0,311615.0,235.0
797
- 795,2022-04-20 00:00:00+03:00,9195.0,304387.0,223.0
798
- 796,2022-04-21 00:00:00+03:00,8875.0,298883.0,197.0
799
- 797,2022-04-22 00:00:00+03:00,9001.0,294209.0,195.0
800
- 798,2022-04-23 00:00:00+03:00,8829.0,289837.0,171.0
801
- 799,2022-04-24 00:00:00+03:00,8446.0,287607.0,168.0
802
- 800,2022-04-25 00:00:00+03:00,7651.0,286244.0,159.0
803
- 801,2022-04-26 00:00:00+03:00,7107.0,281276.0,176.0
804
- 802,2022-04-27 00:00:00+03:00,7705.0,277341.0,163.0
805
- 803,2022-04-28 00:00:00+03:00,7681.0,273793.0,166.0
806
- 804,2022-04-29 00:00:00+03:00,7710.0,270301.0,161.0
807
- 805,2022-04-30 00:00:00+03:00,7363.0,266485.0,157.0
808
- 806,2022-05-01 00:00:00+03:00,7047.0,264652.0,147.0
809
- 807,2022-05-02 00:00:00+03:00,6207.0,263221.0,136.0
810
- 808,2022-05-03 00:00:00+03:00,5466.0,261510.0,125.0
811
- 809,2022-05-04 00:00:00+03:00,5093.0,259810.0,129.0
812
- 810,2022-05-05 00:00:00+03:00,5011.0,255959.0,139.0
813
- 811,2022-05-06 00:00:00+03:00,5541.0,251956.0,136.0
814
- 812,2022-05-07 00:00:00+03:00,5500.0,248675.0,132.0
815
- 813,2022-05-08 00:00:00+03:00,5447.0,247322.0,118.0
816
- 814,2022-05-09 00:00:00+03:00,5030.0,246290.0,103.0
817
- 815,2022-05-10 00:00:00+03:00,4531.0,245706.0,101.0
818
- 816,2022-05-11 00:00:00+03:00,4102.0,244667.0,98.0
819
- 817,2022-05-12 00:00:00+03:00,4065.0,241691.0,111.0
820
- 818,2022-05-13 00:00:00+03:00,4896.0,239225.0,105.0
821
- 819,2022-05-14 00:00:00+03:00,5047.0,236787.0,107.0
 
1
+ timestamp,DailyNewCases,ActiveCases,DailyNewDeaths
2
+ 2020-02-15 00:00:00+03:00,0.0,0.0,0.0
3
+ 2020-02-16 00:00:00+03:00,0.0,0.0,0.0
4
+ 2020-02-17 00:00:00+03:00,0.0,0.0,0.0
5
+ 2020-02-18 00:00:00+03:00,0.0,0.0,0.0
6
+ 2020-02-19 00:00:00+03:00,0.0,0.0,0.0
7
+ 2020-02-20 00:00:00+03:00,0.0,0.0,0.0
8
+ 2020-02-21 00:00:00+03:00,0.0,0.0,0.0
9
+ 2020-02-22 00:00:00+03:00,0.0,0.0,0.0
10
+ 2020-02-23 00:00:00+03:00,0.0,0.0,0.0
11
+ 2020-02-24 00:00:00+03:00,0.0,0.0,0.0
12
+ 2020-02-25 00:00:00+03:00,0.0,0.0,0.0
13
+ 2020-02-26 00:00:00+03:00,0.0,0.0,0.0
14
+ 2020-02-27 00:00:00+03:00,0.0,0.0,0.0
15
+ 2020-02-28 00:00:00+03:00,0.0,0.0,0.0
16
+ 2020-02-29 00:00:00+03:00,0.0,0.0,0.0
17
+ 2020-03-01 00:00:00+03:00,0.0,0.0,0.0
18
+ 2020-03-02 00:00:00+03:00,1.0,1.0,0.0
19
+ 2020-03-03 00:00:00+03:00,0.0,1.0,0.0
20
+ 2020-03-04 00:00:00+03:00,0.0,1.0,0.0
21
+ 2020-03-05 00:00:00+03:00,4.0,5.0,0.0
22
+ 2020-03-06 00:00:00+03:00,6.0,11.0,0.0
23
+ 2020-03-07 00:00:00+03:00,1.0,11.0,0.0
24
+ 2020-03-08 00:00:00+03:00,3.0,14.0,0.0
25
+ 2020-03-09 00:00:00+03:00,3.0,17.0,0.0
26
+ 2020-03-10 00:00:00+03:00,0.0,17.0,0.0
27
+ 2020-03-11 00:00:00+03:00,8.0,25.0,0.0
28
+ 2020-03-12 00:00:00+03:00,6.0,31.0,0.0
29
+ 2020-03-13 00:00:00+03:00,11.0,37.0,0.0
30
+ 2020-03-14 00:00:00+03:00,14.0,51.0,0.0
31
+ 2020-03-15 00:00:00+03:00,4.0,55.0,0.0
32
+ 2020-03-16 00:00:00+03:00,30.0,85.0,0.0
33
+ 2020-03-17 00:00:00+03:00,21.0,106.0,0.0
34
+ 2020-03-18 00:00:00+03:00,33.0,139.0,0.0
35
+ 2020-03-19 00:00:00+03:00,52.0,190.0,1.0
36
+ 2020-03-20 00:00:00+03:00,54.0,240.0,0.0
37
+ 2020-03-21 00:00:00+03:00,53.0,289.0,0.0
38
+ 2020-03-22 00:00:00+03:00,61.0,350.0,0.0
39
+ 2020-03-23 00:00:00+03:00,71.0,420.0,0.0
40
+ 2020-03-24 00:00:00+03:00,57.0,472.0,0.0
41
+ 2020-03-25 00:00:00+03:00,163.0,626.0,2.0
42
+ 2020-03-26 00:00:00+03:00,182.0,799.0,0.0
43
+ 2020-03-27 00:00:00+03:00,196.0,987.0,1.0
44
+ 2020-03-28 00:00:00+03:00,228.0,1211.0,0.0
45
+ 2020-03-29 00:00:00+03:00,270.0,1462.0,4.0
46
+ 2020-03-30 00:00:00+03:00,302.0,1761.0,1.0
47
+ 2020-03-31 00:00:00+03:00,501.0,2199.0,8.0
48
+ 2020-04-01 00:00:00+03:00,440.0,2563.0,7.0
49
+ 2020-04-02 00:00:00+03:00,771.0,3283.0,6.0
50
+ 2020-04-03 00:00:00+03:00,601.0,3834.0,4.0
51
+ 2020-04-04 00:00:00+03:00,582.0,4355.0,9.0
52
+ 2020-04-05 00:00:00+03:00,658.0,4989.0,2.0
53
+ 2020-04-06 00:00:00+03:00,954.0,5890.0,2.0
54
+ 2020-04-07 00:00:00+03:00,1154.0,6945.0,11.0
55
+ 2020-04-08 00:00:00+03:00,1175.0,8029.0,5.0
56
+ 2020-04-09 00:00:00+03:00,1459.0,9357.0,13.0
57
+ 2020-04-10 00:00:00+03:00,1786.0,11028.0,18.0
58
+ 2020-04-11 00:00:00+03:00,1667.0,12433.0,12.0
59
+ 2020-04-12 00:00:00+03:00,2186.0,14349.0,24.0
60
+ 2020-04-13 00:00:00+03:00,2558.0,16710.0,18.0
61
+ 2020-04-14 00:00:00+03:00,2774.0,19238.0,22.0
62
+ 2020-04-15 00:00:00+03:00,3388.0,22306.0,28.0
63
+ 2020-04-16 00:00:00+03:00,3448.0,25402.0,34.0
64
+ 2020-04-17 00:00:00+03:00,4070.0,29145.0,41.0
65
+ 2020-04-18 00:00:00+03:00,4785.0,33423.0,40.0
66
+ 2020-04-19 00:00:00+03:00,6060.0,39201.0,48.0
67
+ 2020-04-20 00:00:00+03:00,4268.0,43270.0,44.0
68
+ 2020-04-21 00:00:00+03:00,5642.0,48434.0,51.0
69
+ 2020-04-22 00:00:00+03:00,5236.0,53066.0,57.0
70
+ 2020-04-23 00:00:00+03:00,4774.0,57327.0,42.0
71
+ 2020-04-24 00:00:00+03:00,5849.0,62439.0,60.0
72
+ 2020-04-25 00:00:00+03:00,5966.0,67657.0,66.0
73
+ 2020-04-26 00:00:00+03:00,6361.0,73435.0,66.0
74
+ 2020-04-27 00:00:00+03:00,6198.0,79007.0,47.0
75
+ 2020-04-28 00:00:00+03:00,6411.0,84235.0,73.0
76
+ 2020-04-29 00:00:00+03:00,5841.0,88141.0,105.0
77
+ 2020-04-30 00:00:00+03:00,7099.0,93806.0,101.0
78
+ 2020-05-01 00:00:00+03:00,7933.0,100042.0,96.0
79
+ 2020-05-02 00:00:00+03:00,9623.0,107819.0,53.0
80
+ 2020-05-03 00:00:00+03:00,10633.0,116768.0,58.0
81
+ 2020-05-04 00:00:00+03:00,10581.0,125817.0,76.0
82
+ 2020-05-05 00:00:00+03:00,10102.0,134054.0,95.0
83
+ 2020-05-06 00:00:00+03:00,10559.0,143065.0,86.0
84
+ 2020-05-07 00:00:00+03:00,11231.0,151732.0,88.0
85
+ 2020-05-08 00:00:00+03:00,10699.0,159528.0,98.0
86
+ 2020-05-09 00:00:00+03:00,10817.0,164933.0,104.0
87
+ 2020-05-10 00:00:00+03:00,11012.0,173467.0,88.0
88
+ 2020-05-11 00:00:00+03:00,11656.0,179534.0,94.0
89
+ 2020-05-12 00:00:00+03:00,10899.0,186615.0,107.0
90
+ 2020-05-13 00:00:00+03:00,10028.0,192056.0,96.0
91
+ 2020-05-14 00:00:00+03:00,9974.0,196410.0,93.0
92
+ 2020-05-15 00:00:00+03:00,10598.0,202199.0,113.0
93
+ 2020-05-16 00:00:00+03:00,9200.0,206340.0,119.0
94
+ 2020-05-17 00:00:00+03:00,9709.0,211748.0,94.0
95
+ 2020-05-18 00:00:00+03:00,8926.0,217747.0,91.0
96
+ 2020-05-19 00:00:00+03:00,9263.0,220974.0,115.0
97
+ 2020-05-20 00:00:00+03:00,8764.0,220341.0,135.0
98
+ 2020-05-21 00:00:00+03:00,8849.0,221774.0,127.0
99
+ 2020-05-22 00:00:00+03:00,8894.0,223374.0,150.0
100
+ 2020-05-23 00:00:00+03:00,9434.0,224558.0,139.0
101
+ 2020-05-24 00:00:00+03:00,8599.0,227641.0,153.0
102
+ 2020-05-25 00:00:00+03:00,8946.0,230996.0,92.0
103
+ 2020-05-26 00:00:00+03:00,8915.0,227406.0,174.0
104
+ 2020-05-27 00:00:00+03:00,8338.0,224504.0,161.0
105
+ 2020-05-28 00:00:00+03:00,8371.0,223916.0,174.0
106
+ 2020-05-29 00:00:00+03:00,8572.0,223992.0,232.0
107
+ 2020-05-30 00:00:00+03:00,8952.0,224551.0,181.0
108
+ 2020-05-31 00:00:00+03:00,9268.0,229267.0,138.0
109
+ 2020-06-01 00:00:00+03:00,9035.0,234146.0,162.0
110
+ 2020-06-02 00:00:00+03:00,8863.0,231719.0,182.0
111
+ 2020-06-03 00:00:00+03:00,8536.0,231105.0,178.0
112
+ 2020-06-04 00:00:00+03:00,8831.0,231101.0,169.0
113
+ 2020-06-05 00:00:00+03:00,8726.0,231626.0,144.0
114
+ 2020-06-06 00:00:00+03:00,8855.0,231576.0,197.0
115
+ 2020-06-07 00:00:00+03:00,8984.0,235083.0,134.0
116
+ 2020-06-08 00:00:00+03:00,8985.0,239999.0,112.0
117
+ 2020-06-09 00:00:00+03:00,8595.0,236714.0,171.0
118
+ 2020-06-10 00:00:00+03:00,8404.0,234516.0,216.0
119
+ 2020-06-11 00:00:00+03:00,8779.0,234754.0,174.0
120
+ 2020-06-12 00:00:00+03:00,8987.0,235338.0,183.0
121
+ 2020-06-13 00:00:00+03:00,8706.0,238659.0,114.0
122
+ 2020-06-14 00:00:00+03:00,8835.0,241966.0,119.0
123
+ 2020-06-15 00:00:00+03:00,8246.0,245580.0,143.0
124
+ 2020-06-16 00:00:00+03:00,8248.0,243868.0,193.0
125
+ 2020-06-17 00:00:00+03:00,7843.0,241481.0,194.0
126
+ 2020-06-18 00:00:00+03:00,7790.0,239468.0,182.0
127
+ 2020-06-19 00:00:00+03:00,7972.0,236816.0,181.0
128
+ 2020-06-20 00:00:00+03:00,7889.0,234358.0,161.0
129
+ 2020-06-21 00:00:00+03:00,7728.0,236858.0,109.0
130
+ 2020-06-22 00:00:00+03:00,7600.0,239658.0,95.0
131
+ 2020-06-23 00:00:00+03:00,7425.0,234917.0,153.0
132
+ 2020-06-24 00:00:00+03:00,7176.0,229546.0,154.0
133
+ 2020-06-25 00:00:00+03:00,7113.0,230225.0,92.0
134
+ 2020-06-26 00:00:00+03:00,6800.0,227861.0,176.0
135
+ 2020-06-27 00:00:00+03:00,6852.0,225325.0,188.0
136
+ 2020-06-28 00:00:00+03:00,6791.0,226277.0,104.0
137
+ 2020-06-29 00:00:00+03:00,6719.0,228560.0,93.0
138
+ 2020-06-30 00:00:00+03:00,6693.0,225879.0,154.0
139
+ 2020-07-01 00:00:00+03:00,6556.0,221938.0,216.0
140
+ 2020-07-02 00:00:00+03:00,6760.0,222504.0,147.0
141
+ 2020-07-03 00:00:00+03:00,6718.0,220131.0,176.0
142
+ 2020-07-04 00:00:00+03:00,6632.0,217609.0,168.0
143
+ 2020-07-05 00:00:00+03:00,6736.0,220340.0,134.0
144
+ 2020-07-06 00:00:00+03:00,6611.0,223237.0,135.0
145
+ 2020-07-07 00:00:00+03:00,6368.0,219856.0,198.0
146
+ 2020-07-08 00:00:00+03:00,6562.0,217614.0,173.0
147
+ 2020-07-09 00:00:00+03:00,6509.0,215142.0,176.0
148
+ 2020-07-10 00:00:00+03:00,6635.0,213851.0,174.0
149
+ 2020-07-11 00:00:00+03:00,6611.0,211896.0,188.0
150
+ 2020-07-12 00:00:00+03:00,6615.0,214766.0,130.0
151
+ 2020-07-13 00:00:00+03:00,6537.0,218239.0,104.0
152
+ 2020-07-14 00:00:00+03:00,6248.0,215508.0,175.0
153
+ 2020-07-15 00:00:00+03:00,6422.0,211350.0,156.0
154
+ 2020-07-16 00:00:00+03:00,6428.0,209168.0,167.0
155
+ 2020-07-17 00:00:00+03:00,6406.0,207707.0,186.0
156
+ 2020-07-18 00:00:00+03:00,6234.0,206327.0,124.0
157
+ 2020-07-19 00:00:00+03:00,6109.0,208860.0,95.0
158
+ 2020-07-20 00:00:00+03:00,5940.0,211457.0,85.0
159
+ 2020-07-21 00:00:00+03:00,5842.0,208364.0,153.0
160
+ 2020-07-22 00:00:00+03:00,5862.0,204392.0,165.0
161
+ 2020-07-23 00:00:00+03:00,5848.0,201816.0,147.0
162
+ 2020-07-24 00:00:00+03:00,5811.0,199029.0,154.0
163
+ 2020-07-25 00:00:00+03:00,5871.0,196388.0,146.0
164
+ 2020-07-26 00:00:00+03:00,5765.0,198966.0,77.0
165
+ 2020-07-27 00:00:00+03:00,5635.0,201437.0,85.0
166
+ 2020-07-28 00:00:00+03:00,5395.0,197794.0,150.0
167
+ 2020-07-29 00:00:00+03:00,5475.0,194984.0,169.0
168
+ 2020-07-30 00:00:00+03:00,5509.0,191042.0,129.0
169
+ 2020-07-31 00:00:00+03:00,5482.0,187608.0,161.0
170
+ 2020-08-01 00:00:00+03:00,5462.0,184861.0,95.0
171
+ 2020-08-02 00:00:00+03:00,5427.0,186569.0,70.0
172
+ 2020-08-03 00:00:00+03:00,5394.0,188464.0,79.0
173
+ 2020-08-04 00:00:00+03:00,5159.0,185601.0,144.0
174
+ 2020-08-05 00:00:00+03:00,5204.0,183111.0,139.0
175
+ 2020-08-06 00:00:00+03:00,5267.0,180931.0,116.0
176
+ 2020-08-07 00:00:00+03:00,5241.0,178818.0,119.0
177
+ 2020-08-08 00:00:00+03:00,5212.0,177286.0,129.0
178
+ 2020-08-09 00:00:00+03:00,5189.0,179183.0,77.0
179
+ 2020-08-10 00:00:00+03:00,5118.0,180972.0,70.0
180
+ 2020-08-11 00:00:00+03:00,4945.0,179293.0,130.0
181
+ 2020-08-12 00:00:00+03:00,5102.0,177143.0,129.0
182
+ 2020-08-13 00:00:00+03:00,5057.0,175978.0,124.0
183
+ 2020-08-14 00:00:00+03:00,5065.0,174361.0,114.0
184
+ 2020-08-15 00:00:00+03:00,5061.0,172856.0,119.0
185
+ 2020-08-16 00:00:00+03:00,4969.0,174200.0,68.0
186
+ 2020-08-17 00:00:00+03:00,4892.0,175904.0,55.0
187
+ 2020-08-18 00:00:00+03:00,4748.0,173993.0,132.0
188
+ 2020-08-19 00:00:00+03:00,4828.0,171909.0,117.0
189
+ 2020-08-20 00:00:00+03:00,4785.0,170494.0,110.0
190
+ 2020-08-21 00:00:00+03:00,4870.0,169457.0,90.0
191
+ 2020-08-22 00:00:00+03:00,4921.0,168110.0,121.0
192
+ 2020-08-23 00:00:00+03:00,4852.0,169727.0,73.0
193
+ 2020-08-24 00:00:00+03:00,4744.0,171950.0,65.0
194
+ 2020-08-25 00:00:00+03:00,4696.0,169874.0,120.0
195
+ 2020-08-26 00:00:00+03:00,4676.0,168032.0,115.0
196
+ 2020-08-27 00:00:00+03:00,4711.0,166211.0,121.0
197
+ 2020-08-28 00:00:00+03:00,4829.0,165025.0,110.0
198
+ 2020-08-29 00:00:00+03:00,4941.0,163938.0,111.0
199
+ 2020-08-30 00:00:00+03:00,4980.0,166251.0,68.0
200
+ 2020-08-31 00:00:00+03:00,4993.0,168756.0,83.0
201
+ 2020-09-01 00:00:00+03:00,4729.0,167044.0,123.0
202
+ 2020-09-02 00:00:00+03:00,4952.0,166417.0,115.0
203
+ 2020-09-03 00:00:00+03:00,4995.0,165532.0,114.0
204
+ 2020-09-04 00:00:00+03:00,5110.0,164709.0,121.0
205
+ 2020-09-05 00:00:00+03:00,5205.0,164425.0,110.0
206
+ 2020-09-06 00:00:00+03:00,5195.0,166736.0,61.0
207
+ 2020-09-07 00:00:00+03:00,5185.0,169542.0,51.0
208
+ 2020-09-08 00:00:00+03:00,5099.0,167747.0,122.0
209
+ 2020-09-09 00:00:00+03:00,5218.0,166414.0,142.0
210
+ 2020-09-10 00:00:00+03:00,5363.0,165734.0,128.0
211
+ 2020-09-11 00:00:00+03:00,5504.0,165402.0,102.0
212
+ 2020-09-12 00:00:00+03:00,5488.0,165343.0,119.0
213
+ 2020-09-13 00:00:00+03:00,5449.0,168008.0,94.0
214
+ 2020-09-14 00:00:00+03:00,5509.0,170985.0,57.0
215
+ 2020-09-15 00:00:00+03:00,5529.0,170759.0,150.0
216
+ 2020-09-16 00:00:00+03:00,5670.0,170488.0,132.0
217
+ 2020-09-17 00:00:00+03:00,5762.0,170352.0,144.0
218
+ 2020-09-18 00:00:00+03:00,5905.0,170784.0,134.0
219
+ 2020-09-19 00:00:00+03:00,6065.0,171450.0,144.0
220
+ 2020-09-20 00:00:00+03:00,6148.0,174624.0,79.0
221
+ 2020-09-21 00:00:00+03:00,6196.0,178133.0,71.0
222
+ 2020-09-22 00:00:00+03:00,6215.0,178212.0,160.0
223
+ 2020-09-23 00:00:00+03:00,6431.0,178743.0,150.0
224
+ 2020-09-24 00:00:00+03:00,6595.0,179059.0,149.0
225
+ 2020-09-25 00:00:00+03:00,7212.0,181846.0,108.0
226
+ 2020-09-26 00:00:00+03:00,7523.0,183196.0,169.0
227
+ 2020-09-27 00:00:00+03:00,7867.0,187896.0,99.0
228
+ 2020-09-28 00:00:00+03:00,8135.0,193268.0,61.0
229
+ 2020-09-29 00:00:00+03:00,8232.0,194861.0,160.0
230
+ 2020-09-30 00:00:00+03:00,8481.0,197307.0,177.0
231
+ 2020-10-01 00:00:00+03:00,8945.0,200098.0,169.0
232
+ 2020-10-02 00:00:00+03:00,9412.0,203270.0,186.0
233
+ 2020-10-03 00:00:00+03:00,9859.0,207392.0,174.0
234
+ 2020-10-04 00:00:00+03:00,10499.0,214500.0,107.0
235
+ 2020-10-05 00:00:00+03:00,10888.0,222090.0,117.0
236
+ 2020-10-06 00:00:00+03:00,11615.0,227265.0,188.0
237
+ 2020-10-07 00:00:00+03:00,11115.0,231479.0,202.0
238
+ 2020-10-08 00:00:00+03:00,11493.0,235727.0,191.0
239
+ 2020-10-09 00:00:00+03:00,12126.0,240560.0,201.0
240
+ 2020-10-10 00:00:00+03:00,12846.0,246428.0,197.0
241
+ 2020-10-11 00:00:00+03:00,13634.0,255679.0,143.0
242
+ 2020-10-12 00:00:00+03:00,13592.0,265353.0,125.0
243
+ 2020-10-13 00:00:00+03:00,13868.0,271427.0,244.0
244
+ 2020-10-14 00:00:00+03:00,14231.0,277499.0,239.0
245
+ 2020-10-15 00:00:00+03:00,13754.0,282575.0,286.0
246
+ 2020-10-16 00:00:00+03:00,15150.0,289008.0,232.0
247
+ 2020-10-17 00:00:00+03:00,14922.0,295034.0,279.0
248
+ 2020-10-18 00:00:00+03:00,15099.0,304571.0,185.0
249
+ 2020-10-19 00:00:00+03:00,15982.0,315046.0,179.0
250
+ 2020-10-20 00:00:00+03:00,16319.0,321392.0,269.0
251
+ 2020-10-21 00:00:00+03:00,15700.0,325823.0,317.0
252
+ 2020-10-22 00:00:00+03:00,15971.0,330076.0,290.0
253
+ 2020-10-23 00:00:00+03:00,17340.0,335870.0,283.0
254
+ 2020-10-24 00:00:00+03:00,16521.0,340528.0,296.0
255
+ 2020-10-25 00:00:00+03:00,16710.0,349305.0,229.0
256
+ 2020-10-26 00:00:00+03:00,17347.0,358859.0,219.0
257
+ 2020-10-27 00:00:00+03:00,16550.0,362245.0,320.0
258
+ 2020-10-28 00:00:00+03:00,16202.0,365740.0,346.0
259
+ 2020-10-29 00:00:00+03:00,17717.0,368351.0,366.0
260
+ 2020-10-30 00:00:00+03:00,18283.0,371760.0,355.0
261
+ 2020-10-31 00:00:00+03:00,18140.0,374712.0,334.0
262
+ 2020-11-01 00:00:00+03:00,18665.0,382873.0,245.0
263
+ 2020-11-02 00:00:00+03:00,18257.0,390532.0,238.0
264
+ 2020-11-03 00:00:00+03:00,18648.0,393494.0,355.0
265
+ 2020-11-04 00:00:00+03:00,19768.0,397306.0,389.0
266
+ 2020-11-05 00:00:00+03:00,19404.0,404180.0,292.0
267
+ 2020-11-06 00:00:00+03:00,20582.0,407429.0,378.0
268
+ 2020-11-07 00:00:00+03:00,20396.0,410658.0,364.0
269
+ 2020-11-08 00:00:00+03:00,20498.0,419378.0,286.0
270
+ 2020-11-09 00:00:00+03:00,21798.0,430198.0,256.0
271
+ 2020-11-10 00:00:00+03:00,20977.0,435207.0,368.0
272
+ 2020-11-11 00:00:00+03:00,19851.0,436010.0,432.0
273
+ 2020-11-12 00:00:00+03:00,21608.0,438368.0,439.0
274
+ 2020-11-13 00:00:00+03:00,21983.0,441205.0,411.0
275
+ 2020-11-14 00:00:00+03:00,22702.0,444890.0,391.0
276
+ 2020-11-15 00:00:00+03:00,22572.0,452654.0,352.0
277
+ 2020-11-16 00:00:00+03:00,22778.0,461265.0,303.0
278
+ 2020-11-17 00:00:00+03:00,22410.0,461178.0,442.0
279
+ 2020-11-18 00:00:00+03:00,20985.0,456528.0,456.0
280
+ 2020-11-19 00:00:00+03:00,23610.0,454102.0,463.0
281
+ 2020-11-20 00:00:00+03:00,24318.0,453201.0,461.0
282
+ 2020-11-21 00:00:00+03:00,24822.0,451535.0,467.0
283
+ 2020-11-22 00:00:00+03:00,24581.0,457707.0,401.0
284
+ 2020-11-23 00:00:00+03:00,25173.0,466517.0,361.0
285
+ 2020-11-24 00:00:00+03:00,24326.0,467126.0,491.0
286
+ 2020-11-25 00:00:00+03:00,23675.0,464546.0,507.0
287
+ 2020-11-26 00:00:00+03:00,25487.0,464436.0,524.0
288
+ 2020-11-27 00:00:00+03:00,27543.0,464801.0,496.0
289
+ 2020-11-28 00:00:00+03:00,27100.0,464095.0,510.0
290
+ 2020-11-29 00:00:00+03:00,26683.0,468332.0,459.0
291
+ 2020-11-30 00:00:00+03:00,26338.0,477055.0,368.0
292
+ 2020-12-01 00:00:00+03:00,26402.0,478125.0,569.0
293
+ 2020-12-02 00:00:00+03:00,25345.0,475999.0,589.0
294
+ 2020-12-03 00:00:00+03:00,28145.0,474088.0,554.0
295
+ 2020-12-04 00:00:00+03:00,27403.0,472021.0,569.0
296
+ 2020-12-05 00:00:00+03:00,28782.0,472651.0,508.0
297
+ 2020-12-06 00:00:00+03:00,29039.0,479891.0,457.0
298
+ 2020-12-07 00:00:00+03:00,28142.0,488727.0,456.0
299
+ 2020-12-08 00:00:00+03:00,26097.0,489324.0,562.0
300
+ 2020-12-09 00:00:00+03:00,26190.0,488689.0,559.0
301
+ 2020-12-10 00:00:00+03:00,27927.0,490177.0,562.0
302
+ 2020-12-11 00:00:00+03:00,28585.0,491978.0,613.0
303
+ 2020-12-12 00:00:00+03:00,28137.0,493437.0,560.0
304
+ 2020-12-13 00:00:00+03:00,28080.0,500752.0,488.0
305
+ 2020-12-14 00:00:00+03:00,27328.0,509068.0,450.0
306
+ 2020-12-15 00:00:00+03:00,26689.0,510367.0,577.0
307
+ 2020-12-16 00:00:00+03:00,26509.0,509790.0,596.0
308
+ 2020-12-17 00:00:00+03:00,28214.0,510977.0,587.0
309
+ 2020-12-18 00:00:00+03:00,28552.0,512825.0,611.0
310
+ 2020-12-19 00:00:00+03:00,28209.0,514340.0,585.0
311
+ 2020-12-20 00:00:00+03:00,28948.0,521862.0,511.0
312
+ 2020-12-21 00:00:00+03:00,29350.0,531014.0,493.0
313
+ 2020-12-22 00:00:00+03:00,28776.0,535071.0,561.0
314
+ 2020-12-23 00:00:00+03:00,27250.0,537325.0,549.0
315
+ 2020-12-24 00:00:00+03:00,29935.0,539735.0,635.0
316
+ 2020-12-25 00:00:00+03:00,29018.0,540793.0,563.0
317
+ 2020-12-26 00:00:00+03:00,29258.0,541299.0,567.0
318
+ 2020-12-27 00:00:00+03:00,28284.0,544641.0,552.0
319
+ 2020-12-28 00:00:00+03:00,27787.0,551461.0,487.0
320
+ 2020-12-29 00:00:00+03:00,27002.0,553027.0,562.0
321
+ 2020-12-30 00:00:00+03:00,26513.0,549706.0,599.0
322
+ 2020-12-31 00:00:00+03:00,27747.0,547938.0,593.0
323
+ 2021-01-01 00:00:00+03:00,27039.0,548643.0,536.0
324
+ 2021-01-02 00:00:00+03:00,26301.0,555600.0,447.0
325
+ 2021-01-03 00:00:00+03:00,24150.0,559399.0,504.0
326
+ 2021-01-04 00:00:00+03:00,23351.0,561114.0,482.0
327
+ 2021-01-05 00:00:00+03:00,24246.0,562210.0,518.0
328
+ 2021-01-06 00:00:00+03:00,24217.0,562927.0,445.0
329
+ 2021-01-07 00:00:00+03:00,23541.0,562233.0,506.0
330
+ 2021-01-08 00:00:00+03:00,23652.0,563754.0,454.0
331
+ 2021-01-09 00:00:00+03:00,23309.0,562913.0,470.0
332
+ 2021-01-10 00:00:00+03:00,22851.0,561228.0,456.0
333
+ 2021-01-11 00:00:00+03:00,23315.0,562321.0,436.0
334
+ 2021-01-12 00:00:00+03:00,22934.0,559969.0,531.0
335
+ 2021-01-13 00:00:00+03:00,22850.0,553595.0,566.0
336
+ 2021-01-14 00:00:00+03:00,24763.0,549832.0,570.0
337
+ 2021-01-15 00:00:00+03:00,24715.0,546356.0,555.0
338
+ 2021-01-16 00:00:00+03:00,24092.0,542547.0,590.0
339
+ 2021-01-17 00:00:00+03:00,23586.0,542212.0,481.0
340
+ 2021-01-18 00:00:00+03:00,22857.0,546265.0,471.0
341
+ 2021-01-19 00:00:00+03:00,21734.0,544151.0,586.0
342
+ 2021-01-20 00:00:00+03:00,21152.0,539416.0,597.0
343
+ 2021-01-21 00:00:00+03:00,21887.0,533789.0,612.0
344
+ 2021-01-22 00:00:00+03:00,21513.0,527404.0,580.0
345
+ 2021-01-23 00:00:00+03:00,20921.0,519987.0,559.0
346
+ 2021-01-24 00:00:00+03:00,21127.0,518178.0,491.0
347
+ 2021-01-25 00:00:00+03:00,19290.0,518009.0,456.0
348
+ 2021-01-26 00:00:00+03:00,18241.0,511888.0,564.0
349
+ 2021-01-27 00:00:00+03:00,17741.0,501113.0,594.0
350
+ 2021-01-28 00:00:00+03:00,19138.0,492901.0,575.0
351
+ 2021-01-29 00:00:00+03:00,19238.0,485401.0,534.0
352
+ 2021-01-30 00:00:00+03:00,19032.0,479419.0,512.0
353
+ 2021-01-31 00:00:00+03:00,18359.0,477253.0,485.0
354
+ 2021-02-01 00:00:00+03:00,17648.0,476295.0,437.0
355
+ 2021-02-02 00:00:00+03:00,16643.0,470027.0,539.0
356
+ 2021-02-03 00:00:00+03:00,16474.0,461153.0,526.0
357
+ 2021-02-04 00:00:00+03:00,16714.0,452800.0,521.0
358
+ 2021-02-05 00:00:00+03:00,16688.0,445379.0,527.0
359
+ 2021-02-06 00:00:00+03:00,16627.0,438678.0,497.0
360
+ 2021-02-07 00:00:00+03:00,16048.0,434410.0,432.0
361
+ 2021-02-08 00:00:00+03:00,15916.0,434038.0,407.0
362
+ 2021-02-09 00:00:00+03:00,15019.0,426732.0,530.0
363
+ 2021-02-10 00:00:00+03:00,14494.0,418115.0,536.0
364
+ 2021-02-11 00:00:00+03:00,15038.0,410639.0,553.0
365
+ 2021-02-12 00:00:00+03:00,15089.0,404501.0,507.0
366
+ 2021-02-13 00:00:00+03:00,14861.0,400095.0,502.0
367
+ 2021-02-14 00:00:00+03:00,14185.0,398656.0,430.0
368
+ 2021-02-15 00:00:00+03:00,14207.0,398534.0,394.0
369
+ 2021-02-16 00:00:00+03:00,13233.0,393681.0,459.0
370
+ 2021-02-17 00:00:00+03:00,12828.0,388123.0,467.0
371
+ 2021-02-18 00:00:00+03:00,13447.0,382360.0,480.0
372
+ 2021-02-19 00:00:00+03:00,13433.0,376686.0,470.0
373
+ 2021-02-20 00:00:00+03:00,12953.0,371675.0,480.0
374
+ 2021-02-21 00:00:00+03:00,12742.0,367988.0,417.0
375
+ 2021-02-22 00:00:00+03:00,12604.0,367312.0,337.0
376
+ 2021-02-23 00:00:00+03:00,11823.0,365762.0,417.0
377
+ 2021-02-24 00:00:00+03:00,11749.0,364910.0,383.0
378
+ 2021-02-25 00:00:00+03:00,11198.0,359560.0,446.0
379
+ 2021-02-26 00:00:00+03:00,11086.0,354496.0,428.0
380
+ 2021-02-27 00:00:00+03:00,11534.0,349571.0,439.0
381
+ 2021-02-28 00:00:00+03:00,11359.0,348160.0,379.0
382
+ 2021-03-01 00:00:00+03:00,11571.0,348121.0,333.0
383
+ 2021-03-02 00:00:00+03:00,10565.0,343279.0,441.0
384
+ 2021-03-03 00:00:00+03:00,10535.0,337668.0,452.0
385
+ 2021-03-04 00:00:00+03:00,11385.0,332455.0,475.0
386
+ 2021-03-05 00:00:00+03:00,11024.0,327553.0,462.0
387
+ 2021-03-06 00:00:00+03:00,11022.0,323107.0,441.0
388
+ 2021-03-07 00:00:00+03:00,10595.0,321758.0,368.0
389
+ 2021-03-08 00:00:00+03:00,10253.0,321310.0,379.0
390
+ 2021-03-09 00:00:00+03:00,9445.0,320488.0,336.0
391
+ 2021-03-10 00:00:00+03:00,9079.0,315751.0,466.0
392
+ 2021-03-11 00:00:00+03:00,9270.0,310556.0,459.0
393
+ 2021-03-12 00:00:00+03:00,9794.0,306368.0,486.0
394
+ 2021-03-13 00:00:00+03:00,9908.0,302933.0,475.0
395
+ 2021-03-14 00:00:00+03:00,10083.0,303209.0,395.0
396
+ 2021-03-15 00:00:00+03:00,9437.0,303975.0,404.0
397
+ 2021-03-16 00:00:00+03:00,9393.0,302281.0,443.0
398
+ 2021-03-17 00:00:00+03:00,8998.0,300097.0,427.0
399
+ 2021-03-18 00:00:00+03:00,9803.0,297379.0,460.0
400
+ 2021-03-19 00:00:00+03:00,9699.0,294298.0,443.0
401
+ 2021-03-20 00:00:00+03:00,9632.0,292259.0,392.0
402
+ 2021-03-21 00:00:00+03:00,9299.0,292444.0,371.0
403
+ 2021-03-22 00:00:00+03:00,9284.0,293577.0,361.0
404
+ 2021-03-23 00:00:00+03:00,8457.0,290747.0,427.0
405
+ 2021-03-24 00:00:00+03:00,8861.0,288852.0,401.0
406
+ 2021-03-25 00:00:00+03:00,9221.0,286799.0,393.0
407
+ 2021-03-26 00:00:00+03:00,9167.0,284681.0,405.0
408
+ 2021-03-27 00:00:00+03:00,8885.0,282842.0,387.0
409
+ 2021-03-28 00:00:00+03:00,9088.0,282964.0,336.0
410
+ 2021-03-29 00:00:00+03:00,8711.0,284102.0,293.0
411
+ 2021-03-30 00:00:00+03:00,8277.0,282382.0,409.0
412
+ 2021-03-31 00:00:00+03:00,8275.0,280073.0,408.0
413
+ 2021-04-01 00:00:00+03:00,9169.0,278612.0,383.0
414
+ 2021-04-02 00:00:00+03:00,8792.0,277172.0,400.0
415
+ 2021-04-03 00:00:00+03:00,9021.0,276191.0,384.0
416
+ 2021-04-04 00:00:00+03:00,8817.0,276439.0,357.0
417
+ 2021-04-05 00:00:00+03:00,8646.0,277690.0,343.0
418
+ 2021-04-06 00:00:00+03:00,8328.0,276727.0,389.0
419
+ 2021-04-07 00:00:00+03:00,8294.0,275202.0,374.0
420
+ 2021-04-08 00:00:00+03:00,8672.0,273951.0,365.0
421
+ 2021-04-09 00:00:00+03:00,9150.0,273037.0,402.0
422
+ 2021-04-10 00:00:00+03:00,8704.0,271760.0,402.0
423
+ 2021-04-11 00:00:00+03:00,8702.0,272895.0,337.0
424
+ 2021-04-12 00:00:00+03:00,8320.0,274282.0,277.0
425
+ 2021-04-13 00:00:00+03:00,8173.0,272506.0,338.0
426
+ 2021-04-14 00:00:00+03:00,8326.0,270986.0,399.0
427
+ 2021-04-15 00:00:00+03:00,8944.0,269307.0,398.0
428
+ 2021-04-16 00:00:00+03:00,8995.0,268796.0,397.0
429
+ 2021-04-17 00:00:00+03:00,9321.0,268887.0,398.0
430
+ 2021-04-18 00:00:00+03:00,8632.0,269739.0,389.0
431
+ 2021-04-19 00:00:00+03:00,8589.0,271164.0,346.0
432
+ 2021-04-20 00:00:00+03:00,8164.0,269318.0,379.0
433
+ 2021-04-21 00:00:00+03:00,8271.0,267546.0,399.0
434
+ 2021-04-22 00:00:00+03:00,8996.0,267211.0,397.0
435
+ 2021-04-23 00:00:00+03:00,8840.0,266246.0,398.0
436
+ 2021-04-24 00:00:00+03:00,8828.0,265421.0,399.0
437
+ 2021-04-25 00:00:00+03:00,8780.0,266329.0,332.0
438
+ 2021-04-26 00:00:00+03:00,8803.0,268145.0,356.0
439
+ 2021-04-27 00:00:00+03:00,8053.0,267767.0,392.0
440
+ 2021-04-28 00:00:00+03:00,7848.0,266808.0,387.0
441
+ 2021-04-29 00:00:00+03:00,9284.0,267286.0,364.0
442
+ 2021-04-30 00:00:00+03:00,8731.0,267214.0,397.0
443
+ 2021-05-01 00:00:00+03:00,9270.0,267455.0,392.0
444
+ 2021-05-02 00:00:00+03:00,8697.0,268471.0,342.0
445
+ 2021-05-03 00:00:00+03:00,8489.0,270257.0,336.0
446
+ 2021-05-04 00:00:00+03:00,7770.0,270935.0,337.0
447
+ 2021-05-05 00:00:00+03:00,7975.0,271044.0,360.0
448
+ 2021-05-06 00:00:00+03:00,7639.0,270544.0,351.0
449
+ 2021-05-07 00:00:00+03:00,8386.0,270532.0,376.0
450
+ 2021-05-08 00:00:00+03:00,8329.0,270236.0,370.0
451
+ 2021-05-09 00:00:00+03:00,8419.0,270804.0,334.0
452
+ 2021-05-10 00:00:00+03:00,8465.0,272174.0,321.0
453
+ 2021-05-11 00:00:00+03:00,8115.0,272951.0,329.0
454
+ 2021-05-12 00:00:00+03:00,8217.0,272199.0,355.0
455
+ 2021-05-13 00:00:00+03:00,8380.0,270838.0,392.0
456
+ 2021-05-14 00:00:00+03:00,9462.0,270151.0,393.0
457
+ 2021-05-15 00:00:00+03:00,8790.0,268711.0,364.0
458
+ 2021-05-16 00:00:00+03:00,8554.0,268301.0,391.0
459
+ 2021-05-17 00:00:00+03:00,9328.0,270108.0,340.0
460
+ 2021-05-18 00:00:00+03:00,8183.0,268955.0,364.0
461
+ 2021-05-19 00:00:00+03:00,7920.0,266924.0,390.0
462
+ 2021-05-20 00:00:00+03:00,9232.0,265777.0,396.0
463
+ 2021-05-21 00:00:00+03:00,8937.0,264986.0,378.0
464
+ 2021-05-22 00:00:00+03:00,8709.0,263964.0,386.0
465
+ 2021-05-23 00:00:00+03:00,8951.0,265261.0,357.0
466
+ 2021-05-24 00:00:00+03:00,8406.0,266898.0,319.0
467
+ 2021-05-25 00:00:00+03:00,7884.0,265646.0,393.0
468
+ 2021-05-26 00:00:00+03:00,8373.0,264478.0,406.0
469
+ 2021-05-27 00:00:00+03:00,9039.0,263356.0,402.0
470
+ 2021-05-28 00:00:00+03:00,9252.0,262819.0,404.0
471
+ 2021-05-29 00:00:00+03:00,9289.0,262457.0,401.0
472
+ 2021-05-30 00:00:00+03:00,9694.0,264410.0,355.0
473
+ 2021-05-31 00:00:00+03:00,8475.0,265831.0,339.0
474
+ 2021-06-01 00:00:00+03:00,9500.0,265965.0,372.0
475
+ 2021-06-02 00:00:00+03:00,8832.0,265383.0,394.0
476
+ 2021-06-03 00:00:00+03:00,8933.0,264540.0,393.0
477
+ 2021-06-04 00:00:00+03:00,8947.0,264580.0,377.0
478
+ 2021-06-05 00:00:00+03:00,9145.0,264761.0,399.0
479
+ 2021-06-06 00:00:00+03:00,9163.0,266204.0,351.0
480
+ 2021-06-07 00:00:00+03:00,9429.0,268547.0,330.0
481
+ 2021-06-08 00:00:00+03:00,9977.0,269262.0,379.0
482
+ 2021-06-09 00:00:00+03:00,10407.0,269456.0,399.0
483
+ 2021-06-10 00:00:00+03:00,11699.0,270676.0,383.0
484
+ 2021-06-11 00:00:00+03:00,12505.0,272597.0,396.0
485
+ 2021-06-12 00:00:00+03:00,13510.0,275722.0,399.0
486
+ 2021-06-13 00:00:00+03:00,14723.0,280922.0,357.0
487
+ 2021-06-14 00:00:00+03:00,13721.0,285960.0,371.0
488
+ 2021-06-15 00:00:00+03:00,14185.0,291169.0,379.0
489
+ 2021-06-16 00:00:00+03:00,13397.0,293914.0,396.0
490
+ 2021-06-17 00:00:00+03:00,14057.0,296350.0,416.0
491
+ 2021-06-18 00:00:00+03:00,17262.0,302205.0,453.0
492
+ 2021-06-19 00:00:00+03:00,17906.0,308961.0,466.0
493
+ 2021-06-20 00:00:00+03:00,17611.0,317493.0,450.0
494
+ 2021-06-21 00:00:00+03:00,17378.0,326070.0,440.0
495
+ 2021-06-22 00:00:00+03:00,16715.0,331122.0,546.0
496
+ 2021-06-23 00:00:00+03:00,17594.0,335508.0,548.0
497
+ 2021-06-24 00:00:00+03:00,20182.0,341617.0,568.0
498
+ 2021-06-25 00:00:00+03:00,20393.0,347385.0,601.0
499
+ 2021-06-26 00:00:00+03:00,21665.0,354084.0,619.0
500
+ 2021-06-27 00:00:00+03:00,20538.0,361295.0,599.0
501
+ 2021-06-28 00:00:00+03:00,21650.0,369708.0,611.0
502
+ 2021-06-29 00:00:00+03:00,20616.0,374975.0,652.0
503
+ 2021-06-30 00:00:00+03:00,21042.0,378992.0,669.0
504
+ 2021-07-01 00:00:00+03:00,23543.0,384935.0,672.0
505
+ 2021-07-02 00:00:00+03:00,23218.0,389277.0,679.0
506
+ 2021-07-03 00:00:00+03:00,24439.0,395120.0,697.0
507
+ 2021-07-04 00:00:00+03:00,25142.0,404115.0,663.0
508
+ 2021-07-05 00:00:00+03:00,24353.0,413274.0,654.0
509
+ 2021-07-06 00:00:00+03:00,23378.0,417504.0,737.0
510
+ 2021-07-07 00:00:00+03:00,23962.0,420674.0,725.0
511
+ 2021-07-08 00:00:00+03:00,24818.0,423422.0,734.0
512
+ 2021-07-09 00:00:00+03:00,25766.0,426630.0,726.0
513
+ 2021-07-10 00:00:00+03:00,25082.0,433210.0,752.0
514
+ 2021-07-11 00:00:00+03:00,25033.0,440112.0,749.0
515
+ 2021-07-12 00:00:00+03:00,25140.0,448113.0,710.0
516
+ 2021-07-13 00:00:00+03:00,24702.0,452469.0,780.0
517
+ 2021-07-14 00:00:00+03:00,23827.0,454241.0,786.0
518
+ 2021-07-15 00:00:00+03:00,25293.0,457250.0,791.0
519
+ 2021-07-16 00:00:00+03:00,25704.0,460223.0,799.0
520
+ 2021-07-17 00:00:00+03:00,25116.0,463115.0,787.0
521
+ 2021-07-18 00:00:00+03:00,25018.0,468483.0,764.0
522
+ 2021-07-19 00:00:00+03:00,24633.0,473633.0,719.0
523
+ 2021-07-20 00:00:00+03:00,23770.0,474401.0,784.0
524
+ 2021-07-21 00:00:00+03:00,23704.0,474738.0,783.0
525
+ 2021-07-22 00:00:00+03:00,24471.0,475753.0,796.0
526
+ 2021-07-23 00:00:00+03:00,23811.0,476222.0,795.0
527
+ 2021-07-24 00:00:00+03:00,23947.0,477418.0,799.0
528
+ 2021-07-25 00:00:00+03:00,24072.0,482033.0,779.0
529
+ 2021-07-26 00:00:00+03:00,23239.0,488345.0,727.0
530
+ 2021-07-27 00:00:00+03:00,23032.0,490482.0,779.0
531
+ 2021-07-28 00:00:00+03:00,22420.0,491525.0,798.0
532
+ 2021-07-29 00:00:00+03:00,23270.0,493162.0,799.0
533
+ 2021-07-30 00:00:00+03:00,23564.0,495447.0,794.0
534
+ 2021-07-31 00:00:00+03:00,23807.0,498691.0,792.0
535
+ 2021-08-01 00:00:00+03:00,22804.0,503435.0,789.0
536
+ 2021-08-02 00:00:00+03:00,23508.0,511265.0,785.0
537
+ 2021-08-03 00:00:00+03:00,22010.0,513524.0,788.0
538
+ 2021-08-04 00:00:00+03:00,22589.0,515227.0,790.0
539
+ 2021-08-05 00:00:00+03:00,23120.0,517183.0,794.0
540
+ 2021-08-06 00:00:00+03:00,22660.0,518910.0,792.0
541
+ 2021-08-07 00:00:00+03:00,22320.0,520952.0,793.0
542
+ 2021-08-08 00:00:00+03:00,22866.0,527362.0,787.0
543
+ 2021-08-09 00:00:00+03:00,22160.0,534279.0,769.0
544
+ 2021-08-10 00:00:00+03:00,21378.0,536136.0,792.0
545
+ 2021-08-11 00:00:00+03:00,21571.0,536841.0,799.0
546
+ 2021-08-12 00:00:00+03:00,21932.0,537770.0,808.0
547
+ 2021-08-13 00:00:00+03:00,22277.0,539864.0,815.0
548
+ 2021-08-14 00:00:00+03:00,22144.0,541639.0,819.0
549
+ 2021-08-15 00:00:00+03:00,21624.0,546021.0,816.0
550
+ 2021-08-16 00:00:00+03:00,20765.0,550379.0,806.0
551
+ 2021-08-17 00:00:00+03:00,20958.0,552125.0,805.0
552
+ 2021-08-18 00:00:00+03:00,20914.0,551527.0,799.0
553
+ 2021-08-19 00:00:00+03:00,21058.0,547777.0,791.0
554
+ 2021-08-20 00:00:00+03:00,20992.0,547633.0,785.0
555
+ 2021-08-21 00:00:00+03:00,21000.0,547189.0,797.0
556
+ 2021-08-22 00:00:00+03:00,20564.0,551577.0,762.0
557
+ 2021-08-23 00:00:00+03:00,19454.0,554854.0,776.0
558
+ 2021-08-24 00:00:00+03:00,18833.0,554257.0,794.0
559
+ 2021-08-25 00:00:00+03:00,19536.0,553330.0,809.0
560
+ 2021-08-26 00:00:00+03:00,19630.0,552479.0,820.0
561
+ 2021-08-27 00:00:00+03:00,19509.0,551973.0,798.0
562
+ 2021-08-28 00:00:00+03:00,19492.0,551255.0,799.0
563
+ 2021-08-29 00:00:00+03:00,19286.0,552940.0,797.0
564
+ 2021-08-30 00:00:00+03:00,18325.0,556293.0,792.0
565
+ 2021-08-31 00:00:00+03:00,17813.0,554687.0,795.0
566
+ 2021-09-01 00:00:00+03:00,18368.0,553940.0,790.0
567
+ 2021-09-02 00:00:00+03:00,18985.0,553458.0,798.0
568
+ 2021-09-03 00:00:00+03:00,18856.0,552825.0,799.0
569
+ 2021-09-04 00:00:00+03:00,18780.0,552072.0,796.0
570
+ 2021-09-05 00:00:00+03:00,18645.0,554668.0,793.0
571
+ 2021-09-06 00:00:00+03:00,17856.0,557458.0,790.0
572
+ 2021-09-07 00:00:00+03:00,17425.0,556845.0,795.0
573
+ 2021-09-08 00:00:00+03:00,18024.0,555810.0,797.0
574
+ 2021-09-09 00:00:00+03:00,18380.0,553757.0,794.0
575
+ 2021-09-10 00:00:00+03:00,18341.0,554188.0,789.0
576
+ 2021-09-11 00:00:00+03:00,18891.0,554395.0,796.0
577
+ 2021-09-12 00:00:00+03:00,18554.0,557664.0,788.0
578
+ 2021-09-13 00:00:00+03:00,18178.0,562654.0,719.0
579
+ 2021-09-14 00:00:00+03:00,17837.0,563803.0,781.0
580
+ 2021-09-15 00:00:00+03:00,18841.0,564813.0,792.0
581
+ 2021-09-16 00:00:00+03:00,19594.0,566287.0,794.0
582
+ 2021-09-17 00:00:00+03:00,19905.0,568782.0,791.0
583
+ 2021-09-18 00:00:00+03:00,20329.0,572065.0,799.0
584
+ 2021-09-19 00:00:00+03:00,20174.0,578028.0,793.0
585
+ 2021-09-20 00:00:00+03:00,19744.0,585002.0,778.0
586
+ 2021-09-21 00:00:00+03:00,19179.0,587932.0,812.0
587
+ 2021-09-22 00:00:00+03:00,19706.0,590719.0,817.0
588
+ 2021-09-23 00:00:00+03:00,21438.0,594770.0,820.0
589
+ 2021-09-24 00:00:00+03:00,21379.0,599493.0,828.0
590
+ 2021-09-25 00:00:00+03:00,22041.0,604387.0,822.0
591
+ 2021-09-26 00:00:00+03:00,22498.0,612409.0,805.0
592
+ 2021-09-27 00:00:00+03:00,22236.0,620353.0,779.0
593
+ 2021-09-28 00:00:00+03:00,21559.0,623692.0,852.0
594
+ 2021-09-29 00:00:00+03:00,22430.0,626809.0,857.0
595
+ 2021-09-30 00:00:00+03:00,23888.0,631004.0,867.0
596
+ 2021-10-01 00:00:00+03:00,24522.0,634684.0,887.0
597
+ 2021-10-02 00:00:00+03:00,25219.0,641165.0,886.0
598
+ 2021-10-03 00:00:00+03:00,25769.0,650653.0,890.0
599
+ 2021-10-04 00:00:00+03:00,25781.0,661025.0,883.0
600
+ 2021-10-05 00:00:00+03:00,25110.0,666672.0,895.0
601
+ 2021-10-06 00:00:00+03:00,25133.0,671035.0,929.0
602
+ 2021-10-07 00:00:00+03:00,27550.0,677331.0,924.0
603
+ 2021-10-08 00:00:00+03:00,27246.0,683075.0,936.0
604
+ 2021-10-09 00:00:00+03:00,29362.0,690420.0,968.0
605
+ 2021-10-10 00:00:00+03:00,28647.0,700831.0,962.0
606
+ 2021-10-11 00:00:00+03:00,29409.0,713823.0,957.0
607
+ 2021-10-12 00:00:00+03:00,28190.0,720334.0,973.0
608
+ 2021-10-13 00:00:00+03:00,28717.0,726266.0,984.0
609
+ 2021-10-14 00:00:00+03:00,31299.0,734909.0,986.0
610
+ 2021-10-15 00:00:00+03:00,32196.0,743839.0,998.0
611
+ 2021-10-16 00:00:00+03:00,33208.0,754162.0,1002.0
612
+ 2021-10-17 00:00:00+03:00,34303.0,768751.0,997.0
613
+ 2021-10-18 00:00:00+03:00,34325.0,785647.0,998.0
614
+ 2021-10-19 00:00:00+03:00,33740.0,794946.0,1015.0
615
+ 2021-10-20 00:00:00+03:00,34073.0,802760.0,1028.0
616
+ 2021-10-21 00:00:00+03:00,36339.0,812168.0,1036.0
617
+ 2021-10-22 00:00:00+03:00,37141.0,822792.0,1064.0
618
+ 2021-10-23 00:00:00+03:00,37678.0,833318.0,1075.0
619
+ 2021-10-24 00:00:00+03:00,35660.0,845122.0,1072.0
620
+ 2021-10-25 00:00:00+03:00,37930.0,861293.0,1069.0
621
+ 2021-10-26 00:00:00+03:00,36446.0,869660.0,1106.0
622
+ 2021-10-27 00:00:00+03:00,36582.0,875968.0,1123.0
623
+ 2021-10-28 00:00:00+03:00,40096.0,885587.0,1159.0
624
+ 2021-10-29 00:00:00+03:00,39849.0,893811.0,1163.0
625
+ 2021-10-30 00:00:00+03:00,40251.0,903993.0,1160.0
626
+ 2021-10-31 00:00:00+03:00,40993.0,916713.0,1158.0
627
+ 2021-11-01 00:00:00+03:00,40402.0,932773.0,1155.0
628
+ 2021-11-02 00:00:00+03:00,39008.0,939698.0,1178.0
629
+ 2021-11-03 00:00:00+03:00,40443.0,946145.0,1189.0
630
+ 2021-11-04 00:00:00+03:00,40217.0,953239.0,1195.0
631
+ 2021-11-05 00:00:00+03:00,40735.0,964177.0,1192.0
632
+ 2021-11-06 00:00:00+03:00,41335.0,975123.0,1188.0
633
+ 2021-11-07 00:00:00+03:00,39165.0,986303.0,1179.0
634
+ 2021-11-08 00:00:00+03:00,39400.0,998931.0,1190.0
635
+ 2021-11-09 00:00:00+03:00,39160.0,1004844.0,1211.0
636
+ 2021-11-10 00:00:00+03:00,38058.0,1007098.0,1239.0
637
+ 2021-11-11 00:00:00+03:00,40759.0,1013464.0,1237.0
638
+ 2021-11-12 00:00:00+03:00,40123.0,1018707.0,1235.0
639
+ 2021-11-13 00:00:00+03:00,39256.0,1022920.0,1241.0
640
+ 2021-11-14 00:00:00+03:00,38823.0,1030703.0,1219.0
641
+ 2021-11-15 00:00:00+03:00,38420.0,1040210.0,1211.0
642
+ 2021-11-16 00:00:00+03:00,36818.0,1041627.0,1240.0
643
+ 2021-11-17 00:00:00+03:00,36626.0,1040618.0,1247.0
644
+ 2021-11-18 00:00:00+03:00,37374.0,1040327.0,1251.0
645
+ 2021-11-19 00:00:00+03:00,37156.0,1039225.0,1254.0
646
+ 2021-11-20 00:00:00+03:00,37120.0,1038919.0,1254.0
647
+ 2021-11-21 00:00:00+03:00,36970.0,1042133.0,1252.0
648
+ 2021-11-22 00:00:00+03:00,35681.0,1047860.0,1241.0
649
+ 2021-11-23 00:00:00+03:00,33996.0,1044562.0,1243.0
650
+ 2021-11-24 00:00:00+03:00,33558.0,1040198.0,1240.0
651
+ 2021-11-25 00:00:00+03:00,33796.0,1034306.0,1238.0
652
+ 2021-11-26 00:00:00+03:00,34690.0,1031616.0,1235.0
653
+ 2021-11-27 00:00:00+03:00,33946.0,1027829.0,1239.0
654
+ 2021-11-28 00:00:00+03:00,33548.0,1029507.0,1224.0
655
+ 2021-11-29 00:00:00+03:00,33860.0,1034458.0,1209.0
656
+ 2021-11-30 00:00:00+03:00,32648.0,1032435.0,1229.0
657
+ 2021-12-01 00:00:00+03:00,32837.0,1028367.0,1226.0
658
+ 2021-12-02 00:00:00+03:00,33389.0,1025350.0,1221.0
659
+ 2021-12-03 00:00:00+03:00,32930.0,1020549.0,1217.0
660
+ 2021-12-04 00:00:00+03:00,32974.0,1017126.0,1215.0
661
+ 2021-12-05 00:00:00+03:00,32602.0,1017929.0,1206.0
662
+ 2021-12-06 00:00:00+03:00,32136.0,1020811.0,1184.0
663
+ 2021-12-07 00:00:00+03:00,31096.0,1016110.0,1182.0
664
+ 2021-12-08 00:00:00+03:00,30752.0,1008707.0,1179.0
665
+ 2021-12-09 00:00:00+03:00,30209.0,1001941.0,1181.0
666
+ 2021-12-10 00:00:00+03:00,30873.0,995981.0,1176.0
667
+ 2021-12-11 00:00:00+03:00,30288.0,988652.0,1171.0
668
+ 2021-12-12 00:00:00+03:00,29929.0,986058.0,1132.0
669
+ 2021-12-13 00:00:00+03:00,29558.0,985934.0,1121.0
670
+ 2021-12-14 00:00:00+03:00,28343.0,979048.0,1145.0
671
+ 2021-12-15 00:00:00+03:00,28363.0,970636.0,1142.0
672
+ 2021-12-16 00:00:00+03:00,28486.0,960834.0,1133.0
673
+ 2021-12-17 00:00:00+03:00,27743.0,950060.0,1080.0
674
+ 2021-12-18 00:00:00+03:00,27434.0,938377.0,1076.0
675
+ 2021-12-19 00:00:00+03:00,27967.0,932666.0,1023.0
676
+ 2021-12-20 00:00:00+03:00,27022.0,928610.0,1019.0
677
+ 2021-12-21 00:00:00+03:00,25907.0,913271.0,1027.0
678
+ 2021-12-22 00:00:00+03:00,25264.0,895193.0,1020.0
679
+ 2021-12-23 00:00:00+03:00,25667.0,878213.0,1002.0
680
+ 2021-12-24 00:00:00+03:00,24703.0,860705.0,998.0
681
+ 2021-12-25 00:00:00+03:00,24946.0,842563.0,981.0
682
+ 2021-12-26 00:00:00+03:00,23721.0,828031.0,968.0
683
+ 2021-12-27 00:00:00+03:00,23210.0,816589.0,937.0
684
+ 2021-12-28 00:00:00+03:00,21922.0,793615.0,935.0
685
+ 2021-12-29 00:00:00+03:00,21119.0,771026.0,932.0
686
+ 2021-12-30 00:00:00+03:00,21073.0,748169.0,926.0
687
+ 2021-12-31 00:00:00+03:00,20638.0,727203.0,912.0
688
+ 2022-01-01 00:00:00+03:00,19751.0,712963.0,847.0
689
+ 2022-01-02 00:00:00+03:00,18233.0,703409.0,811.0
690
+ 2022-01-03 00:00:00+03:00,16343.0,694880.0,835.0
691
+ 2022-01-04 00:00:00+03:00,15903.0,682878.0,834.0
692
+ 2022-01-05 00:00:00+03:00,15772.0,672241.0,828.0
693
+ 2022-01-06 00:00:00+03:00,15316.0,663806.0,802.0
694
+ 2022-01-07 00:00:00+03:00,16735.0,657719.0,787.0
695
+ 2022-01-08 00:00:00+03:00,16568.0,653042.0,796.0
696
+ 2022-01-09 00:00:00+03:00,16246.0,647774.0,763.0
697
+ 2022-01-10 00:00:00+03:00,15830.0,642973.0,741.0
698
+ 2022-01-11 00:00:00+03:00,17525.0,634499.0,783.0
699
+ 2022-01-12 00:00:00+03:00,17946.0,625354.0,745.0
700
+ 2022-01-13 00:00:00+03:00,21155.0,619785.0,740.0
701
+ 2022-01-14 00:00:00+03:00,23820.0,617914.0,739.0
702
+ 2022-01-15 00:00:00+03:00,27179.0,617786.0,723.0
703
+ 2022-01-16 00:00:00+03:00,29230.0,623599.0,686.0
704
+ 2022-01-17 00:00:00+03:00,30726.0,633899.0,670.0
705
+ 2022-01-18 00:00:00+03:00,31252.0,639899.0,688.0
706
+ 2022-01-19 00:00:00+03:00,33899.0,650180.0,698.0
707
+ 2022-01-20 00:00:00+03:00,38850.0,663868.0,684.0
708
+ 2022-01-21 00:00:00+03:00,49513.0,687970.0,692.0
709
+ 2022-01-22 00:00:00+03:00,49485.82,718976.0,681.0
710
+ 2022-01-23 00:00:00+03:00,49458.64,758457.0,679.0
711
+ 2022-01-24 00:00:00+03:00,49431.46,801197.0,655.0
712
+ 2022-01-25 00:00:00+03:00,49404.28,841921.0,681.0
713
+ 2022-01-26 00:00:00+03:00,49377.1,887759.0,657.0
714
+ 2022-01-27 00:00:00+03:00,49349.92,946156.0,665.0
715
+ 2022-01-28 00:00:00+03:00,49322.74,1014017.0,673.0
716
+ 2022-01-29 00:00:00+03:00,49295.56,1014783.3,668.0
717
+ 2022-01-30 00:00:00+03:00,49268.38,1015549.6,617.0
718
+ 2022-01-31 00:00:00+03:00,49241.2,1016315.9,621.0
719
+ 2022-02-01 00:00:00+03:00,49214.02,1017082.2,663.0
720
+ 2022-02-02 00:00:00+03:00,49186.84,1017848.5,678.0
721
+ 2022-02-03 00:00:00+03:00,49159.66,1018614.8,667.0
722
+ 2022-02-04 00:00:00+03:00,49132.48,1019381.1,682.0
723
+ 2022-02-05 00:00:00+03:00,49105.3,1020147.4,714.0
724
+ 2022-02-06 00:00:00+03:00,49078.12,1020913.7,661.0
725
+ 2022-02-07 00:00:00+03:00,49050.94,1021680.0,609.0
726
+ 2022-02-08 00:00:00+03:00,49023.76,1022446.3,698.0
727
+ 2022-02-09 00:00:00+03:00,48996.58,1023212.6,669.0
728
+ 2022-02-10 00:00:00+03:00,48969.4,1023978.9,701.0
729
+ 2022-02-11 00:00:00+03:00,48942.22,1024745.2,722.0
730
+ 2022-02-12 00:00:00+03:00,48915.04,1025511.5,729.0
731
+ 2022-02-13 00:00:00+03:00,48887.86,1026277.8,706.0
732
+ 2022-02-14 00:00:00+03:00,48860.68,1027044.1,683.0
733
+ 2022-02-15 00:00:00+03:00,48833.5,1027810.4,704.0
734
+ 2022-02-16 00:00:00+03:00,48806.32,1028576.7,748.0
735
+ 2022-02-17 00:00:00+03:00,48779.14,1029343.0,790.0
736
+ 2022-02-18 00:00:00+03:00,48751.96,1030109.3,784.0
737
+ 2022-02-19 00:00:00+03:00,48724.78,1030875.6,798.0
738
+ 2022-02-20 00:00:00+03:00,48697.6,1031641.9,745.0
739
+ 2022-02-21 00:00:00+03:00,48670.42,1032408.2,735.0
740
+ 2022-02-22 00:00:00+03:00,48643.24,1033174.5,796.0
741
+ 2022-02-23 00:00:00+03:00,48616.06,1033940.8,785.0
742
+ 2022-02-24 00:00:00+03:00,48588.88,1034707.1,762.0
743
+ 2022-02-25 00:00:00+03:00,48561.7,1035473.4,787.0
744
+ 2022-02-26 00:00:00+03:00,48534.52,1036239.7,793.0
745
+ 2022-02-27 00:00:00+03:00,48507.34,1037006.0,769.0
746
+ 2022-02-28 00:00:00+03:00,48480.16,1037772.3,733.0
747
+ 2022-03-01 00:00:00+03:00,48452.98,1038538.6,786.0
748
+ 2022-03-02 00:00:00+03:00,48425.8,1039304.9,784.0
749
+ 2022-03-03 00:00:00+03:00,48398.62,1040071.2,781.0
750
+ 2022-03-04 00:00:00+03:00,48371.44,1040837.5,776.0
751
+ 2022-03-05 00:00:00+03:00,48344.26,1041603.8,750.0
752
+ 2022-03-06 00:00:00+03:00,48317.08,1042370.1,744.0
753
+ 2022-03-07 00:00:00+03:00,48289.9,1043136.4,668.0
754
+ 2022-03-08 00:00:00+03:00,48262.72,1043902.7,652.0
755
+ 2022-03-09 00:00:00+03:00,48235.54,1044669.0,645.0
756
+ 2022-03-10 00:00:00+03:00,48208.36,1045435.3,665.0
757
+ 2022-03-11 00:00:00+03:00,48181.18,1046201.6,674.0
758
+ 2022-03-12 00:00:00+03:00,48154.0,1046967.9,630.0
759
+ 2022-03-13 00:00:00+03:00,44989.0,1047734.2,596.0
760
+ 2022-03-14 00:00:00+03:00,41055.0,1048500.5,533.0
761
+ 2022-03-15 00:00:00+03:00,36678.0,1049266.8,558.0
762
+ 2022-03-16 00:00:00+03:00,36519.0,1050033.1,576.0
763
+ 2022-03-17 00:00:00+03:00,34819.0,1050799.4,561.0
764
+ 2022-03-18 00:00:00+03:00,34442.0,1051565.7,524.0
765
+ 2022-03-19 00:00:00+03:00,32958.0,1052332.0,495.0
766
+ 2022-03-20 00:00:00+03:00,31035.0,1008258.0,434.0
767
+ 2022-03-21 00:00:00+03:00,28709.0,974620.0,409.0
768
+ 2022-03-22 00:00:00+03:00,26394.0,925622.0,472.0
769
+ 2022-03-23 00:00:00+03:00,26826.0,881397.0,429.0
770
+ 2022-03-24 00:00:00+03:00,25387.0,839890.0,418.0
771
+ 2022-03-25 00:00:00+03:00,25382.0,803014.0,398.0
772
+ 2022-03-26 00:00:00+03:00,24072.0,765758.0,395.0
773
+ 2022-03-27 00:00:00+03:00,23280.0,741160.0,338.0
774
+ 2022-03-28 00:00:00+03:00,21101.0,726180.0,335.0
775
+ 2022-03-29 00:00:00+03:00,19660.0,698272.0,339.0
776
+ 2022-03-30 00:00:00+03:00,20145.0,666980.0,352.0
777
+ 2022-03-31 00:00:00+03:00,19277.0,635416.0,345.0
778
+ 2022-04-01 00:00:00+03:00,19164.0,608240.0,342.0
779
+ 2022-04-02 00:00:00+03:00,17949.0,581302.0,340.0
780
+ 2022-04-03 00:00:00+03:00,16828.0,562131.0,304.0
781
+ 2022-04-04 00:00:00+03:00,15291.0,544285.0,287.0
782
+ 2022-04-05 00:00:00+03:00,13947.0,520457.0,316.0
783
+ 2022-04-06 00:00:00+03:00,14661.0,499521.0,291.0
784
+ 2022-04-07 00:00:00+03:00,14355.0,478285.0,287.0
785
+ 2022-04-08 00:00:00+03:00,14311.0,454632.0,280.0
786
+ 2022-04-09 00:00:00+03:00,13573.0,427817.0,288.0
787
+ 2022-04-10 00:00:00+03:00,13056.0,411242.0,259.0
788
+ 2022-04-11 00:00:00+03:00,11855.0,396094.0,248.0
789
+ 2022-04-12 00:00:00+03:00,10910.0,375452.0,281.0
790
+ 2022-04-13 00:00:00+03:00,11754.0,358804.0,267.0
791
+ 2022-04-14 00:00:00+03:00,11348.0,348045.0,254.0
792
+ 2022-04-15 00:00:00+03:00,11432.0,339693.0,261.0
793
+ 2022-04-16 00:00:00+03:00,11095.0,331542.0,240.0
794
+ 2022-04-17 00:00:00+03:00,10263.0,325076.0,233.0
795
+ 2022-04-18 00:00:00+03:00,9434.0,319973.0,213.0
796
+ 2022-04-19 00:00:00+03:00,8640.0,311615.0,235.0
797
+ 2022-04-20 00:00:00+03:00,9195.0,304387.0,223.0
798
+ 2022-04-21 00:00:00+03:00,8875.0,298883.0,197.0
799
+ 2022-04-22 00:00:00+03:00,9001.0,294209.0,195.0
800
+ 2022-04-23 00:00:00+03:00,8829.0,289837.0,171.0
801
+ 2022-04-24 00:00:00+03:00,8446.0,287607.0,168.0
802
+ 2022-04-25 00:00:00+03:00,7651.0,286244.0,159.0
803
+ 2022-04-26 00:00:00+03:00,7107.0,281276.0,176.0
804
+ 2022-04-27 00:00:00+03:00,7705.0,277341.0,163.0
805
+ 2022-04-28 00:00:00+03:00,7681.0,273793.0,166.0
806
+ 2022-04-29 00:00:00+03:00,7710.0,270301.0,161.0
807
+ 2022-04-30 00:00:00+03:00,7363.0,266485.0,157.0
808
+ 2022-05-01 00:00:00+03:00,7047.0,264652.0,147.0
809
+ 2022-05-02 00:00:00+03:00,6207.0,263221.0,136.0
810
+ 2022-05-03 00:00:00+03:00,5466.0,261510.0,125.0
811
+ 2022-05-04 00:00:00+03:00,5093.0,259810.0,129.0
812
+ 2022-05-05 00:00:00+03:00,5011.0,255959.0,139.0
813
+ 2022-05-06 00:00:00+03:00,5541.0,251956.0,136.0
814
+ 2022-05-07 00:00:00+03:00,5500.0,248675.0,132.0
815
+ 2022-05-08 00:00:00+03:00,5447.0,247322.0,118.0
816
+ 2022-05-09 00:00:00+03:00,5030.0,246290.0,103.0
817
+ 2022-05-10 00:00:00+03:00,4531.0,245706.0,101.0
818
+ 2022-05-11 00:00:00+03:00,4102.0,244667.0,98.0
819
+ 2022-05-12 00:00:00+03:00,4065.0,241691.0,111.0
820
+ 2022-05-13 00:00:00+03:00,4896.0,239225.0,105.0
821
+ 2022-05-14 00:00:00+03:00,5047.0,236787.0,107.0
lab3_report.html ADDED
The diff for this file is too large to render. See raw diff
 
src/lab3_pipeline.py CHANGED
@@ -1,32 +1,27 @@
1
- # TimeSeriesHomework/src/lab3_pipeline.py
2
  """
3
- lab3_pipeline.py
4
- Простой воспроизводимый pipeline для ЛР №3:
5
- - загрузка CSV/Parquet
6
- - предобработка / ресемплинг
7
- - Box-Cox / log (если возможно)
8
- - тесты стационарности (ADF, KPSS)
9
- - создание лагов / роллов
10
- - простые модели (Naive, SeasonalNaive, SARIMAX, auto_arima если доступен)
11
- - VAR если мультивариатные данные
12
- - генерация простого HTML-отчёта
13
  """
14
 
15
- import argparse
16
  import os
17
  import math
18
  import time
19
- from typing import Tuple, Dict, Any, Optional, List
20
 
21
  import numpy as np
22
  import pandas as pd
23
  import matplotlib.pyplot as plt
24
 
25
- # statsmodels (нужен для большинства тестов/моделей)
26
  try:
27
  from statsmodels.tsa.stattools import adfuller, kpss
28
  from statsmodels.tsa.seasonal import seasonal_decompose
 
29
  from statsmodels.stats.diagnostic import acorr_ljungbox
 
 
 
30
  STATSMODELS_AVAILABLE = True
31
  except Exception as e:
32
  STATSMODELS_AVAILABLE = False
@@ -35,30 +30,81 @@ except Exception as e:
35
  # optional heavy deps
36
  try:
37
  import pmdarima as pm
 
38
  PM_AVAILABLE = True
39
  except Exception:
40
  PM_AVAILABLE = False
41
 
42
  try:
43
- from scipy.stats import boxcox, boxcox_normmax
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  SCIPY_AVAILABLE = True
45
  except Exception:
46
  SCIPY_AVAILABLE = False
47
 
48
- # ---- helpers / metrics ----
 
 
 
49
  def mae(y_true, y_pred): return np.mean(np.abs(y_true - y_pred))
50
- def rmse(y_true, y_pred): return math.sqrt(np.mean((y_true - y_pred)**2))
 
 
 
 
51
  def mape(y_true, y_pred): return np.mean(np.abs((y_true - y_pred) / (y_true + 1e-9))) * 100.0
52
- def smape(y_true, y_pred): return 100.0 * np.mean(2.0 * np.abs(y_pred - y_true) / (np.abs(y_true) + np.abs(y_pred) + 1e-9))
53
 
54
- # ---- IO / preprocessing ----
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  def load_data(path: str, timestamp_col: str = 'timestamp', tz: Optional[str] = None) -> pd.DataFrame:
56
  if path.endswith('.parquet'):
57
  df = pd.read_parquet(path)
58
  else:
59
  df = pd.read_csv(path)
60
  if timestamp_col not in df.columns:
61
- raise ValueError(f"timestamp column '{timestamp_col}' not found in data")
62
  df[timestamp_col] = pd.to_datetime(df[timestamp_col], errors='coerce')
63
  if tz is not None:
64
  try:
@@ -72,6 +118,7 @@ def load_data(path: str, timestamp_col: str = 'timestamp', tz: Optional[str] = N
72
  df = df.set_index(timestamp_col)
73
  return df
74
 
 
75
  def resample_and_interpolate(df: pd.DataFrame, freq: str = 'D', method: str = 'linear') -> pd.DataFrame:
76
  dfr = df.resample(freq).asfreq()
77
  if method == 'linear':
@@ -81,192 +128,718 @@ def resample_and_interpolate(df: pd.DataFrame, freq: str = 'D', method: str = 'l
81
  else:
82
  return dfr.fillna(method='ffill').interpolate()
83
 
84
- # ---- transforms ----
85
- def apply_log(series: pd.Series):
86
- if (series <= 0).any():
87
- raise ValueError("log transform requires positive values")
88
- return np.log(series)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  def apply_boxcox(series: pd.Series, lmbda: Optional[float] = None):
91
  if not SCIPY_AVAILABLE:
92
- raise ImportError("scipy required for boxcox transformations")
93
  s = series.dropna()
94
  if (s <= 0).any():
95
  raise ValueError("Box-Cox requires positive values")
96
  if lmbda is None:
97
- lmbda = boxcox_normmax(s, brack=(-2,2))
98
  transformed = boxcox(s, lmbda)
99
- out = pd.Series(index=s.index, data=transformed)
100
- return out, lmbda
101
 
102
- def difference(series: pd.Series, d=1):
103
- return series.diff(d)
104
 
105
- # ---- feature engineering ----
 
 
106
  def make_lags(df: pd.DataFrame, col: str, lags: List[int]):
107
  for l in lags:
108
  df[f'{col}_lag_{l}'] = df[col].shift(l)
109
  return df
110
 
 
111
  def make_rolls(df: pd.DataFrame, col: str, windows: List[int]):
112
  for w in windows:
113
  df[f'{col}_roll_mean_{w}'] = df[col].rolling(window=w, min_periods=1).mean()
114
- df[f'{col}_roll_std_{w}'] = df[col].rolling(window=w, min_periods=1).std()
115
- df[f'{col}_roll_min_{w}'] = df[col].rolling(window=w, min_periods=1).min()
116
- df[f'{col}_roll_max_{w}'] = df[col].rolling(window=w, min_periods=1).max()
117
  return df
118
 
119
- def make_time_features(df: pd.DataFrame, index_name: Optional[str] = None):
120
- idx = df.index if index_name is None else pd.to_datetime(df[index_name])
 
121
  df['dayofweek'] = idx.dayofweek
122
  df['month'] = idx.month
 
123
  df['sin_week'] = np.sin(2 * np.pi * df['dayofweek'] / 7)
124
  df['cos_month'] = np.cos(2 * np.pi * (df['month'] - 1) / 12)
125
  return df
126
 
 
 
 
 
127
  def chronological_split(df: pd.DataFrame, frac_train=0.7, frac_val=0.15):
128
  n = len(df)
129
  i_train = int(n * frac_train)
130
  i_val = i_train + int(n * frac_val)
 
131
  train = df.iloc[:i_train].copy()
132
  val = df.iloc[i_train:i_val].copy()
133
  test = df.iloc[i_val:].copy()
 
 
 
 
 
 
 
 
134
  return train, val, test
135
 
136
- # ---- simple models / wrappers ----
137
- def naive_forecast(train: pd.Series, steps: int):
138
- last = train.iloc[-1]
139
- return np.full(steps, last)
140
 
141
- def seasonal_naive_forecast(series: pd.Series, season: int, steps: int):
142
- last = series.iloc[-season:]
143
- reps = int(np.ceil(steps / season))
144
- arr = np.tile(last.values, reps)[:steps]
145
- return arr
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
- def fit_sarimax_wrapper(series: pd.Series, order=(1,0,0), seasonal_order=(0,0,0,0), **kwargs):
148
- if not STATSMODELS_AVAILABLE:
149
- raise ImportError("statsmodels required for SARIMAX")
150
- from statsmodels.tsa.statespace.sarimax import SARIMAX
151
- m = SARIMAX(series.dropna(), order=order, seasonal_order=seasonal_order,
152
- enforce_stationarity=False, enforce_invertibility=False)
153
- res = m.fit(disp=False, **kwargs)
154
- return res
155
 
156
- def forecast_sarimax(fit_res, steps: int, alpha: float = 0.05):
 
 
157
  if hasattr(fit_res, "get_forecast"):
158
  fc = fit_res.get_forecast(steps=steps)
159
  mean = np.asarray(fc.predicted_mean)
160
  try:
161
- conf = fc.conf_int(alpha=alpha)
162
- lower = np.asarray(conf.iloc[:,0])
163
- upper = np.asarray(conf.iloc[:,1])
164
  except Exception:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  lower = np.full(len(mean), np.nan)
166
  upper = np.full(len(mean), np.nan)
 
 
 
 
 
 
 
 
167
  return mean, (lower, upper)
168
- else:
169
- f = fit_res.forecast(steps=steps)
170
- mean = np.asarray(f)
171
- return mean, (np.full(len(mean), np.nan), np.full(len(mean), np.nan))
172
 
173
- # ---- report generator ----
174
- def generate_report_html(out_path: str, plots: List[plt.Figure], tables: Dict[str, pd.DataFrame], title="LR3 report"):
175
- html_parts = [f"<html><head><meta charset='utf-8'><title>{title}</title></head><body><h1>{title}</h1>"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  for name, df in tables.items():
177
  html_parts.append(f"<h2>{name}</h2>")
178
- html_parts.append(df.to_html(classes='table table-striped', border=0))
 
 
 
 
179
  for i, fig in enumerate(plots):
180
- img_path = f"plot_{i}.png"
181
- fig.savefig(img_path, bbox_inches='tight')
182
- html_parts.append(f"<h3>Figure {i+1}</h3><img src='{img_path}' style='max-width:100%'>")
 
 
 
 
 
 
 
 
 
 
183
  html_parts.append("</body></html>")
 
184
  with open(out_path, 'w', encoding='utf-8') as f:
185
  f.write("\n".join(html_parts))
186
  print("Report saved to", out_path)
187
 
188
- # ---- main pipeline ----
189
- def run_pipeline(data_path: str, timestamp_col: str, target_col: str, out_report: str = 'lab3_report.html', freq='D'):
 
 
 
 
 
 
 
190
  df = load_data(data_path, timestamp_col)
191
  if target_col not in df.columns:
192
  numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist()
193
  if not numeric_cols:
194
- raise ValueError("No numeric columns found for target")
195
  target_col = numeric_cols[0]
 
196
 
197
  series = df[target_col].astype('float').copy()
198
- series = resample_and_interpolate(series.to_frame(), freq=freq).iloc[:,0]
 
 
 
 
 
199
 
200
- df_all = series.to_frame(name=target_col)
 
201
  df_all = make_time_features(df_all)
202
- df_all = make_lags(df_all, target_col, [1,2,7,30])
203
- df_all = make_rolls(df_all, target_col, [7,30])
204
- train, val, test = chronological_split(df_all, 0.7, 0.15)
205
- y_train = train[target_col]
206
- y_val = val[target_col]
 
 
 
207
  y_test = test[target_col]
 
208
 
209
- results = []
210
- horizons = [1,7,30]
 
 
 
 
 
 
 
 
 
211
  for h in horizons:
212
- results.append({'model':'naive','h':h,'pred':naive_forecast(y_train,h)})
213
- results.append({'model':'seasonal_naive','h':h,'pred':seasonal_naive_forecast(y_train, season=7, steps=h)})
 
 
 
 
 
214
 
215
- # SARIMAX baseline
216
- sarimax_res = None
 
 
 
 
 
 
 
 
217
  try:
218
- sarimax_res = fit_sarimax_wrapper(y_train, order=(1,1,1))
 
 
219
  for h in horizons:
220
- p, ci = forecast_sarimax(sarimax_res, steps=h)
221
- results.append({'model':'sarimax(1,1,1)','h':h,'pred':p})
 
 
 
 
 
222
  except Exception as e:
223
- print("SARIMAX fit failed:", e)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
 
225
  # pmdarima auto_arima
226
  if PM_AVAILABLE:
227
  try:
228
- auto = pm.auto_arima(y_train.dropna(), seasonal=False, error_action='ignore', suppress_warnings=True)
229
  for h in horizons:
230
  p = auto.predict(n_periods=h)
231
- results.append({'model':'auto_arima','h':h,'pred':p})
 
 
 
 
 
232
  except Exception as e:
233
  print("auto_arima failed:", e)
234
 
235
- # Evaluate
236
- eval_tables = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  plots = []
 
238
  for rec in results:
239
- pred = np.asarray(rec['pred']).ravel()
240
- y_true = y_test.values[:len(pred)]
241
- if len(y_true)==0:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
  continue
243
- eval_tables.append({
244
- 'model':rec['model'],
245
- 'h':rec['h'],
246
- 'MAE':mae(y_true,pred),
247
- 'RMSE':rmse(y_true,pred),
248
- 'MAPE':mape(y_true,pred),
249
- 'SMAPE':smape(y_true,pred)
250
- })
251
- fig, ax = plt.subplots(figsize=(8,3))
252
- ax.plot(y_train.index[-100:], y_train.values[-100:], label='train')
253
- ax.plot(y_test.index[:len(pred)], y_true, label='test')
254
- ax.plot(y_test.index[:len(pred)], pred, label=f'pred_{rec["model"]}_h{rec["h"]}')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  ax.legend()
256
  plots.append(fig)
257
 
258
- eval_df = pd.DataFrame(eval_tables)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
  tables = {'evaluation': eval_df}
260
- generate_report_html(out_report, plots, tables, title="Lab3 Report")
261
- print("Done. Report:", out_report)
262
-
263
- # CLI runner
264
- if __name__ == '__main__':
265
- parser = argparse.ArgumentParser()
266
- parser.add_argument('--data', required=True)
267
- parser.add_argument('--timestamp', default='timestamp')
268
- parser.add_argument('--target', default='target')
269
- parser.add_argument('--out', default='lab3_report.html')
270
- parser.add_argument('--freq', default='D')
271
- args = parser.parse_args()
272
- run_pipeline(args.data, args.timestamp, args.target, out_report=args.out, freq=args.freq)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # lab3_pipeline.py
2
  """
3
+ Полный pipeline для ЛР №3 (выполнение пунктов 3.1-3.8).
4
+ Сохраняйте файл в папке src проекта (TimeSeriesHomework/src/lab3_pipeline.py).
 
 
 
 
 
 
 
 
5
  """
6
 
 
7
  import os
8
  import math
9
  import time
10
+ from typing import List, Dict, Any, Optional, Tuple
11
 
12
  import numpy as np
13
  import pandas as pd
14
  import matplotlib.pyplot as plt
15
 
16
+ # statsmodels и основные тесты
17
  try:
18
  from statsmodels.tsa.stattools import adfuller, kpss
19
  from statsmodels.tsa.seasonal import seasonal_decompose
20
+ from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
21
  from statsmodels.stats.diagnostic import acorr_ljungbox
22
+ from statsmodels.tsa.statespace.sarimax import SARIMAX
23
+ from statsmodels.tsa.api import VAR
24
+
25
  STATSMODELS_AVAILABLE = True
26
  except Exception as e:
27
  STATSMODELS_AVAILABLE = False
 
30
  # optional heavy deps
31
  try:
32
  import pmdarima as pm
33
+
34
  PM_AVAILABLE = True
35
  except Exception:
36
  PM_AVAILABLE = False
37
 
38
  try:
39
+ from arch import arch_model
40
+
41
+ ARCH_AVAILABLE = True
42
+ except Exception:
43
+ ARCH_AVAILABLE = False
44
+
45
+ try:
46
+ from prophet import Prophet
47
+
48
+ PROPHET_AVAILABLE = True
49
+ except Exception:
50
+ PROPHET_AVAILABLE = False
51
+
52
+ # sklearn
53
+ try:
54
+ from sklearn.model_selection import TimeSeriesSplit
55
+ from sklearn.linear_model import LinearRegression
56
+ from sklearn.metrics import r2_score
57
+
58
+ SKLEARN_AVAILABLE = True
59
+ except Exception:
60
+ SKLEARN_AVAILABLE = False
61
+
62
+ # scipy (Box-Cox, Shapiro)
63
+ try:
64
+ from scipy.stats import boxcox, boxcox_normmax, shapiro
65
+
66
  SCIPY_AVAILABLE = True
67
  except Exception:
68
  SCIPY_AVAILABLE = False
69
 
70
+
71
+ # -------------------------------------------------------------------------
72
+ # Metrics
73
+ # -------------------------------------------------------------------------
74
  def mae(y_true, y_pred): return np.mean(np.abs(y_true - y_pred))
75
+
76
+
77
+ def rmse(y_true, y_pred): return math.sqrt(np.mean((y_true - y_pred) ** 2))
78
+
79
+
80
  def mape(y_true, y_pred): return np.mean(np.abs((y_true - y_pred) / (y_true + 1e-9))) * 100.0
 
81
 
82
+
83
+ def smape(y_true, y_pred): return 100.0 * np.mean(
84
+ 2.0 * np.abs(y_pred - y_true) / (np.abs(y_true) + np.abs(y_pred) + 1e-9))
85
+
86
+
87
+ def rmsle(y_true, y_pred): return math.sqrt(np.mean((np.log1p(y_pred) - np.log1p(y_true)) ** 2))
88
+
89
+
90
+ def mase(y_true, y_pred, naive_ref):
91
+ # naive_ref: series used to compute naive diff (e.g. train series)
92
+ denom = np.mean(np.abs(np.diff(naive_ref)))
93
+ if denom == 0:
94
+ return np.nan
95
+ return np.mean(np.abs(y_true - y_pred)) / denom
96
+
97
+
98
+ # -------------------------------------------------------------------------
99
+ # IO & preprocessing utilities
100
+ # -------------------------------------------------------------------------
101
  def load_data(path: str, timestamp_col: str = 'timestamp', tz: Optional[str] = None) -> pd.DataFrame:
102
  if path.endswith('.parquet'):
103
  df = pd.read_parquet(path)
104
  else:
105
  df = pd.read_csv(path)
106
  if timestamp_col not in df.columns:
107
+ raise ValueError(f"timestamp column '{timestamp_col}' not found")
108
  df[timestamp_col] = pd.to_datetime(df[timestamp_col], errors='coerce')
109
  if tz is not None:
110
  try:
 
118
  df = df.set_index(timestamp_col)
119
  return df
120
 
121
+
122
  def resample_and_interpolate(df: pd.DataFrame, freq: str = 'D', method: str = 'linear') -> pd.DataFrame:
123
  dfr = df.resample(freq).asfreq()
124
  if method == 'linear':
 
128
  else:
129
  return dfr.fillna(method='ffill').interpolate()
130
 
131
+
132
+ # -------------------------------------------------------------------------
133
+ # Transformations and stationarity selection
134
+ # -------------------------------------------------------------------------
135
+ def test_stationarity_pair(series: pd.Series) -> Dict[str, Dict[str, Any]]:
136
+ """Возвращает результаты ADF и KPSS"""
137
+ res = {}
138
+ if not STATSMODELS_AVAILABLE:
139
+ raise ImportError("statsmodels required for stationarity tests")
140
+ s = series.dropna()
141
+ if len(s) < 3:
142
+ return {'adf': {'pvalue': np.nan}, 'kpss': {'pvalue': np.nan}}
143
+ adf_res = adfuller(s, autolag='AIC', regression='c')
144
+ kpss_res = kpss(s, nlags='auto')
145
+ return {'adf': {'stat': adf_res[0], 'pvalue': adf_res[1]}, 'kpss': {'stat': kpss_res[0], 'pvalue': kpss_res[1]}}
146
+
147
+
148
+ def try_transformations_and_choose(y_train: pd.Series, seasonal_period: int = 7):
149
+ """
150
+ Пробуем набор преобразований:
151
+ - none
152
+ - log (если >0)
153
+ - boxcox (если >0 и scipy доступен)
154
+ - diff(1), diff(s), diff(1).diff(s)
155
+ Выбираем ту комбинацию, которая минимизирует конфликт ADF/KPSS:
156
+ критерий: ADF.pvalue < 0.05 (хочется) и KPSS.pvalue > 0.05 (хочется).
157
+ Возвращаем: transformed_series, meta dict (applied transformations, lambda)
158
+ """
159
+ candidates = []
160
+ # original
161
+ candidates.append(('none', y_train))
162
+ # log
163
+ if (y_train > 0).all():
164
+ candidates.append(('log', np.log(y_train)))
165
+ # boxcox
166
+ if (y_train > 0).all() and SCIPY_AVAILABLE:
167
+ try:
168
+ lam = boxcox_normmax(y_train.dropna(), brack=(-2, 2))
169
+ bc, _ = apply_boxcox(y_train, lmbda=lam)
170
+ candidates.append((f'boxcox_{lam:.4f}', bc))
171
+ except Exception:
172
+ pass
173
+ # differenced versions
174
+ # diff1 of original or of transformed series
175
+ final_candidates = []
176
+ for name, ser in candidates:
177
+ ser_clean = ser.dropna()
178
+ final_candidates.append((name, 0, ser_clean)) # 0 differences
179
+ if len(ser_clean) > 3:
180
+ final_candidates.append((name, 1, ser_clean.diff(1).dropna()))
181
+ if seasonal_period and len(ser_clean) > seasonal_period + 3:
182
+ final_candidates.append((name, seasonal_period, ser_clean.diff(seasonal_period).dropna()))
183
+ final_candidates.append(
184
+ (name, ('1+s', seasonal_period), ser_clean.diff(1).diff(seasonal_period).dropna()))
185
+ # Evaluate candidates
186
+ scored = []
187
+ for cand in final_candidates:
188
+ tag = cand[0]
189
+ d = cand[1]
190
+ ser = cand[2]
191
+ if ser.dropna().shape[0] < 10:
192
+ continue
193
+ try:
194
+ tests = test_stationarity_pair(ser)
195
+ # score: lower is better. We want ADF.p < 0.05 and KPSS.p > 0.05.
196
+ adf_p = tests['adf']['pvalue'] if tests['adf']['pvalue'] is not None else 1.0
197
+ kpss_p = tests['kpss']['pvalue'] if tests['kpss']['pvalue'] is not None else 0.0
198
+ # penalty for bad ADF (want small) and bad KPSS (want big)
199
+ score = (adf_p) + (1.0 - kpss_p)
200
+ scored.append({'tag': tag, 'diff': d, 'score': score, 'adf_p': adf_p, 'kpss_p': kpss_p, 'series': ser})
201
+ except Exception:
202
+ continue
203
+ if not scored:
204
+ return y_train, {'method': 'none', 'lambda': None}
205
+ scored = sorted(scored, key=lambda x: x['score'])
206
+ best = scored[0]
207
+ meta = {'method': best['tag'], 'diff': best['diff'], 'adf_p': best['adf_p'], 'kpss_p': best['kpss_p']}
208
+ return best['series'], meta
209
+
210
 
211
  def apply_boxcox(series: pd.Series, lmbda: Optional[float] = None):
212
  if not SCIPY_AVAILABLE:
213
+ raise ImportError("scipy required for boxcox")
214
  s = series.dropna()
215
  if (s <= 0).any():
216
  raise ValueError("Box-Cox requires positive values")
217
  if lmbda is None:
218
+ lmbda = boxcox_normmax(s, brack=(-2, 2))
219
  transformed = boxcox(s, lmbda)
220
+ return pd.Series(index=s.index, data=transformed), float(lmbda)
 
221
 
 
 
222
 
223
+ # -------------------------------------------------------------------------
224
+ # Feature engineering
225
+ # -------------------------------------------------------------------------
226
  def make_lags(df: pd.DataFrame, col: str, lags: List[int]):
227
  for l in lags:
228
  df[f'{col}_lag_{l}'] = df[col].shift(l)
229
  return df
230
 
231
+
232
  def make_rolls(df: pd.DataFrame, col: str, windows: List[int]):
233
  for w in windows:
234
  df[f'{col}_roll_mean_{w}'] = df[col].rolling(window=w, min_periods=1).mean()
235
+ df[f'{col}_roll_std_{w}'] = df[col].rolling(window=w, min_periods=1).std()
236
+ df[f'{col}_roll_min_{w}'] = df[col].rolling(window=w, min_periods=1).min()
237
+ df[f'{col}_roll_max_{w}'] = df[col].rolling(window=w, min_periods=1).max()
238
  return df
239
 
240
+
241
+ def make_time_features(df: pd.DataFrame):
242
+ idx = df.index
243
  df['dayofweek'] = idx.dayofweek
244
  df['month'] = idx.month
245
+ df['is_weekend'] = idx.dayofweek >= 5
246
  df['sin_week'] = np.sin(2 * np.pi * df['dayofweek'] / 7)
247
  df['cos_month'] = np.cos(2 * np.pi * (df['month'] - 1) / 12)
248
  return df
249
 
250
+
251
+ # -------------------------------------------------------------------------
252
+ # Splits, CV and strategies
253
+ # -------------------------------------------------------------------------
254
  def chronological_split(df: pd.DataFrame, frac_train=0.7, frac_val=0.15):
255
  n = len(df)
256
  i_train = int(n * frac_train)
257
  i_val = i_train + int(n * frac_val)
258
+
259
  train = df.iloc[:i_train].copy()
260
  val = df.iloc[i_train:i_val].copy()
261
  test = df.iloc[i_val:].copy()
262
+
263
+ # Проверяем непрерывность дат
264
+ all_data = pd.concat([train, val, test])
265
+ date_diff = (all_data.index[1:] - all_data.index[:-1]).value_counts()
266
+
267
+ if len(date_diff) > 1:
268
+ print(f"Предупреждение: обнаружены разные интервалы между датами: {date_diff.index.tolist()}")
269
+
270
  return train, val, test
271
 
 
 
 
 
272
 
273
+ def expanding_window_cv(X: pd.DataFrame, y: pd.Series, model_fit_predict, initial_train_size: int, h: int,
274
+ n_splits: int = 5):
275
+ """Expanding window: [0:t] -> [t+1:t+h]"""
276
+ n = len(X)
277
+ step = (n - initial_train_size - h) // n_splits if n_splits > 0 else h
278
+ metrics = []
279
+ for i in range(n_splits):
280
+ end_train = initial_train_size + i * step
281
+ train_X, train_y = X.iloc[:end_train], y.iloc[:end_train]
282
+ test_X, test_y = X.iloc[end_train:end_train + h], y.iloc[end_train:end_train + h]
283
+ y_pred = model_fit_predict(train_X, train_y, h)
284
+ metrics.append({'fold': i, 'mae': mae(test_y.values, y_pred), 'rmse': rmse(test_y.values, y_pred)})
285
+ return pd.DataFrame(metrics)
286
+
287
+
288
+ def rolling_window_cv(X: pd.DataFrame, y: pd.Series, model_fit_predict, window: int, h: int, n_splits: int = 5):
289
+ """Rolling window: [t-w:t] -> [t+1:t+h]"""
290
+ n = len(X)
291
+ step = (n - window - h) // n_splits if n_splits > 0 else h
292
+ metrics = []
293
+ for i in range(n_splits):
294
+ start = i * step
295
+ end = start + window
296
+ train_X, train_y = X.iloc[start:end], y.iloc[start:end]
297
+ test_X, test_y = X.iloc[end:end + h], y.iloc[end:end + h]
298
+ y_pred = model_fit_predict(train_X, train_y, h)
299
+ metrics.append({'fold': i, 'mae': mae(test_y.values, y_pred), 'rmse': rmse(test_y.values, y_pred)})
300
+ return pd.DataFrame(metrics)
301
 
 
 
 
 
 
 
 
 
302
 
303
+ # Strategies: recursive, direct, hybrid
304
+ def forecast_recursive_arima(fit_res, steps: int, last_date: pd.Timestamp = None, freq: str = 'D'):
305
+ """Wrapper for SARIMAX results with proper date index"""
306
  if hasattr(fit_res, "get_forecast"):
307
  fc = fit_res.get_forecast(steps=steps)
308
  mean = np.asarray(fc.predicted_mean)
309
  try:
310
+ conf = fc.conf_int()
311
+ low = np.asarray(conf.iloc[:, 0])
312
+ high = np.asarray(conf.iloc[:, 1])
313
  except Exception:
314
+ low = np.full(len(mean), np.nan)
315
+ high = np.full(len(mean), np.nan)
316
+
317
+ # Создаем правильный индекс
318
+ if last_date is not None:
319
+ dates = create_forecast_index(last_date, steps, freq)
320
+ mean = pd.Series(mean, index=dates)
321
+ low = pd.Series(low, index=dates)
322
+ high = pd.Series(high, index=dates)
323
+
324
+ return mean, (low, high)
325
+ else:
326
+ mean = fit_res.forecast(steps=steps)
327
+ if last_date is not None:
328
+ dates = create_forecast_index(last_date, steps, freq)
329
+ mean = pd.Series(mean, index=dates)
330
+ return mean, (None, None)
331
+
332
+
333
+ # Direct strategy for SARIMAX: fit separate models for each horizon
334
+ def forecast_direct_arima(train_series: pd.Series, h: int, order=(1, 0, 0)):
335
+ if not STATSMODELS_AVAILABLE:
336
+ raise ImportError("statsmodels required")
337
+ # create shifted target for forecasting h steps ahead
338
+ df = train_series.to_frame("y")
339
+ df['y_target_h'] = df['y'].shift(-h)
340
+ df = df.dropna()
341
+ # naive approach: use previous value as predictor (simple)
342
+ last = train_series.iloc[-1]
343
+ return np.full(h, last)
344
+
345
+
346
+ # -------------------------------------------------------------------------
347
+ # Models training wrapper
348
+ # -------------------------------------------------------------------------
349
+ def fit_sarimax_simple(series: pd.Series, order=(1, 0, 0), seasonal_order=(0, 0, 0, 0), **kwargs):
350
+ if not STATSMODELS_AVAILABLE:
351
+ raise ImportError("statsmodels required")
352
+ m = SARIMAX(series.dropna(), order=order, seasonal_order=seasonal_order,
353
+ enforce_stationarity=False, enforce_invertibility=False)
354
+ res = m.fit(disp=False, **kwargs)
355
+ return res
356
+
357
+
358
+ def forecast_sarimax(fit_res, steps: int, alpha: float = 0.05) -> Tuple[np.ndarray, Tuple[np.ndarray, np.ndarray]]:
359
+ """
360
+ Делает прогноз из обученного SARIMAX-результата.
361
+ Возвращает (mean, (lower, upper)) — numpy arrays длины steps.
362
+ """
363
+ try:
364
+ if hasattr(fit_res, "get_forecast"):
365
+ fc = fit_res.get_forecast(steps=steps)
366
+ mean = np.asarray(fc.predicted_mean)
367
+
368
+ # Проверяем на NaN
369
+ if np.any(np.isnan(mean)):
370
+ # Fallback: используем простой forecast
371
+ mean = fit_res.forecast(steps=steps)
372
+ mean = np.asarray(mean)
373
+
374
+ try:
375
+ conf = fc.conf_int(alpha=alpha)
376
+ lower = np.asarray(conf.iloc[:, 0])
377
+ upper = np.asarray(conf.iloc[:, 1])
378
+
379
+ # Проверяем доверительные интервалы на NaN
380
+ if np.any(np.isnan(lower)) or np.any(np.isnan(upper)):
381
+ lower = np.full(len(mean), np.nan)
382
+ upper = np.full(len(mean), np.nan)
383
+
384
+ except Exception:
385
+ lower = np.full(len(mean), np.nan)
386
+ upper = np.full(len(mean), np.nan)
387
+
388
+ return mean, (lower, upper)
389
+ else:
390
+ # fallback на forecast
391
+ mean = fit_res.forecast(steps=steps)
392
+ mean = np.asarray(mean)
393
  lower = np.full(len(mean), np.nan)
394
  upper = np.full(len(mean), np.nan)
395
+ return mean, (lower, upper)
396
+
397
+ except Exception as e:
398
+ # Если все методы не сработали, возвращаем массив NaN
399
+ print(f"Warning: SARIMAX forecast failed: {e}")
400
+ mean = np.full(steps, np.nan)
401
+ lower = np.full(steps, np.nan)
402
+ upper = np.full(steps, np.nan)
403
  return mean, (lower, upper)
 
 
 
 
404
 
405
+ def fit_auto_arima(series: pd.Series, seasonal=False, m=1, **kwargs):
406
+ if not PM_AVAILABLE:
407
+ raise ImportError("pmdarima not installed")
408
+ model = pm.auto_arima(series.dropna(), seasonal=seasonal, m=m, error_action='ignore', suppress_warnings=True,
409
+ **kwargs)
410
+ return model
411
+
412
+
413
+ def fit_var(df: pd.DataFrame, maxlags=15):
414
+ if not STATSMODELS_AVAILABLE:
415
+ raise ImportError("statsmodels required")
416
+ model = VAR(df.dropna())
417
+ sel = model.select_order(maxlags=maxlags)
418
+ best = 1
419
+ try:
420
+ so = sel.selected_orders
421
+ for k in ('aic', 'bic', 'fpe', 'hqic'):
422
+ if so.get(k) is not None:
423
+ best = int(so[k])
424
+ break
425
+ except Exception:
426
+ best = 1
427
+ res = model.fit(maxlags=best)
428
+ return res
429
+
430
+
431
+ def fit_garch_on_residuals(residuals, p=1, q=1):
432
+ if not ARCH_AVAILABLE:
433
+ raise ImportError("arch not installed")
434
+ am = arch_model(residuals, vol='Garch', p=p, q=q, dist='normal')
435
+ r = am.fit(disp='off')
436
+ return r
437
+
438
+
439
+ # -------------------------------------------------------------------------
440
+ # Diagnostics and tests
441
+ # -------------------------------------------------------------------------
442
+ def ljung_box_test(resid: np.ndarray, lags: List[int] = [10]):
443
+ if not STATSMODELS_AVAILABLE:
444
+ raise ImportError("statsmodels required")
445
+ res = acorr_ljungbox(resid, lags=lags, return_df=True)
446
+ return res
447
+
448
+
449
+ def shapiro_test(resid: np.ndarray):
450
+ if not SCIPY_AVAILABLE:
451
+ raise ImportError("scipy required")
452
+ stat, p = shapiro(resid)
453
+ return {'stat': stat, 'pvalue': p}
454
+
455
+
456
+ def simple_dm_test(e1: np.ndarray, e2: np.ndarray):
457
+ """
458
+ Простая реализация Diebold-Mariano теста по разности квадратических ошибок.
459
+ Возвращает t-stat и p-value (двухсторонний).
460
+ Примечание: это упрощённая версия, без HAC коррекции.
461
+ """
462
+ # use squared error loss
463
+ d = (e1 - e2)
464
+ n = len(d)
465
+ dbar = np.mean(d)
466
+ sd = np.var(d, ddof=1)
467
+ denom = math.sqrt(sd / n) if sd > 0 else np.nan
468
+ if denom == 0 or np.isnan(denom):
469
+ return {'stat': np.nan, 'pvalue': np.nan}
470
+ tstat = dbar / denom
471
+ # two-sided pval from Student's t approx
472
+ from scipy.stats import t as student_t
473
+ pval = 2 * (1 - student_t.cdf(abs(tstat), df=n - 1))
474
+ return {'stat': float(tstat), 'pvalue': float(pval)}
475
+
476
+
477
+ # -------------------------------------------------------------------------
478
+ # Report generation (HTML)
479
+ # -------------------------------------------------------------------------
480
+ def generate_report_html(out_path: str, plots: List[plt.Figure], tables: Dict[str, pd.DataFrame], title="Lab3 Report"):
481
+ import base64
482
+ from io import BytesIO
483
+
484
+ html_parts = [f"""
485
+ <html>
486
+ <head>
487
+ <meta charset='utf-8'>
488
+ <title>{title}</title>
489
+ <style>
490
+ body {{ font-family: Arial, sans-serif; margin: 20px; background-color: white; color: black; }}
491
+ table {{ border-collapse: collapse; width: 100%; margin: 10px 0; }}
492
+ th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
493
+ th {{ background-color: #f2f2f2; }}
494
+ img {{ max-width: 100%; height: auto; margin: 10px 0; }}
495
+ .table-container {{ overflow-x: auto; }}
496
+ </style>
497
+ </head>
498
+ <body>
499
+ <h1>{title}</h1>
500
+ """]
501
+
502
+ # Таблицы
503
  for name, df in tables.items():
504
  html_parts.append(f"<h2>{name}</h2>")
505
+ html_parts.append('<div class="table-container">')
506
+ html_parts.append(df.to_html(classes='table table-striped', border=0, index=True))
507
+ html_parts.append('</div>')
508
+
509
+ # Графики как base64
510
  for i, fig in enumerate(plots):
511
+ # Сохраняем рисунок в буфер
512
+ buf = BytesIO()
513
+ fig.savefig(buf, format='png', bbox_inches='tight', dpi=100)
514
+ buf.seek(0)
515
+
516
+ # Кодируем в base64
517
+ img_data = base64.b64encode(buf.read()).decode('utf-8')
518
+ html_parts.append(f'<h3>Figure {i + 1}</h3>')
519
+ html_parts.append(f'<img src="data:image/png;base64,{img_data}" alt="Figure {i + 1}">')
520
+
521
+ # Закрываем рисунок чтобы освободить память
522
+ plt.close(fig)
523
+
524
  html_parts.append("</body></html>")
525
+
526
  with open(out_path, 'w', encoding='utf-8') as f:
527
  f.write("\n".join(html_parts))
528
  print("Report saved to", out_path)
529
 
530
+ # -------------------------------------------------------------------------
531
+ # Main runner that orchestrates everything
532
+ # -------------------------------------------------------------------------
533
+ def run_pipeline(data_path: str, timestamp_col: str, target_col: str,
534
+ out_report: str = 'lab3_report.html', freq: str = 'D'):
535
+ """
536
+ Главная точка запуска pipeline.
537
+ """
538
+ print("Loading", data_path)
539
  df = load_data(data_path, timestamp_col)
540
  if target_col not in df.columns:
541
  numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist()
542
  if not numeric_cols:
543
+ raise ValueError("No numeric columns found")
544
  target_col = numeric_cols[0]
545
+ print("Target not found, using", target_col)
546
 
547
  series = df[target_col].astype('float').copy()
548
+ series = resample_and_interpolate(series.to_frame(), freq=freq).iloc[:, 0]
549
+ print("Series length after resample:", len(series))
550
+
551
+ # 3.1 Preprocessing & transformation selection
552
+ transformed, meta = try_transformations_and_choose(series, seasonal_period=7)
553
+ print("Chosen transform:", meta)
554
 
555
+ # 3.2 Feature engineering
556
+ df_all = transformed.to_frame(name=target_col)
557
  df_all = make_time_features(df_all)
558
+ df_all = make_lags(df_all, target_col, [1, 2, 7, 30])
559
+ df_all = make_rolls(df_all, target_col, [7, 30])
560
+
561
+ # dropna rows with lag features
562
+ df_all = df_all.dropna()
563
+ train, val, test = chronological_split(df_all, frac_train=0.7, frac_val=0.15)
564
+ y_train = train[target_col];
565
+ y_val = val[target_col];
566
  y_test = test[target_col]
567
+ print("Sizes train/val/test:", len(y_train), len(y_val), len(y_test))
568
 
569
+ # 3.3 Models: benchmarks + SARIMAX + optional auto_arima + VAR
570
+ results = [] # each elem: dict(model, h, preds (np.array), extra)
571
+ horizons = [1, 7, 30]
572
+
573
+ # Определяем частоту для прогнозов
574
+ try:
575
+ inferred_freq = pd.infer_freq(y_train.index) or freq
576
+ except:
577
+ inferred_freq = freq
578
+
579
+ # Benchmarks
580
  for h in horizons:
581
+ pred_values = np.full(h, y_train.iloc[-1])
582
+ pred_dates = create_forecast_index(y_train.index[-1], h, inferred_freq)
583
+ results.append({
584
+ 'model': 'naive',
585
+ 'h': h,
586
+ 'pred': pd.Series(pred_values, index=pred_dates)
587
+ })
588
 
589
+ if len(y_train) >= 7:
590
+ seasonal_pred = seasonal_naive_forecast(y_train, season=7, steps=h)
591
+ seasonal_dates = create_forecast_index(y_train.index[-1], h, inferred_freq)
592
+ results.append({
593
+ 'model': 'seasonal_naive',
594
+ 'h': h,
595
+ 'pred': pd.Series(seasonal_pred, index=seasonal_dates)
596
+ })
597
+
598
+ # SES/Holt (simple forecasting for 1-step and iterated for multi-step)
599
  try:
600
+ from statsmodels.tsa.holtwinters import SimpleExpSmoothing, ExponentialSmoothing
601
+ # SES as simple baseline
602
+ ses = SimpleExpSmoothing(y_train.dropna()).fit(optimized=True)
603
  for h in horizons:
604
+ pred = ses.forecast(h)
605
+ pred_dates = create_forecast_index(y_train.index[-1], h, inferred_freq)
606
+ results.append({
607
+ 'model': 'SES',
608
+ 'h': h,
609
+ 'pred': pd.Series(pred, index=pred_dates)
610
+ })
611
  except Exception as e:
612
+ print("SES skipped:", e)
613
+
614
+ # SARIMAX baseline
615
+ if STATSMODELS_AVAILABLE:
616
+ try:
617
+ # Проверяем, что данные подходят для SARIMAX
618
+ if len(y_train.dropna()) > 10 and y_train.var() > 1e-6: # достаточное количество точек и дисперсия
619
+ sar = fit_sarimax_simple(y_train, order=(1, 1, 1))
620
+
621
+ # Проверяем, что модель сходилась
622
+ if hasattr(sar, 'mle_retvals') and sar.mle_retvals.get('converged', False):
623
+ for h in horizons:
624
+ mean, (lower, upper) = forecast_sarimax(sar, steps=h)
625
+
626
+ # Проверяем, что прогнозы не все NaN
627
+ if not np.all(np.isnan(mean)):
628
+ pred_dates = create_forecast_index(y_train.index[-1], h, inferred_freq)
629
+ results.append({
630
+ 'model': 'SARIMAX(1,1,1)',
631
+ 'h': h,
632
+ 'pred': pd.Series(mean, index=pred_dates)
633
+ })
634
+ else:
635
+ print(f"SARIMAX returned all NaN for horizon {h}")
636
+ else:
637
+ print("SARIMAX model did not converge")
638
+ else:
639
+ print("Insufficient data for SARIMAX")
640
+ except Exception as e:
641
+ print("SARIMAX failed:", e)
642
 
643
  # pmdarima auto_arima
644
  if PM_AVAILABLE:
645
  try:
646
+ auto = fit_auto_arima(y_train, seasonal=False)
647
  for h in horizons:
648
  p = auto.predict(n_periods=h)
649
+ pred_dates = create_forecast_index(y_train.index[-1], h, inferred_freq)
650
+ results.append({
651
+ 'model': 'auto_arima',
652
+ 'h': h,
653
+ 'pred': pd.Series(p, index=pred_dates)
654
+ })
655
  except Exception as e:
656
  print("auto_arima failed:", e)
657
 
658
+ # VAR if multivariate
659
+ if STATSMODELS_AVAILABLE and df.select_dtypes(include=[np.number]).shape[1] >= 2:
660
+ try:
661
+ num_df = df.select_dtypes(include=[np.number]).dropna()
662
+ var_res = fit_var(num_df, maxlags=5)
663
+ fut = var_res.forecast(var_res.endog[-var_res.k_ar:], steps=30)
664
+ # fut is array shape (30, k)
665
+ # wrap as predictions per horizon for the first variable
666
+ for h in [30]:
667
+ pred_dates = create_forecast_index(y_train.index[-1], h, inferred_freq)
668
+ results.append({
669
+ 'model': 'VAR',
670
+ 'h': h,
671
+ 'pred': pd.Series(fut[:h, 0], index=pred_dates)
672
+ })
673
+ except Exception as e:
674
+ print("VAR failed:", e)
675
+
676
+ # 3.6 Diagnostics later for top models
677
+ # 3.7 Evaluate on test set
678
+ eval_rows = []
679
  plots = []
680
+
681
  for rec in results:
682
+ model_name = rec['model']
683
+ h = rec['h']
684
+ pred = rec['pred']
685
+
686
+ # Выравниваем прогнозы с тестовыми данными по времени
687
+ if hasattr(pred, 'index'):
688
+ # Для прогнозов с правильным индексом
689
+ aligned_pred = pred
690
+ # Берем только первые h точек тестовых данных для сравнения
691
+ y_true_aligned = y_test.iloc[:min(h, len(y_test))]
692
+ else:
693
+ # Для прогнозов без индекса (старый формат)
694
+ pred_values = np.asarray(pred).ravel()
695
+ aligned_pred = pd.Series(pred_values, index=y_test.index[:len(pred_values)])
696
+ y_true_aligned = y_test.iloc[:len(pred_values)]
697
+
698
+ if len(y_true_aligned) == 0:
699
  continue
700
+
701
+ # Обрезаем прогноз до длины тестовых данных
702
+ aligned_pred = aligned_pred.iloc[:len(y_true_aligned)]
703
+
704
+ # Вычисляем метрики
705
+ row = {
706
+ 'model': model_name,
707
+ 'h': h,
708
+ 'MAE': mae(y_true_aligned.values, aligned_pred.values),
709
+ 'RMSE': rmse(y_true_aligned.values, aligned_pred.values),
710
+ 'MAPE': mape(y_true_aligned.values, aligned_pred.values),
711
+ 'SMAPE': smape(y_true_aligned.values, aligned_pred.values)
712
+ }
713
+ # MASE: use naive in-sample reference
714
+ row['MASE'] = mase(y_true_aligned.values, aligned_pred.values, y_train.values)
715
+ # R2 where possible
716
+ try:
717
+ row['R2'] = float((1 - np.sum((y_true_aligned.values - aligned_pred.values) ** 2) / np.sum(
718
+ (y_true_aligned.values - np.mean(y_true_aligned.values)) ** 2)))
719
+ except Exception:
720
+ row['R2'] = np.nan
721
+ eval_rows.append(row)
722
+
723
+ # Визуализация
724
+ fig, ax = plt.subplots(figsize=(8, 3))
725
+
726
+ # Показываем больше данных для контекста
727
+ context_points = min(200, len(y_train))
728
+ ax.plot(y_train.index[-context_points:], y_train.values[-context_points:],
729
+ label='train', alpha=0.7)
730
+
731
+ if len(val) > 0:
732
+ ax.plot(val.index, val.values, label='val', alpha=0.7)
733
+
734
+ ax.plot(y_test.index, y_test.values, label='test', alpha=0.7)
735
+
736
+ # Прогнозы с правильными датами
737
+ ax.plot(aligned_pred.index, aligned_pred.values,
738
+ label=f'pred_{model_name}_h{h}', linewidth=2)
739
+
740
  ax.legend()
741
  plots.append(fig)
742
 
743
+ eval_df = pd.DataFrame(eval_rows)
744
+
745
+ # Diagnostics for top-3 by RMSE
746
+ diag_tables = {}
747
+ try:
748
+ top3 = eval_df.sort_values('RMSE').head(3)['model'].tolist()
749
+ except Exception:
750
+ top3 = []
751
+ for m in top3:
752
+ # find corresponding fitted residuals if model was SARIMAX etc.
753
+ if m.startswith('SARIMAX'):
754
+ try:
755
+ resid = sar.resid.dropna()
756
+ lb = acorr_ljungbox(resid, lags=[10], return_df=True)
757
+ diag_tables[f'ljungbox_{m}'] = lb
758
+ if SCIPY_AVAILABLE:
759
+ sh = shapiro(resid)
760
+ diag_tables[f'shapiro_{m}'] = pd.DataFrame([{'stat': sh[0], 'pvalue': sh[1]}])
761
+ except Exception:
762
+ pass
763
+
764
+ # Diebold-Mariano pairwise for top 2 models (if available)
765
+ dm_table = None
766
+ try:
767
+ if len(eval_df) >= 2:
768
+ sorted_models = eval_df.sort_values('RMSE')
769
+ if len(sorted_models) >= 2:
770
+ m1 = sorted_models.iloc[0]['model']
771
+ m2 = sorted_models.iloc[1]['model']
772
+ # pick their predictions at h=1 (if exist)
773
+ pred1 = None;
774
+ pred2 = None
775
+ for rec in results:
776
+ if rec['model'] == m1 and rec['h'] == 1:
777
+ pred1 = rec['pred']
778
+ if rec['model'] == m2 and rec['h'] == 1:
779
+ pred2 = rec['pred']
780
+ if pred1 is not None and pred2 is not None:
781
+ # align lengths with test
782
+ y_true = y_test.values[:min(len(pred1), len(y_test))]
783
+ e1 = (y_true - pred1.values[:len(y_true)]) ** 2
784
+ e2 = (y_true - pred2.values[:len(y_true)]) ** 2
785
+ dm = simple_dm_test(e1, e2)
786
+ dm_table = pd.DataFrame(
787
+ [{'model1': m1, 'model2': m2, 'dm_stat': dm['stat'], 'pvalue': dm['pvalue']}])
788
+ except Exception:
789
+ dm_table = None
790
+
791
+ # Generate report
792
  tables = {'evaluation': eval_df}
793
+ if diag_tables:
794
+ tables.update(diag_tables)
795
+ if dm_table is not None:
796
+ tables['dm_test'] = dm_table
797
+
798
+ generate_report_html(out_report, plots, tables, title="Lab3 Full Report")
799
+ print("Pipeline finished. Report:", out_report)
800
+
801
+ # Ensure we have at least some predictions
802
+ if not results:
803
+ st.warning("Все модели вернули NaN. Использую простой наивный прогноз.")
804
+ for h in horizons:
805
+ pred_values = np.full(h, y_train.iloc[-1] if len(y_train) > 0 else 0)
806
+ pred_dates = create_forecast_index(y_train.index[-1], h, inferred_freq)
807
+ results.append({
808
+ 'model': 'fallback_naive',
809
+ 'h': h,
810
+ 'pred': pd.Series(pred_values, index=pred_dates)
811
+ })
812
+
813
+
814
+ # -------------------------
815
+ # helpers used in the pipeline but defined later
816
+ # -------------------------
817
+ def seasonal_naive_forecast(series: pd.Series, season: int, steps: int):
818
+ last = series.iloc[-season:]
819
+ reps = int(np.ceil(steps / season))
820
+ arr = np.tile(last.values, reps)[:steps]
821
+ return arr
822
+
823
+
824
+ def create_forecast_index(last_train_date: pd.Timestamp, steps: int, freq: str = 'D') -> pd.DatetimeIndex:
825
+ """Создает правильный временной индекс для прогнозов"""
826
+ try:
827
+ # Если freq = 'auto', пытаемся определить частоту
828
+ if freq == 'auto':
829
+ freq = pd.infer_freq(pd.DatetimeIndex([last_train_date])) or 'D'
830
+
831
+ # Создаем индекс с правильным смещением
832
+ if isinstance(last_train_date, pd.Timestamp):
833
+ start_date = last_train_date + pd.Timedelta(days=1)
834
+ else:
835
+ start_date = last_train_date + pd.DateOffset(days=1)
836
+
837
+ return pd.date_range(
838
+ start=start_date,
839
+ periods=steps,
840
+ freq=freq
841
+ )
842
+ except Exception as e:
843
+ print(f"Warning: could not create proper date index: {e}")
844
+ # Fallback: числовой индекс
845
+ return pd.RangeIndex(start=0, stop=steps)
src/streamlit_app.py CHANGED
@@ -1505,26 +1505,28 @@ def render_lab2():
1505
 
1506
  color = colors[color_idx % len(colors)]
1507
 
 
1508
  # Создаём индексы для прогноза (продолжение после обучающей выборки)
1509
  if len(forecast) > 0:
1510
- # Определяем частоту временного ряда
1511
  try:
1512
- freq = pd.infer_freq(s_train_original.index) or pd.infer_freq(s_test_original.index) or 'D'
1513
- # Создаём даты для прогноза - используем pd.date_range напрямую
1514
- last_train_date = s_train_original.index[-1]
1515
- # Создаём даты начиная с последней даты + 1 период
1516
- # Используем periods=len(forecast)+1 и берём все кроме первого
 
 
1517
  forecast_dates = pd.date_range(
1518
- start=last_train_date,
1519
- periods=len(forecast) + 1,
1520
  freq=freq
1521
- )[1:] # Берём все даты кроме первой (которая равна last_train_date)
1522
  except Exception as e:
1523
- # Если не удалось определить частоту, используем индексы тестовой выборки
1524
  try:
1525
  forecast_dates = s_test_original.index[:len(forecast)]
1526
  except:
1527
- # Последний вариант - создаем простой числовой индекс
1528
  forecast_dates = range(len(s_train_original), len(s_train_original) + len(forecast))
1529
 
1530
  # Добавляем доверительные интервалы, если они есть
@@ -1578,32 +1580,28 @@ def render_lab2():
1578
  ))
1579
 
1580
  color_idx += 1
1581
-
1582
  # Наивный прогноз (если есть)
1583
  if 'Naive' in all_forecasts:
1584
  naive_forecast_vals = all_forecasts['Naive']
1585
  try:
1586
- freq = pd.infer_freq(s_train_original.index) or pd.infer_freq(s_test_original.index) or 'D'
1587
- last_train_date = s_train_original.index[-1]
1588
- # Создаём даты начиная с последней даты + 1 период
 
 
 
 
1589
  naive_dates = pd.date_range(
1590
- start=last_train_date,
1591
- periods=len(naive_forecast_vals) + 1,
1592
  freq=freq
1593
- )[1:] # Берём все даты кроме первой
1594
  except Exception as e:
1595
  try:
1596
  naive_dates = s_test_original.index[:len(naive_forecast_vals)]
1597
  except:
1598
  naive_dates = range(len(s_train_original), len(s_train_original) + len(naive_forecast_vals))
1599
-
1600
- fig.add_trace(go.Scatter(
1601
- x=naive_dates,
1602
- y=naive_forecast_vals,
1603
- name='Naive (прогноз)',
1604
- line=dict(dash='dot', color='gray', width=2),
1605
- mode='lines'
1606
- ))
1607
 
1608
  # Вертикальная линия, разделяющая train и test
1609
  if len(s_train_original) > 0:
@@ -1927,6 +1925,554 @@ import streamlit.components.v1 as components
1927
  import pandas as pd
1928
  from pathlib import Path
1929
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1930
  def render_lab3():
1931
  st.title("🧪 ЛР №3: Сравнительный анализ классических моделей")
1932
 
@@ -2169,7 +2715,11 @@ def render_lab3():
2169
  out_report = st.text_input("Путь для отчёта (HTML)", "./lab3_report.html")
2170
  freq = st.selectbox("Частота ресемплинга", ['D','W','M'])
2171
 
2172
- if st.button("Запустить полный pipeline и сформировать отчёт"):
 
 
 
 
2173
  tmp = "./_lab3_input_tmp.csv"
2174
  # сохраняем df с колонкой timestamp
2175
  df.to_csv(tmp, index=False)
 
1505
 
1506
  color = colors[color_idx % len(colors)]
1507
 
1508
+ # Создаём индексы для прогноза (продолжение после обучающей выборки)
1509
  # Создаём индексы для прогноза (продолжение после обучающей выборки)
1510
  if len(forecast) > 0:
 
1511
  try:
1512
+ # Правильное создание временных индексов для прогнозов
1513
+ if hasattr(s_train_original.index, 'freq') and s_train_original.index.freq is not None:
1514
+ freq = s_train_original.index.freq
1515
+ else:
1516
+ freq = pd.infer_freq(s_train_original.index) or 'D'
1517
+
1518
+ last_date = s_train_original.index[-1]
1519
  forecast_dates = pd.date_range(
1520
+ start=last_date + pd.Timedelta(days=1),
1521
+ periods=len(forecast),
1522
  freq=freq
1523
+ )
1524
  except Exception as e:
1525
+ # Fallback: используем индексы тестовой выборки
1526
  try:
1527
  forecast_dates = s_test_original.index[:len(forecast)]
1528
  except:
1529
+ # Последний вариант - простой числовой индекс
1530
  forecast_dates = range(len(s_train_original), len(s_train_original) + len(forecast))
1531
 
1532
  # Добавляем доверительные интервалы, если они есть
 
1580
  ))
1581
 
1582
  color_idx += 1
1583
+
1584
  # Наивный прогноз (если есть)
1585
  if 'Naive' in all_forecasts:
1586
  naive_forecast_vals = all_forecasts['Naive']
1587
  try:
1588
+ # Правильное создание временных индексов для прогнозов
1589
+ if hasattr(s_train_original.index, 'freq') and s_train_original.index.freq is not None:
1590
+ freq = s_train_original.index.freq
1591
+ else:
1592
+ freq = pd.infer_freq(s_train_original.index) or 'D'
1593
+
1594
+ last_date = s_train_original.index[-1]
1595
  naive_dates = pd.date_range(
1596
+ start=last_date + pd.Timedelta(days=1),
1597
+ periods=len(naive_forecast_vals),
1598
  freq=freq
1599
+ )
1600
  except Exception as e:
1601
  try:
1602
  naive_dates = s_test_original.index[:len(naive_forecast_vals)]
1603
  except:
1604
  naive_dates = range(len(s_train_original), len(s_train_original) + len(naive_forecast_vals))
 
 
 
 
 
 
 
 
1605
 
1606
  # Вертикальная линия, разделяющая train и test
1607
  if len(s_train_original) > 0:
 
1925
  import pandas as pd
1926
  from pathlib import Path
1927
 
1928
+ # -----------------------------
1929
+ # Streamlit: inline pipeline visualizer
1930
+ # -----------------------------
1931
+
1932
+ # inverse helpers (вставь в display_pipeline_inline или в lab3_pipeline)
1933
+ import numpy as _np
1934
+
1935
+ def inverse_boxcox_arr(arr, lmbda):
1936
+ arr = _np.array(arr, dtype=float)
1937
+ if lmbda is None:
1938
+ return arr
1939
+ if abs(lmbda) < 1e-8:
1940
+ return _np.exp(arr)
1941
+ else:
1942
+ return _np.power(lmbda * arr + 1.0, 1.0 / lmbda)
1943
+
1944
+
1945
+ def inverse_transform_preds(preds, meta, orig_series):
1946
+ """
1947
+ Правильное инвертирование преобразований для прогнозов
1948
+ """
1949
+ preds = np.array(preds, dtype=float)
1950
+
1951
+ # Если нет преобразований, возвращаем как есть
1952
+ if meta.get('method') == 'none' and meta.get('diff_order', 0) == 0:
1953
+ return preds
1954
+
1955
+ # Получаем информацию о преобразованиях
1956
+ method = meta.get('method', 'none')
1957
+ lam = meta.get('lambda', None)
1958
+ diff_order = meta.get('diff_order', 0)
1959
+
1960
+ # Шаг 1: Обратное дифференцирование (если было)
1961
+ if diff_order > 0:
1962
+ # Для обратного дифференцирования нужны последние значения исходного ряда
1963
+ orig_values = orig_series.dropna().values
1964
+
1965
+ if len(orig_values) < diff_order:
1966
+ # Недостаточно данных для обратного дифференцирования
1967
+ return preds
1968
+
1969
+ # Простое обратное дифференцирование первого порядка
1970
+ if diff_order == 1:
1971
+ last_value = float(orig_values[-1])
1972
+ reconstructed = []
1973
+ for i, diff_val in enumerate(preds):
1974
+ if i == 0:
1975
+ reconstructed.append(last_value + diff_val)
1976
+ else:
1977
+ reconstructed.append(reconstructed[-1] + diff_val)
1978
+ preds = np.array(reconstructed)
1979
+
1980
+ # Шаг 2: Обратное преобразование Бокса-Кокса или логарифма
1981
+ if method.startswith('boxcox'):
1982
+ if lam is None:
1983
+ lam = 0.0
1984
+ # Обратное преобразование Бокса-Кокса
1985
+ if abs(lam) < 1e-8:
1986
+ preds = np.exp(preds)
1987
+ else:
1988
+ preds = np.power(lam * preds + 1, 1.0 / lam)
1989
+ elif method == 'log':
1990
+ preds = np.exp(preds)
1991
+
1992
+ return preds
1993
+
1994
+
1995
+ def walk_forward_one_step_preds(model_label, model_obj, train_series, test_series, extra=None):
1996
+ """
1997
+ Вернёт numpy array длины len(test_series) с one-step прогнозами.
1998
+ """
1999
+ import numpy as _np
2000
+ preds = []
2001
+ history = train_series.copy() # pd.Series
2002
+
2003
+ for i in range(len(test_series)):
2004
+ try:
2005
+ if model_label == 'sarimax':
2006
+ # Для SARIMAX используем предобученную модель и делаем только прогноз
2007
+ # Не переобучаем модель на каждом шаге
2008
+ if i == 0:
2009
+ # Только на первом шаге используем обученную модель
2010
+ order = model_obj.get('order', (1, 1, 1)) if isinstance(model_obj, dict) else (1, 1, 1)
2011
+ seasonal_order = model_obj.get('seasonal_order', (0, 0, 0, 0)) if isinstance(model_obj, dict) else (
2012
+ 0, 0, 0, 0)
2013
+
2014
+ if len(history.dropna()) < 10:
2015
+ pred_value = float(history.dropna().iloc[-1]) if len(history.dropna()) > 0 else 0.0
2016
+ preds.append(pred_value)
2017
+ history = pd.concat([history, pd.Series([test_series.iloc[i]], index=[test_series.index[i]])])
2018
+ continue
2019
+
2020
+ # Обучаем модель один раз на обучающих данных
2021
+ m = SARIMAX(history.dropna(), order=order, seasonal_order=seasonal_order,
2022
+ enforce_stationarity=False, enforce_invertibility=False)
2023
+ fitted_model = m.fit(disp=False, maxiter=50)
2024
+
2025
+ # Делаем прогноз на один шаг вперед
2026
+ forecast_result = fitted_model.get_forecast(steps=1)
2027
+ pred_value = float(forecast_result.predicted_mean.iloc[0])
2028
+
2029
+ # Проверяем на NaN/Inf
2030
+ if np.isnan(pred_value) or np.isinf(pred_value):
2031
+ pred_value = float(history.dropna().iloc[-1])
2032
+
2033
+ preds.append(pred_value)
2034
+
2035
+ # НЕ добавляем тестовые данные в историю для переобучения
2036
+ # Это предотвращает "подглядывание" в будущее
2037
+ # history остается неизменной после начального обучения
2038
+
2039
+ elif model_label == 'auto_arima':
2040
+ try:
2041
+ # Для auto_arima также обучаем один раз
2042
+ if i == 0:
2043
+ import pmdarima as pm_local
2044
+ if len(history.dropna()) < 10:
2045
+ pred_value = float(history.dropna().iloc[-1])
2046
+ else:
2047
+ auto_model = pm_local.auto_arima(history.dropna(), seasonal=False, error_action='ignore',
2048
+ suppress_warnings=True, maxiter=50)
2049
+
2050
+ if i == 0 or not hasattr(auto_model, 'update'):
2051
+ p = auto_model.predict(n_periods=1)
2052
+ else:
2053
+ # Обновляем модель с новыми данными (если поддерживается)
2054
+ auto_model.update(pd.Series([test_series.iloc[i - 1]]))
2055
+ p = auto_model.predict(n_periods=1)
2056
+
2057
+ pred_value = float(p[0]) if hasattr(p, '__iter__') else float(p)
2058
+
2059
+ # Проверяем на NaN/Inf
2060
+ if np.isnan(pred_value) or np.isinf(pred_value):
2061
+ pred_value = float(history.dropna().iloc[-1])
2062
+
2063
+ preds.append(pred_value)
2064
+ except Exception as e:
2065
+ pred_value = float(history.dropna().iloc[-1]) if len(history.dropna()) > 0 else 0.0
2066
+ preds.append(pred_value)
2067
+
2068
+ elif model_label == 'SES':
2069
+ from statsmodels.tsa.holtwinters import SimpleExpSmoothing
2070
+ try:
2071
+ # Для SES также обучаем один раз
2072
+ if i == 0:
2073
+ if len(history.dropna()) < 2:
2074
+ ses_model = None
2075
+ else:
2076
+ ses_model = SimpleExpSmoothing(history.dropna()).fit(optimized=True)
2077
+
2078
+ if ses_model is None:
2079
+ pred_value = float(history.dropna().iloc[-1])
2080
+ else:
2081
+ p = ses_model.forecast(1)
2082
+ pred_value = float(p.iloc[0]) if hasattr(p, 'iloc') else float(p[0])
2083
+
2084
+ # Проверяем на NaN/Inf
2085
+ if np.isnan(pred_value) or np.isinf(pred_value):
2086
+ pred_value = float(history.dropna().iloc[-1])
2087
+
2088
+ preds.append(pred_value)
2089
+ except Exception as e:
2090
+ pred_value = float(history.dropna().iloc[-1]) if len(history.dropna()) > 0 else 0.0
2091
+ preds.append(pred_value)
2092
+
2093
+ else:
2094
+ # naive: forecast last observed
2095
+ pred_value = float(history.dropna().iloc[-1]) if len(history.dropna()) > 0 else 0.0
2096
+ preds.append(pred_value)
2097
+
2098
+ except Exception as e:
2099
+ # fallback: append last value
2100
+ try:
2101
+ pred_value = float(history.dropna().iloc[-1]) if len(history.dropna()) > 0 else 0.0
2102
+ except:
2103
+ pred_value = 0.0
2104
+ preds.append(pred_value)
2105
+
2106
+ return _np.array(preds, dtype=float)
2107
+
2108
+
2109
+ def display_pipeline_inline(data_path: str, timestamp_col: str, target_col: str, freq: str = 'D'):
2110
+ """
2111
+ Загружает данные через lab3_pipeline helpers и отображает ключевые этапы
2112
+ """
2113
+ import importlib
2114
+ try:
2115
+ import lab3_pipeline as lp
2116
+ importlib.reload(lp)
2117
+ # Определяем PM_AVAILABLE из pipeline
2118
+ PM_AVAILABLE = lp.PM_AVAILABLE
2119
+ STATSMODELS_AVAILABLE = lp.STATSMODELS_AVAILABLE
2120
+ except Exception as e:
2121
+ st.error("Не удалось импортировать lab3_pipeline: " + str(e))
2122
+ return
2123
+
2124
+ st.info("Загружаю данные...")
2125
+ try:
2126
+ df = lp.load_data(data_path, timestamp_col)
2127
+ except Exception as e:
2128
+ st.error("Ошибка загрузки данных: " + str(e))
2129
+ return
2130
+
2131
+ # постараемся получить series
2132
+ if target_col not in df.columns:
2133
+ numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist()
2134
+ if not numeric_cols:
2135
+ st.error("Не найдено числовых колонок для target.")
2136
+ return
2137
+ target_col = numeric_cols[0]
2138
+ st.warning(f"Target не найден — использую {target_col}.")
2139
+
2140
+ series = df[target_col].astype(float).copy()
2141
+
2142
+ # Проверяем данные на наличие NaN и Inf
2143
+ if series.isna().all():
2144
+ st.error("Все значения в целевом ряду NaN. Проверьте данные.")
2145
+ return
2146
+
2147
+ if (series == 0).all():
2148
+ st.warning("Все значения в целевом ряду равны 0. Это может вызвать проблемы с моделями.")
2149
+
2150
+ # Заполняем пропуски простым методом
2151
+ series = series.fillna(method='ffill').fillna(method='bfill').fillna(0)
2152
+
2153
+ st.write("Исходный ряд — первые и последние точки:")
2154
+ st.write(pd.concat([series.head(5), series.tail(5)]).to_frame(target_col))
2155
+
2156
+ # ресемплим/интерполируем
2157
+ try:
2158
+ series_rs = lp.resample_and_interpolate(series.to_frame(), freq=freq).iloc[:, 0]
2159
+ # Снова проверяем и заполняем пропуски после ресемплинга
2160
+ series_rs = series_rs.fillna(method='ffill').fillna(method='bfill').fillna(0)
2161
+ except Exception as e:
2162
+ st.warning("Resample/interpolate failed, using original: " + str(e))
2163
+ series_rs = series
2164
+
2165
+ st.subheader("1) Временной ряд")
2166
+ fig, ax = plt.subplots(figsize=(10,3))
2167
+ ax.plot(series_rs.index, series_rs.values, label='series')
2168
+ ax.set_title("Временной ряд (после ресемплинга)")
2169
+ ax.legend()
2170
+ st.pyplot(fig)
2171
+
2172
+ # 3.1: transformations selection
2173
+ st.subheader("2) Подбор преобразований (log / Box-Cox / differencing)")
2174
+ try:
2175
+ transformed, meta = lp.try_transformations_and_choose(series_rs, seasonal_period=7)
2176
+ st.write("Выбранное преобразование:", meta)
2177
+ except Exception as e:
2178
+ st.warning("Не удалось выполнить подбор преобразований: " + str(e))
2179
+ transformed, meta = series_rs, {'method': 'none'}
2180
+
2181
+ # Покажем original vs transformed
2182
+ fig, ax = plt.subplots(1,1,figsize=(10,3))
2183
+ ax.plot(series_rs.index[-200:], series_rs.values[-200:], label='original')
2184
+ ax.plot(transformed.index[-200:], transformed.values[-200:], label='transformed')
2185
+ ax.set_title("Original vs Transformed (последние 200 точек)")
2186
+ ax.legend()
2187
+ st.pyplot(fig)
2188
+
2189
+ # stationarity tests
2190
+ st.subheader("3) Тесты на стационарность (ADF, KPSS)")
2191
+ try:
2192
+ tests_orig = lp.test_stationarity_pair(series_rs.fillna(method='ffill'))
2193
+ tests_trans = lp.test_stationarity_pair(transformed.fillna(method='ffill'))
2194
+ st.write("Оригинал:", tests_orig)
2195
+ st.write("Преобразованный ряд:", tests_trans)
2196
+ except Exception as e:
2197
+ st.warning("Тесты стационарности не выполнены: " + str(e))
2198
+
2199
+ # decomposition
2200
+ st.subheader("4) Декомпозиция ряда (additive)")
2201
+ try:
2202
+ if lp.STATSMODELS_AVAILABLE:
2203
+ dec = lp.seasonal_decompose(transformed.dropna(), model='additive', period=7)
2204
+ fig = dec.plot()
2205
+ fig.set_size_inches(10,6)
2206
+ st.pyplot(fig)
2207
+ else:
2208
+ st.info("statsmodels не доступен: декомпозиция пропущена.")
2209
+ except Exception as e:
2210
+ st.warning("Ошибка декомпозиции: " + str(e))
2211
+
2212
+ # ACF/PACF
2213
+ st.subheader("5) ACF / PACF")
2214
+ try:
2215
+ if lp.STATSMODELS_AVAILABLE:
2216
+ from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
2217
+
2218
+ ser_ac = transformed.dropna()
2219
+ if len(ser_ac) < 3:
2220
+ st.info("Недостаточно точек для ACF/PACF (нужно >=3).")
2221
+ else:
2222
+ # ACF
2223
+ fig_acf, ax_acf = plt.subplots(figsize=(10, 3))
2224
+ plot_acf(ser_ac, lags=40, ax=ax_acf, zero=False)
2225
+ ax_acf.set_title("ACF")
2226
+ st.pyplot(fig_acf)
2227
+ plt.close(fig_acf)
2228
+
2229
+ # PACF
2230
+ fig_pacf, ax_pacf = plt.subplots(figsize=(10, 3))
2231
+ # метод pacf можно изменить в зависимости от версии statsmodels ('ywm', 'ld', 'ols', ...)
2232
+ try:
2233
+ plot_pacf(ser_ac, lags=40, ax=ax_pacf, zero=False, method='ywm')
2234
+ except Exception:
2235
+ plot_pacf(ser_ac, lags=40, ax=ax_pacf, zero=False)
2236
+ ax_pacf.set_title("PACF")
2237
+ st.pyplot(fig_pacf)
2238
+ plt.close(fig_pacf)
2239
+ else:
2240
+ st.info("statsmodels не доступен — ACF/PACF пропущены.")
2241
+ except Exception as e:
2242
+ st.warning("ACF/PACF error: " + str(e))
2243
+
2244
+ # 3.2 feature engineering demonstration
2245
+ st.subheader("6) Feature engineering (лаги, скользящие, временные признаки)")
2246
+ try:
2247
+ df_all = transformed.to_frame(name=target_col)
2248
+ df_all = lp.make_time_features(df_all)
2249
+ df_all = lp.make_lags(df_all, target_col, [1,2,7,30])
2250
+ df_all = lp.make_rolls(df_all, target_col, [7,30])
2251
+ st.write("Превью признаков:")
2252
+ st.dataframe(df_all.dropna().head(10))
2253
+ except Exception as e:
2254
+ st.warning("Ошибка при генерации признаков: " + str(e))
2255
+
2256
+ # split
2257
+ st.subheader("7) Разбиение train/val/test")
2258
+ try:
2259
+ df_all = df_all.dropna()
2260
+ train, val, test = lp.chronological_split(df_all, frac_train=0.7, frac_val=0)
2261
+ st.write("Размеры:", {'train': len(train), 'val': len(val), 'test': len(test)})
2262
+ except Exception as e:
2263
+ st.warning("Ошибка разбиения: " + str(e))
2264
+ return
2265
+
2266
+ # 3.3-3.5 Модели: несколько базовых (быстро и наглядно)
2267
+ st.subheader("8) Быстрое обучение моделей и прогнозы (h=1,7,30)")
2268
+ horizons = [1,7,30]
2269
+ results = []
2270
+ # benchmarks
2271
+ for h in horizons:
2272
+ try:
2273
+ results.append({'model':'naive','h':h,'pred': lp.naive_forecast(train[target_col], h)})
2274
+ if len(train[target_col])>=7:
2275
+ results.append({'model':'seasonal_naive','h':h, 'pred': lp.seasonal_naive_forecast(train[target_col], season=7, steps=h)})
2276
+ except Exception:
2277
+ pass
2278
+
2279
+ # SES (если доступен)
2280
+ try:
2281
+ from statsmodels.tsa.holtwinters import SimpleExpSmoothing
2282
+ ses = SimpleExpSmoothing(train[target_col].dropna()).fit(optimized=True)
2283
+ for h in horizons:
2284
+ results.append({'model':'SES','h':h,'pred': np.asarray(ses.forecast(h))})
2285
+ except Exception:
2286
+ pass
2287
+
2288
+ # SARIMAX baseline
2289
+ try:
2290
+ sar = lp.fit_sarimax_simple(train[target_col], order=(1,1,1))
2291
+ for h in horizons:
2292
+ p, ci = lp.forecast_sarimax(sar, steps=h)
2293
+ results.append({'model':'SARIMAX(1,1,1)','h':h,'pred': np.asarray(p), 'ci': ci})
2294
+ except Exception as e:
2295
+ st.warning("SARIMAX skipped: " + str(e))
2296
+
2297
+ # pmdarima auto_arima
2298
+ try:
2299
+ if PM_AVAILABLE: # Теперь эта переменная определена
2300
+ auto = lp.fit_auto_arima(train[target_col], seasonal=False)
2301
+ for h in horizons:
2302
+ results.append({'model':'auto_arima','h':h,'pred': np.asarray(auto.predict(n_periods=h))})
2303
+ except Exception:
2304
+ pass
2305
+
2306
+ # VAR if multivariate
2307
+ try:
2308
+ if lp.STATSMODELS_AVAILABLE and df.select_dtypes(include=[np.number]).shape[1] >= 2:
2309
+ num_df = df.select_dtypes(include=[np.number]).dropna()
2310
+ var_res = lp.fit_var(num_df.iloc[:int(len(num_df)*0.7)], maxlags=5)
2311
+ fut = lp.forecast_var(var_res, steps=30)
2312
+ results.append({'model':'VAR','h':30,'pred': np.asarray(fut.iloc[:,0])})
2313
+ except Exception:
2314
+ pass
2315
+
2316
+ # Evaluate models on test
2317
+ st.subheader("9) Оценка моделей на тесте")
2318
+ eval_rows = []
2319
+ for rec in results:
2320
+ pred = np.asarray(rec['pred']).ravel()
2321
+ y_true = test[target_col].values[:len(pred)]
2322
+ if len(y_true)==0:
2323
+ continue
2324
+ row = {
2325
+ 'model': rec['model'],
2326
+ 'h': rec['h'],
2327
+ 'MAE': float(lp.mae(y_true, pred)),
2328
+ 'RMSE': float(lp.rmse(y_true, pred)),
2329
+ 'MAPE': float(lp.mape(y_true, pred))
2330
+ }
2331
+ eval_rows.append(row)
2332
+ if eval_rows:
2333
+ eval_df = pd.DataFrame(eval_rows)
2334
+ st.dataframe(eval_df.sort_values(['h','RMSE']))
2335
+ else:
2336
+ st.info("Нет результатов для оценки.")
2337
+
2338
+ # Получим walk-forward прогнозы для каждого обученного метода (если модель была навчена)
2339
+ # Получим walk-forward прогнозы для каждого обученного метода
2340
+ st.subheader("10) Полная визуализация прогнозов по тесту (walk-forward one-step)")
2341
+
2342
+ # выберем модели, которые были обучены
2343
+ for rec in results:
2344
+ model_name = rec['model']
2345
+ # только те, для которых хотим full series
2346
+ if model_name not in ('SARIMAX(1,1,1)', 'auto_arima', 'SES', 'naive', 'seasonal_naive'):
2347
+ continue
2348
+ st.write("Обрабатываем модель:", model_name)
2349
+
2350
+ # Подготавливаем параметры модели для walk_forward
2351
+ model_args = {}
2352
+ if model_name.startswith('SARIMAX'):
2353
+ model_args = {'order': (1, 1, 1), 'seasonal_order': (0, 0, 0, 0)}
2354
+ model_type = 'sarimax'
2355
+ elif model_name == 'auto_arima' and PM_AVAILABLE:
2356
+ model_type = 'auto_arima'
2357
+ elif model_name == 'SES':
2358
+ model_type = 'SES'
2359
+ elif model_name == 'naive':
2360
+ model_type = 'naive'
2361
+ elif model_name == 'seasonal_naive':
2362
+ model_type = 'naive' # используем naive как fallback
2363
+ else:
2364
+ continue
2365
+
2366
+ # вызов walk_forward для этой модели
2367
+ try:
2368
+ full_preds = walk_forward_one_step_preds(model_type, model_args, train[target_col], test[target_col])
2369
+
2370
+ # Отладочная информация
2371
+ st.write(f"Длина прогнозов: {len(full_preds)}")
2372
+ st.write(f"Количество NaN в прогнозах: {np.isnan(full_preds).sum()}")
2373
+
2374
+ if len(full_preds) > 0 and not np.all(np.isnan(full_preds)):
2375
+ st.write("Пример первых 5 raw preds:", full_preds[:5].tolist())
2376
+
2377
+ # инвертируем трансформации, если они были
2378
+ try:
2379
+ preds_inv = inverse_transform_preds(full_preds, meta, series_rs)
2380
+ st.write("Пример первых 5 инвертированных preds:", preds_inv[:5].tolist())
2381
+ except Exception as e:
2382
+ st.warning(f"inverse_transform failed: {e}")
2383
+ preds_inv = full_preds
2384
+
2385
+ # отрисуем
2386
+ fig, ax = plt.subplots(figsize=(12, 4))
2387
+
2388
+ # history (последние 100 точек для наглядности)
2389
+ hist_points = min(100, len(train))
2390
+ ax.plot(train.index[-hist_points:], train[target_col].values[-hist_points:],
2391
+ label='train (tail)', linewidth=2)
2392
+
2393
+ # test
2394
+ test_to_show = min(len(test), len(full_preds))
2395
+ ax.plot(test.index[:test_to_show], test[target_col].values[:test_to_show],
2396
+ label='test', linewidth=2, alpha=0.7)
2397
+
2398
+ # preds
2399
+ try:
2400
+ ax.plot(test.index[:len(preds_inv)], preds_inv,
2401
+ label=f'pred_{model_name}', linewidth=2, linestyle='--')
2402
+ except Exception as e:
2403
+ ax.plot(range(len(preds_inv)), preds_inv,
2404
+ label=f'pred_{model_name}', linewidth=2, linestyle='--')
2405
+
2406
+ ax.set_title(f'Walk-forward one-step forecasts — {model_name}')
2407
+ ax.legend()
2408
+ ax.grid(True, alpha=0.3)
2409
+ st.pyplot(fig)
2410
+ plt.close(fig)
2411
+
2412
+ # Вычислим метрики качества
2413
+ if len(preds_inv) > 0 and len(test) >= len(preds_inv):
2414
+ y_true = test[target_col].values[:len(preds_inv)]
2415
+ y_pred = preds_inv
2416
+
2417
+ mae_val = np.mean(np.abs(y_true - y_pred))
2418
+ rmse_val = np.sqrt(np.mean((y_true - y_pred) ** 2))
2419
+
2420
+ st.write(f"**Метрики качества для {model_name}:**")
2421
+ st.write(f"- MAE: {mae_val:.4f}")
2422
+ st.write(f"- RMSE: {rmse_val:.4f}")
2423
+
2424
+ else:
2425
+ st.warning(f"Модель {model_name} вернула все NaN прогнозы")
2426
+
2427
+ except Exception as e:
2428
+ st.warning(f"Не удалось посчитать full_preds для {model_name}: {e}")
2429
+ continue
2430
+
2431
+ # Диагностика остатков для SARIMAX (если обучен)
2432
+ st.subheader("11) Диагностика остатков (SARIMAX если есть)")
2433
+ try:
2434
+ if 'sar' in locals():
2435
+ resid = sar.resid.dropna()
2436
+ fig, ax = plt.subplots(figsize=(10,3))
2437
+ ax.plot(resid); ax.set_title("Residuals")
2438
+ st.pyplot(fig)
2439
+ # Ljung-Box
2440
+ try:
2441
+ lb = lp.ljung_box_test(resid, lags=[10])
2442
+ st.write("Ljung-Box (lag=10):")
2443
+ st.dataframe(lb)
2444
+ except Exception:
2445
+ st.info("acorr_ljungbox недоступен")
2446
+ # Shapiro
2447
+ try:
2448
+ sh = lp.shapiro_test(resid)
2449
+ st.write("Shapiro test:", sh)
2450
+ except Exception:
2451
+ st.info("scipy/shapiro недоступен")
2452
+ else:
2453
+ st.info("SARIMAX модель не была обучена — диагностика пропущена.")
2454
+ except Exception as e:
2455
+ st.warning("Error in residual diagnostics: " + str(e))
2456
+
2457
+ # опционально: создать и предложить скачать HTML-отчёт
2458
+ st.subheader("12) Сгенерировать HTML-отчёт")
2459
+ try:
2460
+ if st.button("Сохранить HTML-отчёт (lab3_report.html)"):
2461
+ out_report = "lab3_report.html"
2462
+ lp.generate_report_html(out_report, plots=[], tables={'evaluation': pd.DataFrame(eval_rows)})
2463
+ st.success("Отчёт сохранён: " + out_report)
2464
+ try:
2465
+ with open(out_report, 'r', encoding='utf-8') as f:
2466
+ html = f.read()
2467
+ st.components.v1.html(html, height=600, scrolling=True)
2468
+ except Exception:
2469
+ st.info("Отчёт создан, но не удалось отобразить его в Streamlit.")
2470
+ except Exception:
2471
+ pass
2472
+
2473
+ st.success("Inline pipeline выполнен.")
2474
+
2475
+
2476
  def render_lab3():
2477
  st.title("🧪 ЛР №3: Сравнительный анализ классических моделей")
2478
 
 
2715
  out_report = st.text_input("Путь для отчёта (HTML)", "./lab3_report.html")
2716
  freq = st.selectbox("Частота ресемплинга", ['D','W','M'])
2717
 
2718
+ if st.button("Запустить полный pipeline и сформировать отчёт (и показать результаты)"):
2719
+ tmp = "./_lab3_input_tmp.csv"
2720
+ df.to_csv(tmp, index=False)
2721
+ display_pipeline_inline(tmp, timestamp_col='timestamp', target_col=target, freq=freq)
2722
+
2723
  tmp = "./_lab3_input_tmp.csv"
2724
  # сохраняем df с колонкой timestamp
2725
  df.to_csv(tmp, index=False)
src/streamlit_lab3.py DELETED
@@ -1,50 +0,0 @@
1
- """
2
- streamlit_lab3.py
3
- Упрощённый Streamlit-интерфейс для ЛР №3.
4
- Позволяет загрузить CSV/Parquet, настроить параметры и запустить pipeline (lab3_pipeline.run_pipeline).
5
- """
6
-
7
- import streamlit as st
8
- import os
9
- import pandas as pd
10
- import tempfile
11
- from pathlib import Path
12
-
13
- # импортируем наш pipeline (если он в PATH)
14
- try:
15
- from lab3_pipeline import run_pipeline
16
- PIPELINE_AVAILABLE = True
17
- except Exception as e:
18
- PIPELINE_AVAILABLE = False
19
- st = None
20
-
21
- def main():
22
- st.title('ЛР №3 — Временные ряды (pipeline)')
23
- uploaded = st.file_uploader("Загрузите CSV/Parquet с колонкой timestamp и target", type=['csv','parquet'])
24
- if uploaded is None:
25
- st.info("Загрузите файл, или введите путь к локальному файлу на сервере.")
26
- else:
27
- with tempfile.NamedTemporaryFile(delete=False, suffix=Path(uploaded.name).suffix) as tmp:
28
- tmp.write(uploaded.getbuffer())
29
- tmp_path = tmp.name
30
- st.write("Файл загружен:", tmp_path)
31
- timestamp = st.text_input("Имя колонки с временной меткой", "timestamp")
32
- target = st.text_input("Имя колонки с целевой переменной", "target")
33
- freq = st.selectbox("Частота ресемплинга", ['D','W','M'])
34
- outpath = './lab3_report.html'
35
- if st.button("Запустить ЛР3"):
36
- st.info("Запуск pipeline — может занять время. Выходной файл: " + outpath)
37
- try:
38
- run_pipeline(tmp_path, timestamp, target, out_report=outpath, freq=freq)
39
- with open(outpath, 'r', encoding='utf-8') as f:
40
- html = f.read()
41
- st.markdown("### Отчёт")
42
- st.components.v1.html(html, height=800, scrolling=True)
43
- except Exception as e:
44
- st.error("Ошибка при выполнении pipeline: " + str(e))
45
-
46
- if __name__ == '__main__':
47
- if PIPELINE_AVAILABLE:
48
- main()
49
- else:
50
- print("lab3_pipeline недоступен. Положите lab3_pipeline.py в PYTHONPATH или /mnt/data")