Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/statsmodels/tsa/tsatools.py : 10%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1from statsmodels.compat.python import lrange, lzip
2from statsmodels.compat.numpy import recarray_select
4import numpy as np
5import numpy.lib.recfunctions as nprf
6import pandas as pd
7from pandas import DataFrame
8from pandas.tseries import offsets
9from pandas.tseries.frequencies import to_offset
11from statsmodels.tools.validation import int_like, bool_like, string_like
12from statsmodels.tools.sm_exceptions import ValueWarning
13from statsmodels.tools.data import _is_using_pandas, _is_recarray
14from statsmodels.tools.validation import array_like
17def add_trend(x, trend="c", prepend=False, has_constant='skip'):
18 """
19 Add a trend and/or constant to an array.
21 Parameters
22 ----------
23 x : array_like
24 Original array of data.
25 trend : str {'n', 'c', 't', 'ct', 'ctt'}
26 The trend to add.
28 * 'n' add no trend.
29 * 'c' add constant only.
30 * 't' add trend only.
31 * 'ct' add constant and linear trend.
32 * 'ctt' add constant and linear and quadratic trend.
33 prepend : bool
34 If True, prepends the new data to the columns of X.
35 has_constant : str {'raise', 'add', 'skip'}
36 Controls what happens when trend is 'c' and a constant column already
37 exists in x. 'raise' will raise an error. 'add' will add a column of
38 1s. 'skip' will return the data without change. 'skip' is the default.
40 Returns
41 -------
42 array_like
43 The original data with the additional trend columns. If x is a
44 recarray or pandas Series or DataFrame, then the trend column names
45 are 'const', 'trend' and 'trend_squared'.
47 See Also
48 --------
49 statsmodels.tools.tools.add_constant
50 Add a constant column to an array.
52 Notes
53 -----
54 Returns columns as ['ctt','ct','c'] whenever applicable. There is currently
55 no checking for an existing trend.
56 """
57 prepend = bool_like(prepend, 'prepend')
58 trend = string_like(trend, 'trend', options=('n', 'c', 't', 'ct', 'ctt'))
59 has_constant = string_like(has_constant, 'has_constant',
60 options=('raise', 'add', 'skip'))
62 # TODO: could be generalized for trend of aribitrary order
63 columns = ['const', 'trend', 'trend_squared']
64 if trend == 'n':
65 return x.copy()
66 elif trend == "c": # handles structured arrays
67 columns = columns[:1]
68 trendorder = 0
69 elif trend == "ct" or trend == "t":
70 columns = columns[:2]
71 if trend == "t":
72 columns = columns[1:2]
73 trendorder = 1
74 elif trend == "ctt":
75 trendorder = 2
77 is_recarray = _is_recarray(x)
78 is_pandas = _is_using_pandas(x, None) or is_recarray
79 if is_pandas or is_recarray:
80 if is_recarray:
81 # deprecated: remove recarray support after 0.12
82 import warnings
83 from statsmodels.tools.sm_exceptions import recarray_warning
84 warnings.warn(recarray_warning, FutureWarning)
86 descr = x.dtype.descr
87 x = pd.DataFrame.from_records(x)
88 elif isinstance(x, pd.Series):
89 x = pd.DataFrame(x)
90 else:
91 x = x.copy()
92 else:
93 x = np.asanyarray(x)
95 nobs = len(x)
96 trendarr = np.vander(np.arange(1, nobs + 1, dtype=np.float64), trendorder + 1)
97 # put in order ctt
98 trendarr = np.fliplr(trendarr)
99 if trend == "t":
100 trendarr = trendarr[:, 1]
102 if "c" in trend:
103 if is_pandas or is_recarray:
104 # Mixed type protection
105 def safe_is_const(s):
106 try:
107 return np.ptp(s) == 0.0 and np.any(s != 0.0)
108 except:
109 return False
110 col_const = x.apply(safe_is_const, 0)
111 else:
112 ptp0 = np.ptp(np.asanyarray(x), axis=0)
113 col_is_const = ptp0 == 0
114 nz_const = col_is_const & (x[0] != 0)
115 col_const = nz_const
117 if np.any(col_const):
118 if has_constant == 'raise':
119 msg = "x contains a constant. Adding a constant with " \
120 "trend='{0}' is not allowed.".format(trend)
121 raise ValueError(msg)
122 elif has_constant == 'skip':
123 columns = columns[1:]
124 trendarr = trendarr[:, 1:]
126 order = 1 if prepend else -1
127 if is_recarray or is_pandas:
128 trendarr = pd.DataFrame(trendarr, index=x.index, columns=columns)
129 x = [trendarr, x]
130 x = pd.concat(x[::order], 1)
131 else:
132 x = [trendarr, x]
133 x = np.column_stack(x[::order])
135 if is_recarray:
136 x = x.to_records(index=False)
137 new_descr = x.dtype.descr
138 extra_col = len(new_descr) - len(descr)
139 if prepend:
140 descr = new_descr[:extra_col] + descr
141 else:
142 descr = descr + new_descr[-extra_col:]
144 x = x.astype(np.dtype(descr))
146 return x
149def add_lag(x, col=None, lags=1, drop=False, insert=True):
150 """
151 Returns an array with lags included given an array.
153 Parameters
154 ----------
155 x : array_like
156 An array or NumPy ndarray subclass. Can be either a 1d or 2d array with
157 observations in columns.
158 col : 'string', int, or None
159 If data is a structured array or a recarray, `col` can be a string
160 that is the name of the column containing the variable. Or `col` can
161 be an int of the zero-based column index. If it's a 1d array `col`
162 can be None.
163 lags : int
164 The number of lags desired.
165 drop : bool
166 Whether to keep the contemporaneous variable for the data.
167 insert : bool or int
168 If True, inserts the lagged values after `col`. If False, appends
169 the data. If int inserts the lags at int.
171 Returns
172 -------
173 array : ndarray
174 Array with lags
176 Examples
177 --------
179 >>> import statsmodels.api as sm
180 >>> data = sm.datasets.macrodata.load(as_pandas=False)
181 >>> data = data.data[['year','quarter','realgdp','cpi']]
182 >>> data = sm.tsa.add_lag(data, 'realgdp', lags=2)
184 Notes
185 -----
186 Trims the array both forward and backward, so that the array returned
187 so that the length of the returned array is len(`X`) - lags. The lags are
188 returned in increasing order, ie., t-1,t-2,...,t-lags
189 """
190 lags = int_like(lags, 'lags')
191 drop = bool_like(drop, 'drop')
193 if x.dtype.names:
194 names = x.dtype.names
195 if not col and np.squeeze(x).ndim > 1:
196 raise IndexError("col is None and the input array is not 1d")
197 elif len(names) == 1:
198 col = names[0]
199 if isinstance(col, int):
200 col = x.dtype.names[col]
202 contemp = x[col]
204 # make names for lags
205 tmp_names = [col + '_'+'L(%i)' % i for i in range(1, lags+1)]
206 ndlags = lagmat(contemp, maxlag=lags, trim='Both')
208 # get index for return
209 if insert is True:
210 ins_idx = list(names).index(col) + 1
211 elif insert is False:
212 ins_idx = len(names) + 1
213 else: # insert is an int
214 if insert > len(names):
215 import warnings
216 warnings.warn("insert > number of variables, inserting at the"
217 " last position", ValueWarning)
218 ins_idx = insert
220 first_names = list(names[:ins_idx])
221 last_names = list(names[ins_idx:])
223 if drop:
224 if col in first_names:
225 first_names.pop(first_names.index(col))
226 else:
227 last_names.pop(last_names.index(col))
229 if first_names: # only do this if x is not "empty"
230 # Workaround to avoid NumPy FutureWarning
231 _x = recarray_select(x, first_names)
232 first_arr = nprf.append_fields(_x[lags:], tmp_names, ndlags.T,
233 usemask=False)
235 else:
236 first_arr = np.zeros(len(x)-lags, dtype=lzip(tmp_names,
237 (x[col].dtype,)*lags))
238 for i,name in enumerate(tmp_names):
239 first_arr[name] = ndlags[:,i]
240 if last_names:
241 return nprf.append_fields(first_arr, last_names,
242 [x[name][lags:] for name in last_names], usemask=False)
243 else: # lags for last variable
244 return first_arr
246 else: # we have an ndarray
248 if x.ndim == 1: # make 2d if 1d
249 x = x[:,None]
250 if col is None:
251 col = 0
253 # handle negative index
254 if col < 0:
255 col = x.shape[1] + col
257 contemp = x[:,col]
259 if insert is True:
260 ins_idx = col + 1
261 elif insert is False:
262 ins_idx = x.shape[1]
263 else:
264 if insert < 0: # handle negative index
265 insert = x.shape[1] + insert + 1
266 if insert > x.shape[1]:
267 insert = x.shape[1]
268 import warnings
269 warnings.warn("insert > number of variables, inserting at the"
270 " last position", ValueWarning)
271 ins_idx = insert
273 ndlags = lagmat(contemp, lags, trim='Both')
274 first_cols = lrange(ins_idx)
275 last_cols = lrange(ins_idx,x.shape[1])
276 if drop:
277 if col in first_cols:
278 first_cols.pop(first_cols.index(col))
279 else:
280 last_cols.pop(last_cols.index(col))
281 return np.column_stack((x[lags:,first_cols],ndlags,
282 x[lags:,last_cols]))
285def detrend(x, order=1, axis=0):
286 """
287 Detrend an array with a trend of given order along axis 0 or 1.
289 Parameters
290 ----------
291 x : array_like, 1d or 2d
292 Data, if 2d, then each row or column is independently detrended with
293 the same trendorder, but independent trend estimates.
294 order : int
295 The polynomial order of the trend, zero is constant, one is
296 linear trend, two is quadratic trend.
297 axis : int
298 Axis can be either 0, observations by rows, or 1, observations by
299 columns.
301 Returns
302 -------
303 ndarray
304 The detrended series is the residual of the linear regression of the
305 data on the trend of given order.
306 """
307 order = int_like(order, 'order')
308 axis = int_like(axis, 'axis')
310 if x.ndim == 2 and int(axis) == 1:
311 x = x.T
312 elif x.ndim > 2:
313 raise NotImplementedError('x.ndim > 2 is not implemented until it is needed')
315 nobs = x.shape[0]
316 if order == 0:
317 # Special case demean
318 resid = x - x.mean(axis=0)
319 else:
320 trends = np.vander(np.arange(float(nobs)), N=order + 1)
321 beta = np.linalg.pinv(trends).dot(x)
322 resid = x - np.dot(trends, beta)
324 if x.ndim == 2 and int(axis) == 1:
325 resid = resid.T
327 return resid
330def lagmat(x, maxlag, trim='forward', original='ex', use_pandas=False):
331 """
332 Create 2d array of lags.
334 Parameters
335 ----------
336 x : array_like
337 Data; if 2d, observation in rows and variables in columns.
338 maxlag : int
339 All lags from zero to maxlag are included.
340 trim : {'forward', 'backward', 'both', 'none', None}
341 The trimming method to use.
343 * 'forward' : trim invalid observations in front.
344 * 'backward' : trim invalid initial observations.
345 * 'both' : trim invalid observations on both sides.
346 * 'none', None : no trimming of observations.
347 original : {'ex','sep','in'}
348 How the original is treated.
350 * 'ex' : drops the original array returning only the lagged values.
351 * 'in' : returns the original array and the lagged values as a single
352 array.
353 * 'sep' : returns a tuple (original array, lagged values). The original
354 array is truncated to have the same number of rows as
355 the returned lagmat.
356 use_pandas : bool
357 If true, returns a DataFrame when the input is a pandas
358 Series or DataFrame. If false, return numpy ndarrays.
360 Returns
361 -------
362 lagmat : ndarray
363 The array with lagged observations.
364 y : ndarray, optional
365 Only returned if original == 'sep'.
367 Notes
368 -----
369 When using a pandas DataFrame or Series with use_pandas=True, trim can only
370 be 'forward' or 'both' since it is not possible to consistently extend
371 index values.
373 Examples
374 --------
375 >>> from statsmodels.tsa.tsatools import lagmat
376 >>> import numpy as np
377 >>> X = np.arange(1,7).reshape(-1,2)
378 >>> lagmat(X, maxlag=2, trim="forward", original='in')
379 array([[ 1., 2., 0., 0., 0., 0.],
380 [ 3., 4., 1., 2., 0., 0.],
381 [ 5., 6., 3., 4., 1., 2.]])
383 >>> lagmat(X, maxlag=2, trim="backward", original='in')
384 array([[ 5., 6., 3., 4., 1., 2.],
385 [ 0., 0., 5., 6., 3., 4.],
386 [ 0., 0., 0., 0., 5., 6.]])
388 >>> lagmat(X, maxlag=2, trim="both", original='in')
389 array([[ 5., 6., 3., 4., 1., 2.]])
391 >>> lagmat(X, maxlag=2, trim="none", original='in')
392 array([[ 1., 2., 0., 0., 0., 0.],
393 [ 3., 4., 1., 2., 0., 0.],
394 [ 5., 6., 3., 4., 1., 2.],
395 [ 0., 0., 5., 6., 3., 4.],
396 [ 0., 0., 0., 0., 5., 6.]])
397 """
398 maxlag = int_like(maxlag, 'maxlag')
399 use_pandas = bool_like(use_pandas, 'use_pandas')
400 trim = string_like(trim, 'trim', optional=True,
401 options=('forward', 'backward', 'both', 'none'))
402 original = string_like(original, 'original', options=('ex', 'sep', 'in'))
404 # TODO: allow list of lags additional to maxlag
405 orig = x
406 x = array_like(x, 'x', ndim=2, dtype=None)
407 is_pandas = _is_using_pandas(orig, None) and use_pandas
408 trim = 'none' if trim is None else trim
409 trim = trim.lower()
410 if is_pandas and trim in ('none', 'backward'):
411 raise ValueError("trim cannot be 'none' or 'forward' when used on "
412 "Series or DataFrames")
414 dropidx = 0
415 nobs, nvar = x.shape
416 if original in ['ex', 'sep']:
417 dropidx = nvar
418 if maxlag >= nobs:
419 raise ValueError("maxlag should be < nobs")
420 lm = np.zeros((nobs + maxlag, nvar * (maxlag + 1)))
421 for k in range(0, int(maxlag + 1)):
422 lm[maxlag - k:nobs + maxlag - k,
423 nvar * (maxlag - k):nvar * (maxlag - k + 1)] = x
425 if trim in ('none', 'forward'):
426 startobs = 0
427 elif trim in ('backward', 'both'):
428 startobs = maxlag
429 else:
430 raise ValueError('trim option not valid')
432 if trim in ('none', 'backward'):
433 stopobs = len(lm)
434 else:
435 stopobs = nobs
437 if is_pandas:
438 x = orig
439 x_columns = x.columns if isinstance(x, DataFrame) else [x.name]
440 columns = [str(col) for col in x_columns]
441 for lag in range(maxlag):
442 lag_str = str(lag + 1)
443 columns.extend([str(col) + '.L.' + lag_str for col in x_columns])
444 lm = DataFrame(lm[:stopobs], index=x.index, columns=columns)
445 lags = lm.iloc[startobs:]
446 if original in ('sep', 'ex'):
447 leads = lags[x_columns]
448 lags = lags.drop(x_columns, 1)
449 else:
450 lags = lm[startobs:stopobs, dropidx:]
451 if original == 'sep':
452 leads = lm[startobs:stopobs, :dropidx]
454 if original == 'sep':
455 return lags, leads
456 else:
457 return lags
460def lagmat2ds(x, maxlag0, maxlagex=None, dropex=0, trim='forward',
461 use_pandas=False):
462 """
463 Generate lagmatrix for 2d array, columns arranged by variables.
465 Parameters
466 ----------
467 x : array_like
468 Data, 2d. Observations in rows and variables in columns.
469 maxlag0 : int
470 The first variable all lags from zero to maxlag are included.
471 maxlagex : {None, int}
472 The max lag for all other variables all lags from zero to maxlag are
473 included.
474 dropex : int
475 Exclude first dropex lags from other variables. For all variables,
476 except the first, lags from dropex to maxlagex are included.
477 trim : str
478 The trimming method to use.
480 * 'forward' : trim invalid observations in front.
481 * 'backward' : trim invalid initial observations.
482 * 'both' : trim invalid observations on both sides.
483 * 'none' : no trimming of observations.
484 use_pandas : bool
485 If true, returns a DataFrame when the input is a pandas
486 Series or DataFrame. If false, return numpy ndarrays.
488 Returns
489 -------
490 ndarray
491 The array with lagged observations, columns ordered by variable.
493 Notes
494 -----
495 Inefficient implementation for unequal lags, implemented for convenience.
496 """
497 maxlag0 = int_like(maxlag0, 'maxlag0')
498 maxlagex = int_like(maxlagex, 'maxlagex', optional=True)
499 trim = string_like(trim, 'trim', optional=True,
500 options=('forward', 'backward', 'both', 'none'))
501 if maxlagex is None:
502 maxlagex = maxlag0
503 maxlag = max(maxlag0, maxlagex)
504 is_pandas = _is_using_pandas(x, None)
506 if x.ndim == 1:
507 if is_pandas:
508 x = pd.DataFrame(x)
509 else:
510 x = x[:, None]
511 elif x.ndim == 0 or x.ndim > 2:
512 raise ValueError('Only supports 1 and 2-dimensional data.')
514 nobs, nvar = x.shape
516 if is_pandas and use_pandas:
517 lags = lagmat(x.iloc[:, 0], maxlag, trim=trim,
518 original='in', use_pandas=True)
519 lagsli = [lags.iloc[:, :maxlag0 + 1]]
520 for k in range(1, nvar):
521 lags = lagmat(x.iloc[:, k], maxlag, trim=trim,
522 original='in', use_pandas=True)
523 lagsli.append(lags.iloc[:, dropex:maxlagex + 1])
524 return pd.concat(lagsli, axis=1)
525 elif is_pandas:
526 x = np.asanyarray(x)
528 lagsli = [lagmat(x[:, 0], maxlag, trim=trim, original='in')[:, :maxlag0 + 1]]
529 for k in range(1, nvar):
530 lagsli.append(lagmat(x[:, k], maxlag, trim=trim, original='in')[:, dropex:maxlagex + 1])
531 return np.column_stack(lagsli)
534def vec(mat):
535 return mat.ravel('F')
538def vech(mat):
539 # Gets Fortran-order
540 return mat.T.take(_triu_indices(len(mat)))
543# tril/triu/diag, suitable for ndarray.take
545def _tril_indices(n):
546 rows, cols = np.tril_indices(n)
547 return rows * n + cols
550def _triu_indices(n):
551 rows, cols = np.triu_indices(n)
552 return rows * n + cols
555def _diag_indices(n):
556 rows, cols = np.diag_indices(n)
557 return rows * n + cols
560def unvec(v):
561 k = int(np.sqrt(len(v)))
562 assert(k * k == len(v))
563 return v.reshape((k, k), order='F')
566def unvech(v):
567 # quadratic formula, correct fp error
568 rows = .5 * (-1 + np.sqrt(1 + 8 * len(v)))
569 rows = int(np.round(rows))
571 result = np.zeros((rows, rows))
572 result[np.triu_indices(rows)] = v
573 result = result + result.T
575 # divide diagonal elements by 2
576 result[np.diag_indices(rows)] /= 2
578 return result
581def duplication_matrix(n):
582 """
583 Create duplication matrix D_n which satisfies vec(S) = D_n vech(S) for
584 symmetric matrix S
586 Returns
587 -------
588 D_n : ndarray
589 """
590 n = int_like(n, 'n')
591 tmp = np.eye(n * (n + 1) // 2)
592 return np.array([unvech(x).ravel() for x in tmp]).T
595def elimination_matrix(n):
596 """
597 Create the elimination matrix L_n which satisfies vech(M) = L_n vec(M) for
598 any matrix M
600 Parameters
601 ----------
603 Returns
604 -------
605 """
606 n = int_like(n, 'n')
607 vech_indices = vec(np.tril(np.ones((n, n))))
608 return np.eye(n * n)[vech_indices != 0]
611def commutation_matrix(p, q):
612 """
613 Create the commutation matrix K_{p,q} satisfying vec(A') = K_{p,q} vec(A)
615 Parameters
616 ----------
617 p : int
618 q : int
620 Returns
621 -------
622 K : ndarray (pq x pq)
623 """
624 p = int_like(p, 'p')
625 q = int_like(q, 'q')
627 K = np.eye(p * q)
628 indices = np.arange(p * q).reshape((p, q), order='F')
629 return K.take(indices.ravel(), axis=0)
632def _ar_transparams(params):
633 """
634 Transforms params to induce stationarity/invertability.
636 Parameters
637 ----------
638 params : array_like
639 The AR coefficients
641 Reference
642 ---------
643 Jones(1980)
644 """
645 newparams = np.tanh(params/2)
646 tmp = np.tanh(params/2)
647 for j in range(1,len(params)):
648 a = newparams[j]
649 for kiter in range(j):
650 tmp[kiter] -= a * newparams[j-kiter-1]
651 newparams[:j] = tmp[:j]
652 return newparams
655def _ar_invtransparams(params):
656 """
657 Inverse of the Jones reparameterization
659 Parameters
660 ----------
661 params : array_like
662 The transformed AR coefficients
663 """
664 params = params.copy()
665 tmp = params.copy()
666 for j in range(len(params)-1,0,-1):
667 a = params[j]
668 for kiter in range(j):
669 tmp[kiter] = (params[kiter] + a * params[j-kiter-1])/\
670 (1-a**2)
671 params[:j] = tmp[:j]
672 invarcoefs = 2*np.arctanh(params)
673 return invarcoefs
676def _ma_transparams(params):
677 """
678 Transforms params to induce stationarity/invertability.
680 Parameters
681 ----------
682 params : ndarray
683 The ma coeffecients of an (AR)MA model.
685 Reference
686 ---------
687 Jones(1980)
688 """
689 newparams = ((1-np.exp(-params))/(1+np.exp(-params))).copy()
690 tmp = ((1-np.exp(-params))/(1+np.exp(-params))).copy()
692 # levinson-durbin to get macf
693 for j in range(1,len(params)):
694 b = newparams[j]
695 for kiter in range(j):
696 tmp[kiter] += b * newparams[j-kiter-1]
697 newparams[:j] = tmp[:j]
698 return newparams
701def _ma_invtransparams(macoefs):
702 """
703 Inverse of the Jones reparameterization
705 Parameters
706 ----------
707 params : ndarray
708 The transformed MA coefficients
709 """
710 tmp = macoefs.copy()
711 for j in range(len(macoefs)-1,0,-1):
712 b = macoefs[j]
713 for kiter in range(j):
714 tmp[kiter] = (macoefs[kiter]-b *macoefs[j-kiter-1])/(1-b**2)
715 macoefs[:j] = tmp[:j]
716 invmacoefs = -np.log((1-macoefs)/(1+macoefs))
717 return invmacoefs
720def unintegrate_levels(x, d):
721 """
722 Returns the successive differences needed to unintegrate the series.
724 Parameters
725 ----------
726 x : array_like
727 The original series
728 d : int
729 The number of differences of the differenced series.
731 Returns
732 -------
733 y : array_like
734 The increasing differences from 0 to d-1 of the first d elements
735 of x.
737 See Also
738 --------
739 unintegrate
740 """
741 d = int_like(d, 'd')
742 x = x[:d]
743 return np.asarray([np.diff(x, d - i)[0] for i in range(d, 0, -1)])
746def unintegrate(x, levels):
747 """
748 After taking n-differences of a series, return the original series
750 Parameters
751 ----------
752 x : array_like
753 The n-th differenced series
754 levels : list
755 A list of the first-value in each differenced series, for
756 [first-difference, second-difference, ..., n-th difference]
758 Returns
759 -------
760 y : array_like
761 The original series de-differenced
763 Examples
764 --------
765 >>> x = np.array([1, 3, 9., 19, 8.])
766 >>> levels = unintegrate_levels(x, 2)
767 >>> levels
768 array([ 1., 2.])
769 >>> unintegrate(np.diff(x, 2), levels)
770 array([ 1., 3., 9., 19., 8.])
771 """
772 levels = list(levels)[:] # copy
773 if len(levels) > 1:
774 x0 = levels.pop(-1)
775 return unintegrate(np.cumsum(np.r_[x0, x]), levels)
776 x0 = levels[0]
777 return np.cumsum(np.r_[x0, x])
780def freq_to_period(freq):
781 """
782 Convert a pandas frequency to a periodicity
784 Parameters
785 ----------
786 freq : str or offset
787 Frequency to convert
789 Returns
790 -------
791 period : int
792 Periodicity of freq
794 Notes
795 -----
796 Annual maps to 1, quarterly maps to 4, monthly to 12, weekly to 52.
797 """
798 if not isinstance(freq, offsets.DateOffset):
799 freq = to_offset(freq) # go ahead and standardize
800 freq = freq.rule_code.upper()
802 if freq == 'A' or freq.startswith(('A-', 'AS-')):
803 return 1
804 elif freq == 'Q' or freq.startswith(('Q-', 'QS-')):
805 return 4
806 elif freq == 'M' or freq.startswith(('M-', 'MS')):
807 return 12
808 elif freq == 'W' or freq.startswith('W-'):
809 return 52
810 elif freq == 'D':
811 return 7
812 elif freq == 'B':
813 return 5
814 elif freq == 'H':
815 return 24
816 else: # pragma : no cover
817 raise ValueError("freq {} not understood. Please report if you "
818 "think this is in error.".format(freq))
821__all__ = ['lagmat', 'lagmat2ds','add_trend', 'duplication_matrix',
822 'elimination_matrix', 'commutation_matrix',
823 'vec', 'vech', 'unvec', 'unvech', 'freq_to_period']