import numpy as np
[docs]def OptimalLength(data: np.ndarray):
"""
Function calculates the optimal parameter value when using a stationary bootstraping algorithm.
The method is based on the 2004 paper by Politis & White:
Dimitris N. Politis & Halbert White (2004) Automatic Block-Length Selection for the Dependent Bootstrap, Econometric Reviews,
23:1, 53-70, DOI: 10.1081/ETC-120028836
The code was modified compared to Patton's implementation in that it takes as input a one dimensional time-series
and returns the optimalblock size only for the stationary bootstrap algorithm.
Warning! The minimal size of the time series is 9 elements.
Example:
>>> import numpy as np
>>> data = np.array([0.4,0.2,0.1,0.4,0.3,0.1,0.3,0.4,0.2,0.5,0.1,0.2])
>>> OptimalLength(data)
4.0
Args:
data: ndarray array containing the time-series that we wish to bootstrap.
Ex. np.array([-1,0.2,0.3,0.7,0.5,0.1,0.4,0.3,0.5])
Returns:
Bstar: optimal value of the parameter m Ex. 1
Original Matlab version written by:
James P. LeSage, Dept of Economics
University of Toledo
2801 W. Bancroft St,
Toledo, OH 43606
jpl@jpl.econ.utoledo.edu
This Python implementation is based on Andrew J. Patton's Matlab code avalible at:
http://public.econ.duke.edu/~ap172/
Implemented by Gregor Fabjan from Qnity Consultants on 12/11/2021.
"""
n = data.shape[0]
kn = max(5,np.sqrt(np.log10(n)))
mmax = int(np.ceil(np.sqrt(n))+kn)
bmax = np.ceil(min(3*np.sqrt(n),n/3))
c = 2
temp = mlag(data,mmax)
temp = np.delete(temp,range(mmax),0)
corcoef= np.zeros(mmax)
for iCor in range(0,mmax):
corcoef[iCor] = np.corrcoef(data[mmax:len(data)],temp[:,iCor])[0,1]
temp2 =np.transpose(mlag(corcoef,kn))
temp3 = np.zeros((kn,corcoef.shape[0]+1-kn))
for iRow in range(kn):
temp3[iRow,:] = np.append(temp2[iRow,kn:corcoef.shape[0]],corcoef[len(corcoef)-kn+iRow-1])
treshold = abs(temp3) < (c* np.sqrt(np.log10(n)/n)) #Test if coeff bigger than triger
treshold = np.sum(treshold,axis = 0 )
count = 0
mhat = None
for x in treshold:
if (x==kn):
mhat = count
break
count +=1
if (mhat is None):
# largest lag that is still significant
seccrit = corcoef >(c* np.sqrt(np.log10(n)/n))
for iLag in range(seccrit.shape[0]-1,0,-1):
if (seccrit[iLag]):
mhat = iLag+1
break
if(mhat is None):
M = 0
elif (2*mhat > mmax):
M = mmax
else:
M = 2*mhat
# Computing the inputs to the function for Bstar
kk = np.arange(-M, M+1, 1)
if (M>0):
temp = mlag(data,M)
temp = np.delete(temp,range(M),0)
temp2 = np.zeros((temp.shape[0],temp.shape[1]+1))
for iRow in range(len(data)-M):
temp2[iRow,:] = np.hstack((data[M+iRow],temp[iRow,:]))
temp2 = np.transpose(temp2)
temp3 = np.cov(temp2)
acv = temp3[:,0]
acv2 = np.zeros((len(acv)-1,2))
acv2[:,0] = np.transpose(-np.linspace(1,M,M))
acv2[:,1] = acv[1:len(acv)]
if acv2.shape[0]>1:
acv2 =acv2[::-1]
acv3 = np.zeros((acv2.shape[0]+acv.shape[0],1))
Counter = 0
for iEl in range(acv2.shape[0]):
acv3[Counter,0] = acv2[iEl,1]
Counter +=1
for iEl in range(acv.shape[0]):
acv3[Counter,0] = acv[iEl]
Counter +=1
Ghat = 0
DSBhat = 0
LamTemp =lam(kk/M)
for iHat in range(acv3.shape[0]):
Ghat += LamTemp[iHat]* np.absolute(kk[iHat])*acv3[iHat,0]
DSBhat += LamTemp[iHat]*acv3[iHat,0]
DSBhat = 2* np.square(DSBhat)
Bstar = np.power(2*np.square(Ghat)/DSBhat,1/3)*np.power(n,1/3)
if Bstar>bmax:
Bstar = bmax
else:
Bstar = 1
return Bstar
[docs]def mlag(x: np.ndarray,n)-> np.ndarray:
"""Returns a numpy array in which the k-th column is the series x pushed down (lagged) by k places.
Example:
>>> import numpy as np
>>> x = np.array([1,2,3,4])
>>> n = 2
>>> mlag(x,n)
array([[0, 0],
[1, 0],
[2, 1],
[3, 2]])
The function was tested passing a numpy array (ndarray) as input and requires numpy to run.
Args:
x: ndarray array for which the lagged matrix is calculated. np.array([1,2,3,4])
n: integer specifying how many lags does the function consider
Returns:
xlag: ndarray contining the k-th lagged values in the k-th column of the matrix
Original Matlab version written by:
James P. LeSage, Dept of Economics
University of Toledo
2801 W. Bancroft St,
Toledo, OH 43606
jpl@jpl.econ.utoledo.edu
This Python implementation is based on Andrew J. Patton's Matlab code avalible at:
http://public.econ.duke.edu/~ap172/
Implemented by Gregor Fabjan from Qnity Consultants on 12/11/2021
"""
nobs = x.shape[0]
out = np.zeros((nobs,n))
for iLag in range(1,n+1):
for iCol in range(nobs-iLag):
out[iCol+iLag,iLag-1] = x[iCol];
return out
[docs]def lam(x: np.ndarray) -> np.ndarray:
"""Returns the value at points x of the Trapezoidal function.
Trapezoidal funcion maps all numbers bigger than 1 or smaller than -1 to zero.
Values between -1/2 to 1/2 to 1 and the rest either on the line connecting (-1,0) to (-1/2,1) or (1/2,1) to (1,0).
Example:
>>> import numpy as np
>>> x = np.array([0.55])
>>> lam(x)
array([0.9])
Args:
x: ndarray array of points on which we wish to apply the trapezoidal mapping.
Ex. np.array([-1,0.2,0.3,0.7])
Returns:
ndarray of mapped points Ex. array([0. , 1. , 1. , 0.6])
Original Matlab version written by:
James P. LeSage, Dept of Economics
University of Toledo
2801 W. Bancroft St,
Toledo, OH 43606
jpl@jpl.econ.utoledo.edu
This Python implementation is based on Andrew J. Patton's Matlab code avalible at:
http://public.econ.duke.edu/~ap172/
Implemented by Gregor Fabjan from Qnity Consultants on 12/11/2021.
"""
nrow = x.shape[0]
out = np.zeros(nrow)
for row in range(nrow):
out[row] = (abs(x[row])>=0) * (abs(x[row])<0.5) + 2 * (1-abs(x[row])) * (abs(x[row])>=0.5) * (abs(x[row])<=1)
return out