tspoon 0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tspoon-0.1/PKG-INFO +3 -0
- tspoon-0.1/setup.cfg +4 -0
- tspoon-0.1/setup.py +20 -0
- tspoon-0.1/tspoon/__init__.py +1 -0
- tspoon-0.1/tspoon/main.py +770 -0
- tspoon-0.1/tspoon.egg-info/PKG-INFO +3 -0
- tspoon-0.1/tspoon.egg-info/SOURCES.txt +7 -0
- tspoon-0.1/tspoon.egg-info/dependency_links.txt +1 -0
- tspoon-0.1/tspoon.egg-info/top_level.txt +1 -0
tspoon-0.1/PKG-INFO
ADDED
tspoon-0.1/setup.cfg
ADDED
tspoon-0.1/setup.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name='tspoon',
|
|
5
|
+
version='0.1',
|
|
6
|
+
packages=find_packages(),
|
|
7
|
+
install_requires=[
|
|
8
|
+
# 'os',
|
|
9
|
+
# 'time',
|
|
10
|
+
# 'sys',
|
|
11
|
+
# 'pickle',
|
|
12
|
+
# 'pandas',
|
|
13
|
+
# 'numpy',
|
|
14
|
+
# 'regex',
|
|
15
|
+
# 'datetime',
|
|
16
|
+
# 'matplotlib',
|
|
17
|
+
# 'statsmodels',
|
|
18
|
+
# 'copy'
|
|
19
|
+
]
|
|
20
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .main import *
|
|
@@ -0,0 +1,770 @@
|
|
|
1
|
+
########################################################################################
|
|
2
|
+
#
|
|
3
|
+
# Utility fuctions - Date, Text, Time-series, Plotting
|
|
4
|
+
# Created by Beomseok Seo 2023.01.01
|
|
5
|
+
# Modified by Beomseok Seo 2024.01.01
|
|
6
|
+
#
|
|
7
|
+
########################################################################################
|
|
8
|
+
|
|
9
|
+
import os, time, sys
|
|
10
|
+
import pickle
|
|
11
|
+
import pandas as pd
|
|
12
|
+
import numpy as np
|
|
13
|
+
import regex as re
|
|
14
|
+
import datetime as dt
|
|
15
|
+
from dateutil.relativedelta import relativedelta
|
|
16
|
+
|
|
17
|
+
import matplotlib.pyplot as plt
|
|
18
|
+
import statsmodels.api as sm
|
|
19
|
+
import copy
|
|
20
|
+
|
|
21
|
+
from statsmodels.tsa.filters.hp_filter import hpfilter
|
|
22
|
+
from statsmodels.tsa.x13 import x13_arima_analysis
|
|
23
|
+
from statsmodels.tsa.ar_model import AutoReg
|
|
24
|
+
|
|
25
|
+
#date functions
|
|
26
|
+
|
|
27
|
+
def firstdate(Y,m):
|
|
28
|
+
return dt.date(int(Y),int(m),1).strftime('%Y-%m-%d')
|
|
29
|
+
|
|
30
|
+
def lastdate(Y,m):
|
|
31
|
+
return (dt.date(int(Y),int(m),1)+relativedelta(months=1)-dt.timedelta(days=1)).strftime('%Y-%m-%d')
|
|
32
|
+
|
|
33
|
+
def datesbetween(startdate, enddate):
|
|
34
|
+
start_dt = dt.datetime.strptime(startdate,'%Y-%m-%d')
|
|
35
|
+
end_dt = dt.datetime.strptime(enddate,'%Y-%m-%d')
|
|
36
|
+
delta = dt.timedelta(days=1)
|
|
37
|
+
|
|
38
|
+
dates = []
|
|
39
|
+
|
|
40
|
+
while start_dt <= end_dt:
|
|
41
|
+
dates.append(start_dt.strftime('%Y-%m-%d'))
|
|
42
|
+
start_dt += delta
|
|
43
|
+
|
|
44
|
+
return dates
|
|
45
|
+
|
|
46
|
+
def daytrans(basedate):
|
|
47
|
+
return dt.date(int(basedate[:4]),int(basedate[4:6]),int(basedate[6:])).strftime('%Y-%m-%d')
|
|
48
|
+
|
|
49
|
+
def timetrans(basedate):
|
|
50
|
+
return dt.time(int(basedate[:2]),int(basedate[2:4]),int(basedate[4:])).strftime('%H:%M:%S')
|
|
51
|
+
|
|
52
|
+
def dayahead(basedate,dayahead):
|
|
53
|
+
if len(basedate) == 8:
|
|
54
|
+
return (dt.date(int(basedate[:4]),int(basedate[4:6]),int(basedate[6:]))-dt.timedelta(dayahead)).strftime('%Y%m%d')
|
|
55
|
+
elif len(basedate) == 10:
|
|
56
|
+
return (dt.date(int(basedate[:4]),int(basedate[5:7]),int(basedate[8:]))-dt.timedelta(dayahead)).strftime('%Y-%m-%d')
|
|
57
|
+
|
|
58
|
+
def dateexp(basedate):
|
|
59
|
+
return dt.date(int(basedate[:4]),int(basedate[5:7]),int(basedate[8:])).strftime('%Y.%m.%d')
|
|
60
|
+
|
|
61
|
+
def dayafter(basedate,dayahead):
|
|
62
|
+
return (dt.date(int(basedate[:4]),int(basedate[4:6]),int(basedate[6:]))+dt.timedelta(dayahead)).strftime('%Y%m%d')
|
|
63
|
+
|
|
64
|
+
def day2week(x, dformat='yyyy-mm-dd'):
|
|
65
|
+
if dformat=='yyyy-mm-dd':
|
|
66
|
+
isodate = dt.date(int(x[0:4]), int(x[5:7]), int(x[8:10])).isocalendar()
|
|
67
|
+
elif dformat=='yyyymmdd':
|
|
68
|
+
isodate = dt.date(int(x[0:4]), int(x[4:6]), int(x[6:8])).isocalendar()
|
|
69
|
+
return(str(isodate[0]*100+isodate[1]))
|
|
70
|
+
|
|
71
|
+
def day2month(x, dformat='yyyy-mm-dd'):
|
|
72
|
+
if dformat=='yyyy-mm-dd':
|
|
73
|
+
md = str(x)[0:4]+str(x)[5:7]
|
|
74
|
+
elif dformat=='yyyymmdd':
|
|
75
|
+
md = str(x)[0:4]+str(x)[4:6]
|
|
76
|
+
return(md)
|
|
77
|
+
|
|
78
|
+
def day2year(x):
|
|
79
|
+
yd = str(x)[0:4]
|
|
80
|
+
return(yd)
|
|
81
|
+
|
|
82
|
+
def month2quarter(x):
|
|
83
|
+
if str(x)[-2:] in ['01','02','03']:
|
|
84
|
+
qq = 'q1'
|
|
85
|
+
elif str(x)[-2:] in ['04','05','06']:
|
|
86
|
+
qq = 'q2'
|
|
87
|
+
elif str(x)[-2:] in ['07','08','09']:
|
|
88
|
+
qq = 'q3'
|
|
89
|
+
elif str(x)[-2:] in ['10','11','12']:
|
|
90
|
+
qq = 'q4'
|
|
91
|
+
mq = str(x)[:4]+qq
|
|
92
|
+
return(mq)
|
|
93
|
+
|
|
94
|
+
def quarter2month(x):
|
|
95
|
+
if str(x)[-2:] == 'q1':
|
|
96
|
+
mm = '03'
|
|
97
|
+
elif str(x)[-2:] == 'q2':
|
|
98
|
+
mm = '06'
|
|
99
|
+
elif str(x)[-2:] == 'q3':
|
|
100
|
+
mm = '09'
|
|
101
|
+
elif str(x)[-2:] == 'q4':
|
|
102
|
+
mm = '12'
|
|
103
|
+
mq = str(x)[:4]+mm
|
|
104
|
+
return(mq)
|
|
105
|
+
|
|
106
|
+
def week2day(x):
|
|
107
|
+
if (sys.version.split(' ')[0])>='3.8':
|
|
108
|
+
wd = dt.date.fromisocalendar(int(str(x)[0:4]), int(str(x)[5:7]), 1)
|
|
109
|
+
else:
|
|
110
|
+
wd = dt.datetime.strptime(str(x)[0:4]+'-W'+str(x)[4:6]+'-'+str(1), "%Y-W%W-%w")
|
|
111
|
+
return(wd.strftime('%Y-%m-%d'))
|
|
112
|
+
|
|
113
|
+
def month2day(x, day='first', dformat='yyyy-mm-dd'):
|
|
114
|
+
if day=='first':
|
|
115
|
+
md = dt.date(int(str(x)[0:4]),int(str(x)[4:6]),1)
|
|
116
|
+
elif day=='last':
|
|
117
|
+
md = dt.date(int(str(x)[0:4]),int(str(x)[4:6])+1,1)-dt.timedelta(dayahead)
|
|
118
|
+
if dformat=='yyyy-mm-dd':
|
|
119
|
+
return(md.strftime('%Y-%m-%d'))
|
|
120
|
+
elif dformat=='yyyymmdd':
|
|
121
|
+
return(md.strftime('%Y%m%d'))
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def backwardMovingAverage(TS, lag_day=14, dd=None, todf=False):
|
|
125
|
+
if todf is True:
|
|
126
|
+
val = [np.mean(TS[i-lag_day+1:i+1]) for i in range(lag_day,len(TS))]
|
|
127
|
+
df = pd.DataFrame(val, index = TS.index[lag_day:])
|
|
128
|
+
return(df, None)
|
|
129
|
+
else:
|
|
130
|
+
return([np.mean(TS[i-lag_day+1:i+1]) for i in range(lag_day,len(TS))], dd[lag_day:])
|
|
131
|
+
|
|
132
|
+
def bMA(TS, lag_day=14, dd=None, todf=False):
|
|
133
|
+
if todf is True:
|
|
134
|
+
val = [np.mean(TS[i-lag_day+1:i+1]) for i in range(lag_day,len(TS))]
|
|
135
|
+
df = pd.DataFrame(val, index = TS.index[lag_day:])
|
|
136
|
+
return(df)
|
|
137
|
+
else:
|
|
138
|
+
return([np.mean(TS[i-lag_day+1:i+1]) for i in range(lag_day,len(TS))])
|
|
139
|
+
|
|
140
|
+
def cMA(TS, lag_day=14, lead_day=14, dd=None, todf=False):
|
|
141
|
+
if todf is True:
|
|
142
|
+
val = [np.mean(TS[i-lag_day+1:i+lead_day]) for i in range(lag_day,len(TS)-lead_day)]
|
|
143
|
+
df = pd.DataFrame(val, index = TS.index[lag_day:len(TS)-lead_day])
|
|
144
|
+
return(df)
|
|
145
|
+
else:
|
|
146
|
+
return([np.mean(TS[i-lag_day+1:i+1]) for i in range(lag_day,len(TS))])
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def cutTimeSeries(TS,DTS, START_DAY='2020-01-01'):
|
|
150
|
+
dd_ = [dt.date(int(i[0:4]),int(i[5:7]),int(i[8:10])) for i in DTS]
|
|
151
|
+
dd_ = [i>dt.date(int(START_DAY[0:4]),int(START_DAY[5:7]),int(START_DAY[8:10])) for i in dd_]
|
|
152
|
+
return(np.array(TS)[dd_],np.array(DTS)[dd_])
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def yoy(dat, period=12, smooth=None):
|
|
157
|
+
if smooth is not None:
|
|
158
|
+
base = cMA(dat, lag_day=smooth[0], lead_day=smooth[1], todf=True).shift(period)
|
|
159
|
+
return (dat/base*100-100).iloc[period:]
|
|
160
|
+
else:
|
|
161
|
+
return (dat/dat.shift(period)*100-100).iloc[period:]
|
|
162
|
+
|
|
163
|
+
def mom(dat, period=1):
|
|
164
|
+
return (dat/dat.shift(period)*100-100).iloc[period:]
|
|
165
|
+
|
|
166
|
+
def unyoy(dat_yoy, dat_level, period=52, smooth=None, max_iter=3, backward=False, backward_beginning_index=None):
|
|
167
|
+
if smooth is not None:
|
|
168
|
+
base = cMA(dat_level, lag_day=smooth[0], lead_day=smooth[1], todf=True).squeeze()
|
|
169
|
+
else:
|
|
170
|
+
base = dat_level
|
|
171
|
+
|
|
172
|
+
flag_f = dat_yoy.index == base.dropna().index[-1]
|
|
173
|
+
if np.any(flag_f):
|
|
174
|
+
base = pd.concat([base.loc[:base.dropna().index[-1]],pd.Series(np.nan, index=dat_yoy.index[np.where(flag_f)[0][0]+1:])])
|
|
175
|
+
|
|
176
|
+
k = dat_yoy.dropna().index[-1]
|
|
177
|
+
|
|
178
|
+
pred_level = ((dat_yoy+100)/100*base.shift(period))
|
|
179
|
+
|
|
180
|
+
i=1
|
|
181
|
+
while np.isnan(pred_level.loc[k]):
|
|
182
|
+
flag = pred_level.index == base.dropna().index[-1]
|
|
183
|
+
base = pd.concat([base.loc[:base.dropna().index[-1]], pred_level.iloc[np.where(flag)[0][0]+1:]])
|
|
184
|
+
pred_level = ((dat_yoy+100)/100*base.shift(period))
|
|
185
|
+
i+=1
|
|
186
|
+
if i >max_iter:
|
|
187
|
+
raise Exception("Something is wrong in the iteration of computing pred_level!")\
|
|
188
|
+
|
|
189
|
+
pred_level[base.index[:period]] = base.iloc[:period]
|
|
190
|
+
|
|
191
|
+
if backward:
|
|
192
|
+
flag_b = dat_yoy.index == base.dropna().index[0]
|
|
193
|
+
|
|
194
|
+
if np.any(flag_b):
|
|
195
|
+
base = pd.concat([pd.Series(np.nan, index=dat_yoy.index[:np.where(flag_b)[0][0]]), base.loc[base.dropna().index[0]:]])
|
|
196
|
+
|
|
197
|
+
k = dat_yoy.dropna().index[0]
|
|
198
|
+
|
|
199
|
+
if backward_beginning_index is not None:
|
|
200
|
+
pred_level = pd.concat([pd.Series(np.nan, index=backward_beginning_index), pred_level])
|
|
201
|
+
dat_yoy = pd.concat([pd.Series(np.nan, index=backward_beginning_index), dat_yoy])
|
|
202
|
+
base = pd.concat([pd.Series(np.nan, index=backward_beginning_index), base])
|
|
203
|
+
flag_b = list([False for i in range(len(backward_beginning_index))]) + list(flag_b)
|
|
204
|
+
|
|
205
|
+
if dat_yoy.dropna().index[0] == dat_yoy.index[0]:
|
|
206
|
+
k = backward_beginning_index[0]
|
|
207
|
+
else:
|
|
208
|
+
k = dat_yoy.index[max(0,np.where(dat_yoy.index==dat_yoy.dropna().index[0])[0][0]-period)]
|
|
209
|
+
|
|
210
|
+
pred_level_back = (base/((dat_yoy+100)/100)).shift(-period)
|
|
211
|
+
|
|
212
|
+
i=1
|
|
213
|
+
while np.isnan(pred_level_back.loc[k]):
|
|
214
|
+
flag = pred_level_back.index == base.dropna().index[0]
|
|
215
|
+
base = pd.concat([pred_level_back.iloc[:np.where(flag)[0][0]], base.loc[base.dropna().index[0]:]])
|
|
216
|
+
pred_level_back = (base/((dat_yoy+100)/100)).shift(-period)
|
|
217
|
+
i+=1
|
|
218
|
+
if i >max_iter:
|
|
219
|
+
raise Exception("Something is wrong in the iteration of computing pred_level!")
|
|
220
|
+
|
|
221
|
+
pred_level[dat_yoy.index[:np.where(flag_b)[0][0]]] = pred_level_back.loc[dat_yoy.index[:np.where(flag_b)[0][0]]]
|
|
222
|
+
|
|
223
|
+
return pred_level
|
|
224
|
+
|
|
225
|
+
def naoutlier(df, quantile=0.99):
|
|
226
|
+
q = df.quantile(quantile)
|
|
227
|
+
return df[df < q]
|
|
228
|
+
|
|
229
|
+
# dataframe function
|
|
230
|
+
|
|
231
|
+
def GenDf_w2m(df_w, aggregate='last'):
|
|
232
|
+
df_wm = copy.deepcopy(df_w)
|
|
233
|
+
df_wm.index = [day2month(week2day(x)) for x in df_wm.index]
|
|
234
|
+
df_wm.index.name = 'index'
|
|
235
|
+
if aggregate=='last':
|
|
236
|
+
df_m = df_wm[~df_wm.index.duplicated(keep='last')]
|
|
237
|
+
if aggregate=='mean':
|
|
238
|
+
df_m = df_wm.groupby('index').mean()
|
|
239
|
+
elif aggregate=='max':
|
|
240
|
+
df_m = df_wm.groupby('index').max()
|
|
241
|
+
elif aggregate=='median':
|
|
242
|
+
df_m = df_wm.groupby('index').median()
|
|
243
|
+
return df_m
|
|
244
|
+
|
|
245
|
+
def GenDf_m2w(df_w,df_m,interpolate='linear'):
|
|
246
|
+
|
|
247
|
+
if df_w is None:
|
|
248
|
+
|
|
249
|
+
firstmon = df_m.index[0]
|
|
250
|
+
lastmon = df_m.index[-1]
|
|
251
|
+
|
|
252
|
+
start_dt = firstdate(firstmon[:4],firstmon[4:])
|
|
253
|
+
end_dt = lastdate(lastmon[:4],lastmon[4:])
|
|
254
|
+
|
|
255
|
+
weeks = uniq([day2week(x) for x in datesbetween(start_dt, end_dt)])
|
|
256
|
+
df_w = pd.DataFrame(index=weeks)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
df_mw = pd.DataFrame(index = [day2month(week2day(x)) for x in df_w.index], columns = df_m.columns)
|
|
260
|
+
df_mw_index = np.array([int(x) for x in df_mw.index])
|
|
261
|
+
month_loc = np.where([x>0 for x in df_mw_index[1:] - df_mw_index[:-1]]+[True])[0]
|
|
262
|
+
df_mw.index = df_w.index
|
|
263
|
+
|
|
264
|
+
try:
|
|
265
|
+
df_mw.iloc[month_loc] = df_m.loc[[str(x) for x in df_mw_index[month_loc]],:]
|
|
266
|
+
except:
|
|
267
|
+
for m in month_loc:
|
|
268
|
+
try:
|
|
269
|
+
df_mw.iloc[m] = df_m.loc[str(df_mw_index[m]),:]
|
|
270
|
+
except:
|
|
271
|
+
continue
|
|
272
|
+
|
|
273
|
+
if interpolate=='linear':
|
|
274
|
+
return df_mw.apply(pd.to_numeric).interpolate('linear', limit_area='inside')
|
|
275
|
+
else:
|
|
276
|
+
return df_mw.apply(pd.to_numeric)
|
|
277
|
+
|
|
278
|
+
def GenDf_q2m(df_q,interpolate='linear'):
|
|
279
|
+
df_q.index = [str(x) for x in df_q.index]
|
|
280
|
+
df_q.index = [x.replace('Q','q') for x in df_q.index]
|
|
281
|
+
|
|
282
|
+
df_qm = pd.DataFrame(index = [str(x)+str(y+100)[-2:] for x in uniq([z[:4] for z in df_q.index]) for y in range(1,13)],
|
|
283
|
+
columns = df_q.columns)
|
|
284
|
+
df_qm = df_qm.loc[quarter2month(df_q.index[0]):quarter2month(df_q.index[-1])]
|
|
285
|
+
quarter_loc = np.where([x[-2:] in ('03','06','09','12') for x in df_qm.index])[0]
|
|
286
|
+
|
|
287
|
+
try:
|
|
288
|
+
df_qm.iloc[quarter_loc] = df_q.loc[[month2quarter(x) for x in df_qm.index[quarter_loc]],:]
|
|
289
|
+
except:
|
|
290
|
+
for q in quarter_loc:
|
|
291
|
+
try:
|
|
292
|
+
df_qm.iloc[q] = df_q.loc[month2quarter(df_qm.index[q]),:]
|
|
293
|
+
except:
|
|
294
|
+
continue
|
|
295
|
+
|
|
296
|
+
if interpolate=='linear':
|
|
297
|
+
return df_qm.apply(pd.to_numeric).interpolate('linear', limit_area='inside')
|
|
298
|
+
else:
|
|
299
|
+
return df_qm.apply(pd.to_numeric)
|
|
300
|
+
|
|
301
|
+
def GenDf_m2q(df_m, aggregate='last'):
|
|
302
|
+
df_mq = copy.deepcopy(df_m)
|
|
303
|
+
df_mq.index = [month2quarter(x) for x in df_mq.index]
|
|
304
|
+
df_mq.index.name = 'index'
|
|
305
|
+
if aggregate=='last':
|
|
306
|
+
df_q = df_mq[~df_mq.index.duplicated(keep='last')]
|
|
307
|
+
if aggregate=='mean':
|
|
308
|
+
df_q = df_mq.groupby('index').mean()
|
|
309
|
+
elif aggregate=='max':
|
|
310
|
+
df_q = df_mq.groupby('index').max()
|
|
311
|
+
elif aggregate=='median':
|
|
312
|
+
df_q = df_mq.groupby('index').median()
|
|
313
|
+
elif aggregate=='sum':
|
|
314
|
+
df_q = df_mq.groupby('index').sum()
|
|
315
|
+
return df_q
|
|
316
|
+
|
|
317
|
+
def GenDf_y2m(df_y,interpolate='linear'):
|
|
318
|
+
df_y.index = [str(x) for x in df_y.index]
|
|
319
|
+
df_ym = pd.DataFrame(index = [str(x)+str(y+100)[-2:] for x in df_y.index for y in range(1,13)], columns = df_y.columns)
|
|
320
|
+
df_ym_index = np.array([int(x[:4]) for x in df_ym.index])
|
|
321
|
+
year_loc = np.where([x>0 for x in df_ym_index[1:] - df_ym_index[:-1]]+[True])[0]
|
|
322
|
+
|
|
323
|
+
try:
|
|
324
|
+
df_ym.iloc[year_loc] = df_y.loc[[str(x) for x in df_ym_index[year_loc]],:]
|
|
325
|
+
except:
|
|
326
|
+
for y in year_loc:
|
|
327
|
+
try:
|
|
328
|
+
df_ym.iloc[y] = df_y.loc[str(df_ym_index[y]),:]
|
|
329
|
+
except:
|
|
330
|
+
continue
|
|
331
|
+
|
|
332
|
+
if interpolate=='linear':
|
|
333
|
+
return df_ym.apply(pd.to_numeric).interpolate('linear', limit_area='inside')
|
|
334
|
+
else:
|
|
335
|
+
return df_ym.apply(pd.to_numeric)
|
|
336
|
+
|
|
337
|
+
def GenMonthDummy(index, MW='week', num_month=13):
|
|
338
|
+
if MW == 'week':
|
|
339
|
+
month_dummy = pd.get_dummies([int(day2month(week2day(x))[-2:]) for x in index])
|
|
340
|
+
month_dummy.index = index
|
|
341
|
+
# month_dummy = pd.DataFrame(0,index = index, columns = range(1,num_month))
|
|
342
|
+
# for i,m in enumerate([int(day2month(week2day(x))[-2:]) for x in month_dummy.index]):
|
|
343
|
+
# month_dummy.loc[month_dummy.index[i],m] = 1
|
|
344
|
+
elif MW == 'month':
|
|
345
|
+
month_dummy = pd.get_dummies([int(x[-2:]) for x in index])
|
|
346
|
+
month_dummy.index = index
|
|
347
|
+
# month_dummy = pd.DataFrame(0,index = index, columns = range(1,num_month))
|
|
348
|
+
# for i,m in enumerate([int(x[-2:]) for x in month_dummy.index]):
|
|
349
|
+
# month_dummy.loc[month_dummy.index[i],m] = 1
|
|
350
|
+
|
|
351
|
+
month_dummy.columns = [str(x) for x in month_dummy.columns]
|
|
352
|
+
return month_dummy
|
|
353
|
+
|
|
354
|
+
def GenYearDummy(index, MW='week'):
|
|
355
|
+
year_dummy = pd.get_dummies([x[:4] for x in index])
|
|
356
|
+
year_dummy.index = index
|
|
357
|
+
year_dummy.columns = [str(x) for x in year_dummy.columns]
|
|
358
|
+
return year_dummy
|
|
359
|
+
# year_dummy = pd.DataFrame(index = index)
|
|
360
|
+
# for i,y in enumerate(np.unique([x[:4] for x in index])):
|
|
361
|
+
# year_dummy = pd.concat([year_dummy, \
|
|
362
|
+
# pd.DataFrame(1,index=[x for x in index if str(x[:4])==str(y)], \
|
|
363
|
+
# columns=[str(y)])],\
|
|
364
|
+
# axis=1)
|
|
365
|
+
# year_dummy.columns = [str(x) for x in year_dummy.columns]
|
|
366
|
+
# return year_dummy.fillna(0)
|
|
367
|
+
|
|
368
|
+
def GenStructBreakDummy(index, time, time2=None, MW='week'):
|
|
369
|
+
if MW == 'week':
|
|
370
|
+
structbreak_dummy = pd.DataFrame(0,index = index, columns = ['sb'])
|
|
371
|
+
if time2 is None:
|
|
372
|
+
structbreak_dummy.loc[structbreak_dummy.index>=str(time),'sb'] = 1
|
|
373
|
+
else:
|
|
374
|
+
structbreak_dummy.loc[(structbreak_dummy.index>=str(time)) & (structbreak_dummy.index<=str(time2)),'sb'] = 1
|
|
375
|
+
elif MW == 'month':
|
|
376
|
+
structbreak_dummy = pd.DataFrame(0,index = index, columns = ['sb'])
|
|
377
|
+
if time2 is None:
|
|
378
|
+
structbreak_dummy.loc[structbreak_dummy.index>=str(time),'sb'] = 1
|
|
379
|
+
else:
|
|
380
|
+
structbreak_dummy.loc[(structbreak_dummy.index>=str(time)) & (structbreak_dummy.index<=str(time2)),'sb'] = 1
|
|
381
|
+
|
|
382
|
+
structbreak_dummy.columns = [str(x) for x in structbreak_dummy.columns]
|
|
383
|
+
return structbreak_dummy
|
|
384
|
+
|
|
385
|
+
def GenCountDummy(index, holiday, holiday_counts):
|
|
386
|
+
holiday_dummy = pd.DataFrame(0,index=index,columns=['h'])
|
|
387
|
+
for i,h in enumerate(holiday):
|
|
388
|
+
holiday_dummy.loc[h,'h'] = holiday_counts[i]
|
|
389
|
+
holiday_dummy = holiday_dummy.loc[index]
|
|
390
|
+
return holiday_dummy
|
|
391
|
+
|
|
392
|
+
# data check fuction
|
|
393
|
+
|
|
394
|
+
def uniq(ls):
|
|
395
|
+
seen = set()
|
|
396
|
+
uniq = [x for x in ls if x not in seen and not seen.add(x)]
|
|
397
|
+
return uniq
|
|
398
|
+
|
|
399
|
+
def dupes(ls):
|
|
400
|
+
seen = set()
|
|
401
|
+
dupes = [x for x in ls if x in seen or seen.add(x)]
|
|
402
|
+
return dupes
|
|
403
|
+
|
|
404
|
+
# text function
|
|
405
|
+
|
|
406
|
+
def Arti2Sents(doc):
|
|
407
|
+
return([p for w in doc for p in w.split('. ')])
|
|
408
|
+
|
|
409
|
+
def Arti2SentsGroup(doc):
|
|
410
|
+
return([w.split('. ') for w in doc])
|
|
411
|
+
|
|
412
|
+
def Arrange2Article(results):
|
|
413
|
+
return [[item for sublist in res for item in sublist] for res in results]
|
|
414
|
+
|
|
415
|
+
def Arrange2Sentence(results):
|
|
416
|
+
return [item for sublist in results for item in sublist], [i for i,sublist in enumerate(results) for _ in sublist]
|
|
417
|
+
|
|
418
|
+
def WordCheck0(content,words_list):
|
|
419
|
+
return any([re.search(w,content)!=None for w in words_list])
|
|
420
|
+
|
|
421
|
+
def WordCheck1(content,words_list_by_groups):
|
|
422
|
+
return all([any([re.search(w,content)!=None for w in Words]) for Words in words_list_by_groups])
|
|
423
|
+
|
|
424
|
+
def WordCheck2(content,words_list_by_groups,words_negation):
|
|
425
|
+
return all([any([re.search(w,content)!=None for w in Words]) for Words in words_list_by_groups]+[re.search(w,content)==None for w in words_negation])
|
|
426
|
+
|
|
427
|
+
def Arti2Sents(doc):
|
|
428
|
+
delim = ['┃ ','→ ','— ',' ','! ','? ','•','○','●','◎','◇','◆','□','■','▷','▶','◈','▣',
|
|
429
|
+
'\uf0a7','\uf0d8','\uf076','\uf077','\uf06c','\uf09f']
|
|
430
|
+
p = []
|
|
431
|
+
for w in doc:
|
|
432
|
+
for d in delim:
|
|
433
|
+
w = w.replace(d,'. ')
|
|
434
|
+
p+=w.split('. ')
|
|
435
|
+
return(p)
|
|
436
|
+
#return([p for w in doc for p in w.replace('┃ ','. ').replace('• ','. ').replace('— ','. ').replace(' ','. ').replace('! ','. ').replace('? ','. ').split('. ')])
|
|
437
|
+
|
|
438
|
+
def Arti2SentsGroup(doc):
|
|
439
|
+
delim = ['┃ ','→ ','— ',' ','! ','? ','•','○','●','◎','◇','◆','□','■','▷','▶','◈','▣',
|
|
440
|
+
'\uf0a7','\uf0d8','\uf076','\uf077','\uf06c','\uf09f']
|
|
441
|
+
p = []
|
|
442
|
+
for w in doc:
|
|
443
|
+
for d in delim:
|
|
444
|
+
w = w.replace(d,'. ')
|
|
445
|
+
p.append(w.split('. '))
|
|
446
|
+
return(p)
|
|
447
|
+
|
|
448
|
+
def Arrange2Article(results):
|
|
449
|
+
return [[item for sublist in res for item in sublist] for res in results]
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
#pad and cut
|
|
454
|
+
|
|
455
|
+
def IntEncode(tokenized_sents, vocab): return [y+1 for y in vocab.doc2idx(tokenized_sents)]
|
|
456
|
+
|
|
457
|
+
def PadNCut(encoded_sents, maxlen): return np.array(np.pad(encoded_sents,[maxlen-min(len(encoded_sents),maxlen),0],'constant')[:maxlen])
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
#criteria functions
|
|
462
|
+
|
|
463
|
+
def rmse(y_pred,y_true): return np.sqrt(np.mean((y_pred-y_true)**2))
|
|
464
|
+
|
|
465
|
+
def mae(y_pred,y_true): return np.mean(np.abs(y_pred-y_true))
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
#transformation functions
|
|
470
|
+
|
|
471
|
+
def x13as(df, period='M', X12PATH='D:/x1.programs/x13as/'):
|
|
472
|
+
df.dropna(inplace=True)
|
|
473
|
+
ind = df.index
|
|
474
|
+
col = df.columns[0]
|
|
475
|
+
df.index = pd.PeriodIndex(df.index, freq=period)
|
|
476
|
+
df.columns = ['temp']
|
|
477
|
+
df = x13_arima_analysis(df, x12path=X12PATH).seasadj.to_frame(col)
|
|
478
|
+
df.index = ind
|
|
479
|
+
return df
|
|
480
|
+
|
|
481
|
+
def hp(df, period='M', lamb=None):
|
|
482
|
+
if lamb != None:
|
|
483
|
+
return sm.tsa.filters.hp_filter.hpfilter(x, lamb=lamb)
|
|
484
|
+
if period == 'D':
|
|
485
|
+
lamb = 1600*((365/4)**4)
|
|
486
|
+
elif period == 'W':
|
|
487
|
+
lamb = 1600*((52/4)**4)
|
|
488
|
+
elif period == 'M':
|
|
489
|
+
lamb = 129600 # or 14400
|
|
490
|
+
elif period == 'Q':
|
|
491
|
+
lamb = 1600
|
|
492
|
+
elif period == 'Y':
|
|
493
|
+
lamb = 6.25 # 100 for half-yearly
|
|
494
|
+
return sm.tsa.filters.hp_filter.hpfilter(x, lamb=lamb)
|
|
495
|
+
|
|
496
|
+
def extrapolate(df, maxlags=1):
|
|
497
|
+
df_ = df.copy()
|
|
498
|
+
df = copy.deepcopy(df.loc[df.dropna(axis=0).index[0]:])
|
|
499
|
+
|
|
500
|
+
if df.isna().sum().sum() == 0:
|
|
501
|
+
return df
|
|
502
|
+
|
|
503
|
+
if df.shape[1] == 1:
|
|
504
|
+
df_train = df.dropna()
|
|
505
|
+
df_test = df[df.isna().sum(axis=1)>0]
|
|
506
|
+
|
|
507
|
+
df_test[df_test.columns[0]] = AutoReg(endog=df_train, lags=maxlags)\
|
|
508
|
+
.fit().forecast(df_test.shape[0]).values
|
|
509
|
+
df.loc[df_test.index] = df_test
|
|
510
|
+
df_.loc[df.index] = df
|
|
511
|
+
return df_
|
|
512
|
+
else:
|
|
513
|
+
col_id_nan = np.where(df.dropna(axis=0,how='all').isna().sum(axis=0)>0)[0]
|
|
514
|
+
for i in col_id_nan:
|
|
515
|
+
df_train = df.dropna()
|
|
516
|
+
df_test = df[df.iloc[:,i].isna()]
|
|
517
|
+
|
|
518
|
+
forc = AutoReg(endog=df_train.iloc[:,[i]],\
|
|
519
|
+
exog=df_train.drop(df_train.columns[col_id_nan], axis=1), lags=maxlags)\
|
|
520
|
+
.fit().forecast(df_test.shape[0],\
|
|
521
|
+
exog=df_test.drop(df_train.columns[col_id_nan], axis=1)).values
|
|
522
|
+
df.iloc[:,i].loc[df_test.index] = forc
|
|
523
|
+
df_.loc[df.index] = df
|
|
524
|
+
|
|
525
|
+
# df_train = df.dropna()
|
|
526
|
+
# df_test = df[df.isna().sum(axis=1)>0]
|
|
527
|
+
|
|
528
|
+
# df_test[df_test.columns[0]] = AutoReg(endog=df_train.iloc[:,[0]],\
|
|
529
|
+
# exog=df_train.iloc[:,1:], lags=maxlags)\
|
|
530
|
+
# .fit().forecast(df_test.shape[0],\
|
|
531
|
+
# exog=df_test.iloc[:,1:]).values
|
|
532
|
+
# df.loc[df_test.index] = df_test
|
|
533
|
+
# df_.loc[df.index] = df
|
|
534
|
+
return df_
|
|
535
|
+
|
|
536
|
+
def proportion(df):
|
|
537
|
+
return (df.T/df.sum(axis=1)*100).T
|
|
538
|
+
|
|
539
|
+
def contribution(df, period=12):
|
|
540
|
+
# return (df.T/df.shift(period).sum(axis=1).T).T
|
|
541
|
+
return ((df-df.shift(period)).T/df.shift(period).sum(axis=1)).T
|
|
542
|
+
|
|
543
|
+
def contribution_proportion(df, period=12):
|
|
544
|
+
return ((df-df.shift(period)).T/(df.sum(axis=1)-df.shift(period).sum(axis=1))).T
|
|
545
|
+
|
|
546
|
+
def norm(pdx): return (pdx-pdx.mean())/pdx.std()
|
|
547
|
+
def scale(pdx): return (pdx-pdx.min())/(pdx.max()-pdx.min())
|
|
548
|
+
def linintp(pdx): return pdx.interpolate(method='linear')
|
|
549
|
+
def hptrend(lst,lamb=1): return sm.tsa.filters.hp_filter.hpfilter(lst, lamb=lamb)[1]
|
|
550
|
+
def hpcycle(lst,lamb=1): return sm.tsa.filters.hp_filter.hpfilter(lst, lamb=lamb)[0]
|
|
551
|
+
# def hmtrend(lst, hint=12): return qe.hamilton_filter(lst.values, hint)[1]
|
|
552
|
+
# def hmcycle(lst, hint=12): return qe.hamilton_filter(lst.values, hint)[0]
|
|
553
|
+
|
|
554
|
+
def unnorm(pdx,m,s): return pdx*s+m
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def ifexist(df, var, error_return=None):
|
|
558
|
+
if type(df)==dict:
|
|
559
|
+
if var in df.keys():
|
|
560
|
+
return df[var]
|
|
561
|
+
else:
|
|
562
|
+
return error_return
|
|
563
|
+
elif type(df)==pd.DataFrame:
|
|
564
|
+
if var in df.columns:
|
|
565
|
+
return df[var]
|
|
566
|
+
else:
|
|
567
|
+
return error_return
|
|
568
|
+
|
|
569
|
+
#memory functions
|
|
570
|
+
|
|
571
|
+
def sizeof_fmt(num, suffix='B'):
|
|
572
|
+
''' by Fred Cirera, https://stackoverflow.com/a/1094933/1870254, modified'''
|
|
573
|
+
for unit in ['','Ki','Mi','Gi','Ti','Pi','Ei','Zi']:
|
|
574
|
+
if abs(num) < 1024.0:
|
|
575
|
+
return "%3.1f %s%s" % (num, unit, suffix)
|
|
576
|
+
num /= 1024.0
|
|
577
|
+
return "%.1f %s%s" % (num, 'Yi', suffix)
|
|
578
|
+
|
|
579
|
+
# plotting functions
|
|
580
|
+
|
|
581
|
+
def Hangul(fontpath = '/usr/share/fonts/truetype/nanum/NanumBarunGothic.ttf'):
|
|
582
|
+
from matplotlib.font_manager import fontManager, FontProperties
|
|
583
|
+
from matplotlib import rcParams
|
|
584
|
+
|
|
585
|
+
fontManager.addfont(fontpath)
|
|
586
|
+
fontprop = FontProperties(fname=fontpath, size=10)
|
|
587
|
+
fontname = fontprop.get_name()
|
|
588
|
+
|
|
589
|
+
rcParams['font.family'] = fontname
|
|
590
|
+
rcParams['axes.unicode_minus'] =False
|
|
591
|
+
|
|
592
|
+
def Plotly(df, color=None, theme=None, dropdown=False):
|
|
593
|
+
pd.options.plotting.backend = "plotly"
|
|
594
|
+
if color is not None:
|
|
595
|
+
fig = df.plot(color_discrete_map=color)
|
|
596
|
+
else:
|
|
597
|
+
fig = df.plot()
|
|
598
|
+
|
|
599
|
+
myupdatemenus=[
|
|
600
|
+
dict(
|
|
601
|
+
type = "buttons",
|
|
602
|
+
buttons=list([
|
|
603
|
+
dict(
|
|
604
|
+
args=["visible", "legendonly"],
|
|
605
|
+
label="Deselect All",
|
|
606
|
+
method="restyle"
|
|
607
|
+
),
|
|
608
|
+
dict(
|
|
609
|
+
args=["visible", True],
|
|
610
|
+
label="Select All",
|
|
611
|
+
method="restyle"
|
|
612
|
+
)
|
|
613
|
+
]),
|
|
614
|
+
direction = "right",
|
|
615
|
+
showactive= True,
|
|
616
|
+
pad={"r": 10, "t": 10},
|
|
617
|
+
x=0.9,
|
|
618
|
+
xanchor="left",
|
|
619
|
+
y=1.12,
|
|
620
|
+
yanchor="top"
|
|
621
|
+
),
|
|
622
|
+
]
|
|
623
|
+
fig.update_layout(dict(updatemenus = myupdatemenus))
|
|
624
|
+
|
|
625
|
+
if theme=='white':
|
|
626
|
+
fig.update_layout(
|
|
627
|
+
plot_bgcolor='white'
|
|
628
|
+
)
|
|
629
|
+
fig.update_xaxes(
|
|
630
|
+
mirror=True,
|
|
631
|
+
ticks='outside',
|
|
632
|
+
showline=True,
|
|
633
|
+
linecolor='black',
|
|
634
|
+
gridcolor='lightgrey'
|
|
635
|
+
)
|
|
636
|
+
fig.update_yaxes(
|
|
637
|
+
mirror=True,
|
|
638
|
+
ticks='outside',
|
|
639
|
+
showline=True,
|
|
640
|
+
linecolor='black',
|
|
641
|
+
gridcolor='lightgrey'
|
|
642
|
+
)
|
|
643
|
+
fig.update_layout(
|
|
644
|
+
xaxis_title="", yaxis_title=""
|
|
645
|
+
)
|
|
646
|
+
|
|
647
|
+
if dropdown:
|
|
648
|
+
add1updatemenus = [
|
|
649
|
+
dict(buttons= [dict(
|
|
650
|
+
method= 'restyle',
|
|
651
|
+
label= str(i),
|
|
652
|
+
args= [{'x':[[z for z in df[y].index if int(z)>=int(i)] for y in df],
|
|
653
|
+
'y': [df[y][[z for z in df[y].index if int(z)>=int(i)]] for y in df]}]
|
|
654
|
+
) for i in df.index],
|
|
655
|
+
direction= 'down',
|
|
656
|
+
showactive= True,
|
|
657
|
+
pad={"r": 10, "t": 10},
|
|
658
|
+
x=0.0,
|
|
659
|
+
xanchor="left",
|
|
660
|
+
y=1.12,
|
|
661
|
+
yanchor="top"
|
|
662
|
+
)
|
|
663
|
+
]
|
|
664
|
+
add2updatemenus = [
|
|
665
|
+
dict(buttons= [dict(
|
|
666
|
+
method= 'restyle',
|
|
667
|
+
label= str(i),
|
|
668
|
+
args= [{'x':[[z for z in df[y].index if int(z)<=int(i)] for y in df],
|
|
669
|
+
'y': [df[y][[z for z in df[y].index if int(z)<=int(i)]] for y in df]}]
|
|
670
|
+
) for i in df.index],
|
|
671
|
+
direction= 'down',
|
|
672
|
+
showactive= True,
|
|
673
|
+
pad={"r": 10, "t": 10},
|
|
674
|
+
x=0.15,
|
|
675
|
+
xanchor="left",
|
|
676
|
+
y=1.12,
|
|
677
|
+
yanchor="top"
|
|
678
|
+
)
|
|
679
|
+
]
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
fig.update_layout(dict(updatemenus = myupdatemenus+add1updatemenus+add2updatemenus))
|
|
683
|
+
pass
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
fig.show()
|
|
687
|
+
|
|
688
|
+
def plotly_theme(fig, legend_x=0.65, legend_y=0.05, fs=20, legend_orientation='v', fs_legend=None, \
|
|
689
|
+
tickangle_x=90, title_x=None, title_y=None, range_y=None, margin=dict(l=10, r=30, t=30, b=10),\
|
|
690
|
+
left_unit=None, right_unit=None ):
|
|
691
|
+
|
|
692
|
+
if fs_legend is None:
|
|
693
|
+
fs_legend = fs
|
|
694
|
+
|
|
695
|
+
fig.update_layout(
|
|
696
|
+
legend=dict(
|
|
697
|
+
x=legend_x,
|
|
698
|
+
y=legend_y,
|
|
699
|
+
traceorder="normal",
|
|
700
|
+
title=None,
|
|
701
|
+
orientation=legend_orientation,
|
|
702
|
+
font=dict(
|
|
703
|
+
size=fs_legend,
|
|
704
|
+
#family="sans-serif",
|
|
705
|
+
#color="black"
|
|
706
|
+
),
|
|
707
|
+
)
|
|
708
|
+
)
|
|
709
|
+
fig.update_layout(
|
|
710
|
+
margin=margin,
|
|
711
|
+
plot_bgcolor='white',
|
|
712
|
+
font=dict(size=fs)
|
|
713
|
+
)
|
|
714
|
+
fig.update_xaxes(
|
|
715
|
+
mirror=True,
|
|
716
|
+
ticks='outside',
|
|
717
|
+
showline=True,
|
|
718
|
+
linecolor='black',
|
|
719
|
+
tickangle=tickangle_x,
|
|
720
|
+
#gridcolor='lightgrey'
|
|
721
|
+
)
|
|
722
|
+
fig.update_yaxes(
|
|
723
|
+
mirror=True,
|
|
724
|
+
ticks='outside',
|
|
725
|
+
showline=True,
|
|
726
|
+
linecolor='black',
|
|
727
|
+
#gridcolor='lightgrey'
|
|
728
|
+
)
|
|
729
|
+
fig.update_layout(
|
|
730
|
+
xaxis_title=title_x,
|
|
731
|
+
yaxis_title=title_y,
|
|
732
|
+
)
|
|
733
|
+
if range_y is not None:
|
|
734
|
+
fig.update_yaxes(
|
|
735
|
+
range=range_y
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
if left_unit is not None:
|
|
739
|
+
fig.add_annotation(dict(font=dict(color="black",size=left_unit.get('fs', fs)),
|
|
740
|
+
x=0, y=1.01,
|
|
741
|
+
showarrow=False,
|
|
742
|
+
text=left_unit['text'],
|
|
743
|
+
xanchor='left',
|
|
744
|
+
yanchor='bottom',
|
|
745
|
+
textangle=0,
|
|
746
|
+
xref="paper",
|
|
747
|
+
yref="paper"
|
|
748
|
+
))
|
|
749
|
+
|
|
750
|
+
if right_unit is not None:
|
|
751
|
+
fig.add_annotation(dict(font=dict(color="black",size=right_unit.get('fs', fs)),
|
|
752
|
+
x=1, y=1.01,
|
|
753
|
+
showarrow=False,
|
|
754
|
+
text=right_unit['text'],
|
|
755
|
+
xanchor='right',
|
|
756
|
+
yanchor='bottom',
|
|
757
|
+
textangle=0,
|
|
758
|
+
xref="paper",
|
|
759
|
+
yref="paper"
|
|
760
|
+
))
|
|
761
|
+
|
|
762
|
+
# fig.add_trace(go.Scatter(
|
|
763
|
+
# x=[-1],
|
|
764
|
+
# y=[1.5],
|
|
765
|
+
# mode="text",
|
|
766
|
+
# name="",
|
|
767
|
+
# text=["(%p)"],
|
|
768
|
+
# textposition="top center"
|
|
769
|
+
# ))
|
|
770
|
+
# fig.show()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
tspoon
|