Authors: Jozef Hanč, Martina Hančová, Andrej Gajdoš
Faculty of Science, P. J. Šafárik University in Košice, Slovakia
emails: martina.hancova@upjs.sk
EBLUP-NE for cyber attacks
Python-based computational tools - SciPy, CVXPY
To get back to the contents, use the Home key.
- solver - the convex optimization solver ECOS, OSQP, and SCS chosen according to the given problem
* **OSQP** for convex quadratic problems
* `max_iter` - maximum number of iterations (default: 10000).
* `eps_abs` - absolute accuracy (default: 1e-4).
* `eps_rel` - relative accuracy (default: 1e-4).
* **ECOS** for convex second-order cone problems
* `max_iters` - maximum number of iterations (default: 100).
* `abstol` - absolute accuracy (default: 1e-7).
* `reltol` - relative accuracy (default: 1e-6).
* `feastol` - tolerance for feasibility conditions (default: 1e-7).
* `abstol_inacc` - absolute accuracy for inaccurate solution (default: 5e-5).
* `reltol_inacc` - relative accuracy for inaccurate solution (default: 5e-5).
* `feastol_inacc` - tolerance for feasibility condition for inaccurate solution (default: 1e-4).
* **SCS** for large-scale convex cone problems
* `max_iters` - maximum number of iterations (default: 2500).
* `eps` - convergence tolerance (default: 1e-4).
* `alpha` - relaxation parameter (default: 1.8).
* `scale` - balance between minimizing primal and dual residual (default: 5.0).
* `normalize` - whether to precondition data matrices (default: True).
* `use_indirect` - whether to use indirect solver for KKT sytem (instead of direct) (default: True).<font>
import cvxpy
import numpy as np
import pandas as pd
import platform as pt
from cvxpy import *
from math import cos, sin
from numpy.linalg import inv, norm
from itertools import product
from __future__ import print_function
from __future__ import division
np.set_printoptions(precision=10)
# software versions
print('cvxpy:'+cvxpy.__version__)
print('numpy:'+np.__version__)
print('pandas:'+pd.__version__)
print('python:'+pt.python_version())
cvxpy:1.0.1 numpy:1.16.3 pandas:0.24.2 python:2.7.16
This FDSLRM application describes the real time series data set representing total weekly number of cyber attacks against a honeynet -- an unconventional tool which mimics real systems connected to Internet like business or school computers intranets to study methods, tools and goals of cyber attackers.
Data, taken from from Sokol, 2017 were collected from November 2014 to May 2016 in CZ.NIC honeynet consisting of Kippo honeypots in medium-interaction mode. The number of time series observations is $n=72$.
The suitable FDSLRM, after a preliminary logarithmic transformation of data $Z(t) = \log X(t)$, is Gaussian orthogonal:
$ \begin{array}{rl} & Z(t) & \! = \! &\beta_1+\beta_2\cos\left(\tfrac{2\pi t\cdot 3}{72}\right)+\beta_3\sin\left(\tfrac{2\pi t\cdot 3}{72}\right)+\beta_4\sin\left(\tfrac{2\pi t\cdot 4}{72}\right) + \\ & & & +Y_1\sin\left(\tfrac{2\pi\ t\cdot 6}{72}\right)+Y_2\sin\left(\tfrac{2\pi\cdot t\cdot 7}{72}\right)+w(t), \, t\in \mathbb{N}, \end{array} $
where $\boldsymbol{\beta}=(\beta_1,\,\beta_2,\,\beta_3,\,\beta_4)' \in \mathbb{R}^4, \mathbf{Y} = (Y_1,Y_2)' \sim \mathcal{N}_2(\boldsymbol{0}, \mathrm{D}), w(t) \sim \mathcal{iid}\, \mathcal{N} (0, \sigma_0^2), \boldsymbol{\nu}= (\sigma_0^2, \sigma_1^2, \sigma_2^2) \in \mathbb{R}_{+}^3$.
We identified the given and most parsimonious structure of the FDSLRM using an iterative process of the model building and selection based on exploratory tools of spectral analysis and residual diagnostics (for details see our Jupyter notebook cyberattacks.ipynb
).
# data - time series observation
path = 'cyberattacks.csv'
data = pd.read_csv(path)
# log of observations x as matrix
x = np.asmatrix(np.log(data.values))
x.shape
(72L, 1L)
# model parameters
n, k, l = 72, 4, 2
# significant frequencies
om1, om2, om3, om4 = 2*np.pi*3/72, 2*np.pi*4/72, 2*np.pi*6/72, 2*np.pi*7/72
# model - design matrices F', F, V',V
Fc = np.mat([[1 for t in range(1,n+1)],
[cos(om1*t) for t in range(1,n+1)],
[sin(om1*t) for t in range(1,n+1)],
[sin(om2*t) for t in range(1,n+1)]])
Vc = np.mat([[sin(om3*t) for t in range(1,n+1)],
[sin(om4*t) for t in range(1,n+1)]])
F, V = Fc.T, Vc.T
# columns vj of V and their squared norm ||vj||^2
vv = lambda j: V[:,j-1]
nv2 = lambda j: np.trace(vv(j).T*vv(j))
# auxiliary matrices and vectors
# Gram matrices GF, GV
GF, GV = Fc*F, Vc*V
InvGF, InvGV = inv(GF), inv(GV)
# projectors PF, MF, PV, MV
In = np.identity(n)
PF = F*InvGF*Fc
PV = V*InvGV*Vc
MF, MV = In-PF, In-PV
# residuals e, e'
e = MF*x
ec = e.T
# orthogonality condition
Fc*V, GV
(matrix([[ 1.4024722673e-16, 1.7287362306e-16], [ 2.6382490321e-15, 5.6684775950e-15], [ 5.1625370645e-15, 1.0630385461e-14], [-5.3845816694e-15, 2.7478019859e-15]]), matrix([[ 3.6000000000e+01, -4.6629367034e-15], [-4.6629367034e-15, 3.6000000000e+01]]))
using formula (4.1) from Hancova et al 2019
$
\renewcommand{\arraystretch}{1.4} \breve{\boldsymbol{\nu}}(\mathbf{e}) = \begin{pmatrix} \tfrac{1}{n-k-l}\,\mathbf{e}'\,\mathrm{M_V}\,\mathbf{e} \\ (\mathbf{e}'\mathbf{v}_1)^2/||\mathbf{v}_1||^4 \\ \vdots \\ (\mathbf{e}'\mathbf{v}_l)^2/||\mathbf{v}_l||^4 \end{pmatrix} $
# NE according to formula (4.1)
NE0 = [1/(n-k-l)*np.trace(ec*MV*e)]
NEj = [(np.trace(ec*vv(j))/nv2(j))**2 for j in range(1,l+1)]
NE = NE0+NEj
print(NE, norm(NE))
[0.059342012638689975, 0.02547467738230785, 0.015495329728874086] 0.06641188820647728
NE as a convex optimization problem
\begin{array}{ll} \textit{minimize} & \quad f_0(\boldsymbol{\nu})=||\mathbf{e}\mathbf{e}' - \mathrm{VDV'}||^2+||\mathrm{M_V}\mathbf{e}\mathbf{e}'\mathrm{M_V}-\nu_0\mathrm{M_F}\mathrm{M_V}||^2 \\[6pt] \textit{subject to} & \quad \boldsymbol{\nu} = \left(\nu_0, \ldots, \nu_l\right)'\in [0, \infty)^{l+1} \end{array}$
$
# the optimization variable, objective function
v = Variable(l+1)
fv = sum_squares(e*ec-V*diag(v[1:])*Vc)+sum_squares(MV*e*ec*MV-v[0]*MF*MV)
# the optimization problem for NE
objective = Minimize(fv)
constraints = [v >= 0]
prob = Problem(objective,constraints)
# solve the NE problem
prob.solve()
NEcvx = v.value
print('NEcvx =', NEcvx, ' norm = ', norm(NEcvx))
C:\Users\jozef\Anaconda3\envs\py27\lib\site-packages\cvxpy\problems\problem.py:609: RuntimeWarning: overflow encountered in long_scalars if self.max_big_small_squared < big*small**2: C:\Users\jozef\Anaconda3\envs\py27\lib\site-packages\cvxpy\problems\problem.py:610: RuntimeWarning: overflow encountered in long_scalars self.max_big_small_squared = big*small**2
NEcvx = [0.0593420126 0.0254746774 0.0154953297] norm = 0.06641188820647728
using formula (3.10) from Hancova et al 2019.
$
\mathring{\nu}_j = \rho_j^2 \breve{\nu}_j; j = 0,1 \ldots, l\ \rho_0 = 1, \rho_j = \dfrac{\hat{\nu}_j||\mathbf{v}_j||^2}{\hat{\nu}_0+\hat{\nu}_j||\mathbf{v}_j||^2} $
where $\boldsymbol{\breve{\nu}}$ are NE, $\boldsymbol{\hat{\nu}}$ are initial estimates for EBLUP-NE
# EBLUP-NE based on formula (3.9)
rho2 = lambda est: [1]+ [ (est[j]*nv2(j)/(est[0]+est[j]*nv2(j)))**2 for j in range(1,l+1) ]
EBLUPNE = lambda est: [rho2(est)[j]*NE[j] for j in range(l+1)]
# numerical results
print(rho2(NE))
[1, 0.88214464875427, 0.8169426439141592]
print(EBLUPNE(NE),norm(EBLUPNE(NE)))
[0.059342012638689975, 0.022472350331544304, 0.012658795637028068] 0.06470491558153942
using formula (3.6) for general FDSLRM from Hancova et al 2019.
$
\mathring{\nu}_0 = \breve{\nu}_0, \mathring{\nu}_j = (\mathbf{Y}^)_j^2, j = 1, 2, \ldots, l \ \mathbf{Y}^ = \mathbb{T}\mathbf{X} \mbox{ with } \mathbb{T} = \mathrm{D}\mathbb{U}^{-1}\mathrm{V}'\mathrm{M_F}, \mathbb{U} = \mathrm{V}'\mathrm{M_F}\mathrm{V}\mathrm{D} + \nu_0 \mathrm{I}_l $
def EBLUPNEgen(est):
D = np.diag(est[1:])
U = Vc*MF*V*D + est[0]*np.identity(l)
T = D*inv(U)*Vc*MF
eest = np.vstack((np.matrix(NE[0]),np.multiply(T*x, T*x)))
return np.array(eest).flatten().tolist()
print(EBLUPNEgen(NE), norm(EBLUPNEgen(NE)))
[0.059342012638689975, 0.02247235033154422, 0.01265879563702813] 0.06470491558153939
using the the KKT algorithm (tab.3, Hancova et al 2019)
$~$
$
\qquad \mathbf{q} = \left(\begin{array}{c} \mathbf{e}' \mathbf{e}\\ (\mathbf{e}' \mathbf{v}_{1})^2 \\ \vdots \\ (\mathbf{e}' \mathbf{v}_{l})^2 \end{array}\right) $
$\qquad\mathrm{G} = \left(\begin{array}{ccccc}
\small n^* & ||\mathbf{v}{1}||^2 & ||\mathbf{v}{2}||^2 & \ldots & ||\mathbf{v}{l}||^2 \ ||\mathbf{v}{1}||^2 & ||\mathbf{v}{1}||^4 & 0 & \ldots & 0 \ ||\mathbf{v}{2}||^2 & 0 & ||\mathbf{v}{2}||^4 & \ldots & 0 \ \vdots & \vdots & \vdots & \ldots & \vdots \ ||\mathbf{v}{l}||^2 & 0 & 0 & \ldots & ||\mathbf{v}_{l}||^4 \end{array}\right) $
# Input: form G
ns, nvj = n, norm(V, axis=0)
u, v, Q = np.mat(ns), np.mat(nvj**2), np.diag(nvj**4)
G = np.bmat([[u,v],[v.T,Q]])
# form q
e2, Ve2 = ec*e, np.multiply(Vc*e, Vc*e)
q = np.vstack((e2, Ve2))
# body of the algorithm
for b in product([0,1], repeat=l):
# set the KKT-conditions matrix K
K = G*1
for j in range(1,l+1):
if b[j-1] == 0: K[0,j], K[j,j] = 0,-1
# calculate the auxiliary vector g
g = inv(K)*q
# test non-negativity g
if (g >= 0).all(): break
# Output: Form estimates nu
nu = g*1
for j in range(1,l+1):
if b[j-1] == 0: nu[j] = 0
NN_DOOLSE = np.array(nu).flatten()
print(NN_DOOLSE, norm(NN_DOOLSE),b)
[0.0559510405 0.0239204818 0.0139411342] 0.062426465569625715 (1, 1)
nonnegative DOOLSE as a convex optimization problem
\begin{array}{ll} \textit{minimize} & f_0(\boldsymbol{\nu})=||\mathbf{e}\mathbf{e}'-\Sigma_\boldsymbol{\nu}||^2 \\[6pt] \textit{subject to} & \boldsymbol{\nu} = \left(\nu_0, \ldots, \nu_l\right)'\in [0, \infty)^{l+1} \end{array}$
$
# set the optimization variable, objective function
v = Variable(l+1)
fv = sum_squares(e*e.T - v[0]*In - V*diag(v[1:])*V.T)
# construct the problem for DOOLSE
objective = Minimize(fv)
constraints = [v >= 0]
prob = Problem(objective,constraints)
# solve the DOOLSE problem
prob.solve()
NN_DOOLSEcvx = v.value
print('NN-DOOLSEcvx =', NN_DOOLSEcvx, 'norm =', norm(NN_DOOLSEcvx))
NN-DOOLSEcvx = [0.0559510405 0.0239204818 0.0139411342] norm = 0.06242646556962571
using equivalent (RE)MLE convex problem (proposition 5, Hancova et al 2019)
\begin{array}{ll} \textit{minimize} & \quad f_0(\mathbf{d})=-(n^*\!-l)\ln d_0 - \displaystyle\sum\limits_{j=1}^{l} \ln(d_0-d_j||\mathbf{v}_j||^2+d_0\mathbf{e}'\mathbf{e}-\mathbf{e}'\mathrm{V}\,\mathrm{diag}\{d_j\}\mathrm{V}'\mathbf{e} \\[6pt] \textit{subject to} & \quad d_0 > \max\{d_j||\mathbf{v}_j||^2, j = 1, \ldots, l\} \\ & \quad d_j \geq 0, j=1,\ldots l \\ & \\ & \quad\text{for MLE: } n^* = n, \text{ for REMLE: } n^* = n-k \\ \textit{back transformation:} & \quad \nu_0 = \dfrac{1}{d_0}, \nu_j = \dfrac{d_j}{d_0\left(d_0 -d_j||\mathbf{v}_j||^2\right)} \end{array}$
$
# set variables for the objective
ns = n
d = Variable(l+1)
logdetS = (ns-l)*log(d[0])+sum(log(d[0]-GV*d[1:]))
# construct the problem
objective = Maximize(logdetS-(d[0]*ec*e-ec*V*diag(d[1:])*Vc*e))
constraints = [0 <= d[1:], max(GV*d[1:]) <= d[0]]
prob = Problem(objective,constraints)
# solve the problem
solution = prob.solve()
dv = d.value.tolist()
# back transformation
s0 = [1/dv[0]]
sj = [dv[i]/(dv[0]*(dv[0]-dv[i]*GV[i-1,i-1])) for i in range(1,l+1)]
sv = s0+sj
print('MLEcvx = ', sv, ' norm = ', norm(sv))
MLEcvx = [0.05595104070567166, 0.023920500360518803, 0.013941147758383572] norm = 0.062426475908594986
# numerical results
print(rho2(NN_DOOLSE))
[1, 0.8817032888843341, 0.809458464559698]
print(EBLUPNE(NN_DOOLSE),norm(EBLUPNE(NN_DOOLSE)))
[0.059342012638689975, 0.02246110683124819, 0.012542825810180661] 0.06467842193034488
#cross-checking
print(EBLUPNEgen(NN_DOOLSE), norm(EBLUPNEgen(NN_DOOLSE)))
[0.059342012638689975, 0.022461106831248145, 0.012542825810180742] 0.06467842193034488
using the KKT algorithm (tab.3, Hancova et al 2019)
# Input: form G
ns, nvj = n-k, norm(V, axis=0)
u, v, Q = np.mat(ns), np.mat(nvj**2), np.diag(nvj**4)
G = np.bmat([[u,v],[v.T,Q]])
# form q
e2, Ve2 = ec*e, np.multiply(Vc*e, Vc*e)
q = np.vstack((e2, Ve2))
# body of the algorithm
for b in product([0,1], repeat=l):
# set the KKT-conditions matrix K
K = G*1
for j in range(1,l+1):
if b[j-1] == 0: K[0,j], K[j,j] = 0,-1
# calculate the auxiliary vector g
g = inv(K)*q
# test non-negativity g
if (g >= 0).all(): break
# Output: Form estimates nu
nu = g*1
for j in range(1,l+1):
if b[j-1] == 0: nu[j] = 0
NN_MDOOLSE = np.array(nu).flatten()
print(NN_MDOOLSE, norm(NN_MDOOLSE),b)
[0.0593420126 0.0238262881 0.0138469405] 0.06542861936152926 (1, 1)
nu.dtype
dtype('float64')
nonnegative DOOLSE as a convex optimization problem
\begin{array}{ll} \textit{minimize} & f_0(\boldsymbol{\nu})=||\mathbf{e}\mathbf{e}'-\mathrm{M_F}\Sigma_\boldsymbol{\nu}\mathrm{M_F}||^2 \\[6pt] \textit{subject to} & \boldsymbol{\nu} = \left(\nu_0, \ldots, \nu_l\right)'\in [0, \infty)^{l+1} \end{array}$
$
# the optimization variable, objective function
v = Variable(l+1)
fv = sum_squares(e*ec - v[0]*MF - V*diag(v[1:])*Vc)
# the optimization problem for MDOOLSE
objective = Minimize(fv)
constraints = [v >= 0]
prob = Problem(objective,constraints)
# solve the MDOOLSE problem
prob.solve()
NN_MDOOLSEcvx = v.value
print('NN-MDOOLSEcvx =', NN_MDOOLSEcvx, 'norm =', norm(NN_MDOOLSEcvx) )
NN-MDOOLSEcvx = [0.0593420126 0.0238262881 0.0138469405] norm = 0.06542861936152927
using equivalent (RE)MLE convex problem (proposition 5, Hancova et al 2019)
\begin{array}{ll} \textit{minimize} & \quad f_0(\mathbf{d})=-(n^*\!-l)\ln d_0 - \displaystyle\sum\limits_{j=1}^{l} \ln(d_0-d_j||\mathbf{v}_j||^2+d_0\mathbf{e}'\mathbf{e}-\mathbf{e}'\mathrm{V}\,\mathrm{diag}\{d_j\}\mathrm{V}'\mathbf{e} \\[6pt] \textit{subject to} & \quad d_0 > \max\{d_j||\mathbf{v}_j||^2, j = 1, \ldots, l\} \\ & \quad d_j \geq 0, j=1,\ldots l \\ & \\ & \quad\text{for MLE: } n^* = n, \text{ for REMLE: } n^* = n-k \\ \textit{back transformation:} & \quad \nu_0 = \dfrac{1}{d_0}, \nu_j = \dfrac{d_j}{d_0\left(d_0 -d_j||\mathbf{v}_j||^2\right)} \end{array}$
$
# set variables for the objective
ns = n - k
d = Variable(l+1)
logdetS = (ns-l)*log(d[0])+sum(log(d[0]-GV*d[1:]))
# construct the problem
objective = Maximize(logdetS-(d[0]*ec*e-ec*V*diag(d[1:])*Vc*e))
constraints = [0 <= d[1:], max(GV*d[1:]) <= d[0]]
prob = Problem(objective,constraints)
# solve the problem
solution = prob.solve()
dv = d.value.tolist()
# back transformation
s0 = [1/dv[0]]
sj = [dv[i]/(dv[0]*(dv[0]-dv[i]*GV[i-1,i-1])) for i in range(1,l+1)]
sv = s0+sj
print('REMLEcvx = ', sv, ' norm = ', norm(sv))
REMLEcvx = [0.059342015683809674, 0.0238262991597481, 0.013846952971800199] norm = 0.06542862877724531
# numerical results
print(rho2(NN_MDOOLSE))
[1, 0.8747730479406809, 0.7985571584490208]
print(EBLUPNE(NN_MDOOLSE),norm(EBLUPNE(NN_MDOOLSE)))
[0.059342012638689975, 0.022284561179026965, 0.012373906477520326] 0.06458474814123422
#cross-checking
print(EBLUPNEgen(NN_MDOOLSE), norm(EBLUPNEgen(NN_MDOOLSE)))
[0.059342012638689975, 0.02228456117902675, 0.012373906477520492] 0.06458474814123417
This notebook belongs to suplementary materials of the paper submitted to Statistical Papers and available at https://arxiv.org/abs/1905.07771.
We propose a two-stage estimation method of variance components in time series models known as FDSLRMs, whose observations can be described by a linear mixed model (LMM). We based estimating variances, fundamental quantities in a time series forecasting approach called kriging, on the empirical (plug-in) best linear unbiased predictions of unobservable random components in FDSLRM.
The method, providing invariant non-negative quadratic estimators, can be used for any absolutely continuous probability distribution of time series data. As a result of applying the convex optimization and the LMM methodology, we resolved two problems $-$ theoretical existence and equivalence between least squares estimators, non-negative (M)DOOLSE, and maximum likelihood estimators, (RE)MLE, as possible starting points of our method and a practical lack of computational implementation for FDSLRM. As for computing (RE)MLE in the case of $ n $ observed time series values, we also discovered a new algorithm of order $\mathcal{O}(n)$, which at the default precision is $10^7$ times more accurate and $n^2$ times faster than the best current Python(or R)-based computational packages, namely CVXPY, CVXR, nlme, sommer and mixed.
We illustrate our results on three real data sets $-$ electricity consumption, tourism and cyber security $-$ which are easily available, reproducible, sharable and modifiable in the form of interactive Jupyter notebooks.