tsdr 0.1__tar.gz → 0.2__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.
- {tsdr-0.1 → tsdr-0.2}/PKG-INFO +3 -3
- {tsdr-0.1 → tsdr-0.2}/README.md +2 -2
- {tsdr-0.1 → tsdr-0.2}/pyproject.toml +1 -1
- {tsdr-0.1 → tsdr-0.2}/tsdr/autocorrelation.py +9 -8
- {tsdr-0.1 → tsdr-0.2}/tsdr/diffusion.py +8 -6
- {tsdr-0.1 → tsdr-0.2}/tsdr/latentvariable.py +4 -2
- {tsdr-0.1 → tsdr-0.2}/tsdr/nonstationarity.py +10 -10
- {tsdr-0.1 → tsdr-0.2}/tsdr/predictability.py +8 -10
- {tsdr-0.1 → tsdr-0.2}/LICENSE.txt +0 -0
- {tsdr-0.1 → tsdr-0.2}/tsdr/.DS_Store +0 -0
- {tsdr-0.1 → tsdr-0.2}/tsdr/__init__.py +0 -0
- {tsdr-0.1 → tsdr-0.2}/tsdr/determinism.py +0 -0
- {tsdr-0.1 → tsdr-0.2}/tsdr/slowness.py +0 -0
{tsdr-0.1 → tsdr-0.2}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: tsdr
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2
|
|
4
4
|
Summary: Time-series dimension reduction
|
|
5
5
|
Author-Email: Kieran S Owens <kowe6911@uni.sydney.edu.au>
|
|
6
6
|
Maintainer-Email: Kieran S Owens <kowe6911@uni.sydney.edu.au>
|
|
@@ -27,9 +27,9 @@ Description-Content-Type: text/markdown
|
|
|
27
27
|
|
|
28
28
|
## About
|
|
29
29
|
|
|
30
|
-
Time-series dimension reduction (TSDR) methods are a class of algorithms for the dimension reduction of multivariate data that exploit temporal structure.
|
|
30
|
+
Time-series dimension reduction (TSDR) methods are a class of algorithms for the dimension reduction of multivariate data that exploit temporal structure. In contrast to general dimension reduction (GDR) methods, the outputs of which are invariant to temporal permutation, TSDR methods are sensitive to temporal structure.
|
|
31
31
|
|
|
32
|
-
The figure above visually summarises the categories of TSDR methods that we defined in Owens & Fulcher (2025). The first five categories (a-e) consist of methods that extract time-series components based on different aspects of temporal structure, i.e., slowness, autocorrelation, predictability, determinism, and non-stationarity. The final two categories (f-g) consist of methods that share a common methodology, i.e., diffusion-based and
|
|
32
|
+
The figure above visually summarises the categories of TSDR methods that we defined in Owens & Fulcher (2025). The first five categories (a-e) consist of methods that extract time-series components based on different aspects of temporal structure, i.e., slowness, autocorrelation, predictability, determinism, and non-stationarity. The final two categories (f-g) consist of methods that share a common methodology, i.e., diffusion-based and latent variable methods.
|
|
33
33
|
|
|
34
34
|
The <em>tsdr</em> package provides python implementations of TSDR methods from each of these seven categories. The methods are written in a simple, readable style to enable time-series analysts to better understand a subset of the TSDR methods discussed in the Owens & Fulcher (2025) review paper.
|
|
35
35
|
|
{tsdr-0.1 → tsdr-0.2}/README.md
RENAMED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
|
|
11
11
|
## About
|
|
12
12
|
|
|
13
|
-
Time-series dimension reduction (TSDR) methods are a class of algorithms for the dimension reduction of multivariate data that exploit temporal structure.
|
|
13
|
+
Time-series dimension reduction (TSDR) methods are a class of algorithms for the dimension reduction of multivariate data that exploit temporal structure. In contrast to general dimension reduction (GDR) methods, the outputs of which are invariant to temporal permutation, TSDR methods are sensitive to temporal structure.
|
|
14
14
|
|
|
15
|
-
The figure above visually summarises the categories of TSDR methods that we defined in Owens & Fulcher (2025). The first five categories (a-e) consist of methods that extract time-series components based on different aspects of temporal structure, i.e., slowness, autocorrelation, predictability, determinism, and non-stationarity. The final two categories (f-g) consist of methods that share a common methodology, i.e., diffusion-based and
|
|
15
|
+
The figure above visually summarises the categories of TSDR methods that we defined in Owens & Fulcher (2025). The first five categories (a-e) consist of methods that extract time-series components based on different aspects of temporal structure, i.e., slowness, autocorrelation, predictability, determinism, and non-stationarity. The final two categories (f-g) consist of methods that share a common methodology, i.e., diffusion-based and latent variable methods.
|
|
16
16
|
|
|
17
17
|
The <em>tsdr</em> package provides python implementations of TSDR methods from each of these seven categories. The methods are written in a simple, readable style to enable time-series analysts to better understand a subset of the TSDR methods discussed in the Owens & Fulcher (2025) review paper.
|
|
18
18
|
|
|
@@ -480,8 +480,9 @@ class CSA():
|
|
|
480
480
|
The dimension (number of variables) of the time-series output.
|
|
481
481
|
Default: 1.
|
|
482
482
|
|
|
483
|
-
lag: int
|
|
484
|
-
The maximum time lag at which to compute autocorrelation
|
|
483
|
+
lag: int or list
|
|
484
|
+
The maximum time lag at which to compute autocorrelation,
|
|
485
|
+
or else a list of specified lags.
|
|
485
486
|
Default: 1.
|
|
486
487
|
|
|
487
488
|
method: str
|
|
@@ -497,13 +498,13 @@ class CSA():
|
|
|
497
498
|
to the input time series X.
|
|
498
499
|
"""
|
|
499
500
|
|
|
500
|
-
def __init__(self, n_components=1,
|
|
501
|
+
def __init__(self, n_components=1, lag=2, max_iters=1000):
|
|
501
502
|
|
|
502
503
|
self.n_components = n_components
|
|
503
|
-
if isinstance(
|
|
504
|
-
self.lags = range(1,
|
|
505
|
-
elif isinstance(
|
|
506
|
-
self.lags =
|
|
504
|
+
if isinstance(lag, int):
|
|
505
|
+
self.lags = range(1, lag+1)
|
|
506
|
+
elif isinstance(lag, list):
|
|
507
|
+
self.lags = list(lag)
|
|
507
508
|
self.max_iters = max_iters
|
|
508
509
|
|
|
509
510
|
def fit(self, X, y=None):
|
|
@@ -661,7 +662,7 @@ class sPCA_dwt():
|
|
|
661
662
|
|
|
662
663
|
whiten: bool
|
|
663
664
|
Whether to whiten the data.
|
|
664
|
-
Default:
|
|
665
|
+
Default: True
|
|
665
666
|
|
|
666
667
|
method: str
|
|
667
668
|
Whether to use PCA or SVD. Options: 'pca' or 'svd'.
|
|
@@ -156,12 +156,12 @@ class DMcov():
|
|
|
156
156
|
Wnorm = D_neg_root @ W @ D_neg_root
|
|
157
157
|
|
|
158
158
|
# eigendecomposition
|
|
159
|
-
_, eigvecs = np.linalg.
|
|
159
|
+
_, eigvecs = np.linalg.eigh(Wnorm)
|
|
160
160
|
|
|
161
161
|
else:
|
|
162
162
|
|
|
163
163
|
# eigendecomposition
|
|
164
|
-
_, eigvecs = np.linalg.
|
|
164
|
+
_, eigvecs = np.linalg.eigh(D - W)
|
|
165
165
|
|
|
166
166
|
self.components = eigvecs[:,1:1+self.n_components]
|
|
167
167
|
|
|
@@ -292,8 +292,10 @@ class DIG():
|
|
|
292
292
|
for i in range(D):
|
|
293
293
|
for j in range(D):
|
|
294
294
|
if i != j:
|
|
295
|
-
W[i,j] += 0.5*(np.exp(-G[i,j]/knn_k[i])**self.alpha)
|
|
296
|
-
W[i,j] += 0.5*(np.exp(-G[i,j]/knn_k[j])**self.alpha)
|
|
295
|
+
# W[i,j] += 0.5*(np.exp(-G[i,j]/knn_k[i])**self.alpha)
|
|
296
|
+
# W[i,j] += 0.5*(np.exp(-G[i,j]/knn_k[j])**self.alpha)
|
|
297
|
+
W[i,j] += 0.5*np.exp(-(G[i,j]/knn_k[i])**self.alpha)
|
|
298
|
+
W[i,j] += 0.5*np.exp(-(G[i,j]/knn_k[j])**self.alpha)
|
|
297
299
|
|
|
298
300
|
return W
|
|
299
301
|
|
|
@@ -311,7 +313,7 @@ class DIG():
|
|
|
311
313
|
|
|
312
314
|
kneedle = KneeLocator(range(1, self.tmax + 1), vne,
|
|
313
315
|
S=1.0, curve='convex', direction='decreasing')
|
|
314
|
-
return int(kneedle.elbow)
|
|
316
|
+
return int(kneedle.elbow) if kneedle.elbow is not None else self.tmax//2
|
|
315
317
|
|
|
316
318
|
# computation of information distance
|
|
317
319
|
def _information_distance(self, W):
|
|
@@ -332,7 +334,7 @@ class DIG():
|
|
|
332
334
|
|
|
333
335
|
N = D.shape[0]
|
|
334
336
|
H = np.eye(N) - np.ones((N, N)) / N
|
|
335
|
-
K = -0.5 * (H @ D @ H)
|
|
337
|
+
K = -0.5 * (H @ (D **2) @ H)
|
|
336
338
|
eigenvals, eigenvecs = np.linalg.eigh(K)
|
|
337
339
|
eigenvals_sorted = eigenvals.argsort()[::-1]
|
|
338
340
|
idxs = eigenvals_sorted[:self.n_components]
|
|
@@ -140,6 +140,7 @@ class LDS():
|
|
|
140
140
|
|
|
141
141
|
# Sum expectations over time
|
|
142
142
|
sum_Exx = Exx.sum(axis=0) # \sum_t E[x_t x_t^T]
|
|
143
|
+
sum_Exx0 = Exx[:-1].sum(axis=0) # sum_{t=1}^{T-1}
|
|
143
144
|
sum_Exx1 = Exx[1:].sum(axis=0) # \sum_{t=2}^T E[x_t x_t^T]
|
|
144
145
|
sum_Exxm1 = Exxm1.sum(axis=0) # \sum_{t=2}^T E[x_t x_{t-1}^T]
|
|
145
146
|
|
|
@@ -147,11 +148,12 @@ class LDS():
|
|
|
147
148
|
if self.constrain_A_identity:
|
|
148
149
|
A = np.eye(d)
|
|
149
150
|
else:
|
|
150
|
-
A = sum_Exxm1 @ pinv(
|
|
151
|
+
A = sum_Exxm1 @ pinv(sum_Exx0)
|
|
151
152
|
|
|
152
153
|
# Update the latent state noise covariance matrix Q, Eq. (20)
|
|
153
154
|
# and enforce symmetry
|
|
154
|
-
Q = (sum_Exx1 - A @ sum_Exxm1.T) / (T - 1)
|
|
155
|
+
#Q = (sum_Exx1 - A @ sum_Exxm1.T) / (T - 1)
|
|
156
|
+
Q = (sum_Exx1 - A @ sum_Exxm1.T - sum_Exxm1 @ A.T + A @ sum_Exx0 @ A.T) / (T - 1)
|
|
155
157
|
Q = (Q + Q.T) / 2
|
|
156
158
|
|
|
157
159
|
# Update the output/Observation matrix C, Eq. (14)
|
|
@@ -118,7 +118,7 @@ class ASSA():
|
|
|
118
118
|
S = self._compute_S(Xw)
|
|
119
119
|
|
|
120
120
|
# eigendecomposition of S
|
|
121
|
-
eigvals, eigvecs = np.linalg.
|
|
121
|
+
eigvals, eigvecs = np.linalg.eigh(S)
|
|
122
122
|
eigvecs_sorted = eigvecs[:,np.argsort(eigvals)]
|
|
123
123
|
|
|
124
124
|
# eigenvalues
|
|
@@ -269,7 +269,7 @@ class SSAsir():
|
|
|
269
269
|
Mm = self._compute_Mm(Xw)
|
|
270
270
|
|
|
271
271
|
# eigendecomposition of S
|
|
272
|
-
eigvals, eigvecs = np.linalg.
|
|
272
|
+
eigvals, eigvecs = np.linalg.eigh(Mm)
|
|
273
273
|
eigvecs_sorted = eigvecs[:,np.argsort(eigvals)]
|
|
274
274
|
|
|
275
275
|
# get linear transformation
|
|
@@ -417,7 +417,7 @@ class SSAsave():
|
|
|
417
417
|
Mv = self._compute_Mv(Xw)
|
|
418
418
|
|
|
419
419
|
# eigendecomposition of S
|
|
420
|
-
eigvals, eigvecs = np.linalg.
|
|
420
|
+
eigvals, eigvecs = np.linalg.eigh(Mv)
|
|
421
421
|
eigvecs_sorted = eigvecs[:,np.argsort(eigvals)]
|
|
422
422
|
|
|
423
423
|
# get linear transformation
|
|
@@ -575,7 +575,7 @@ class SSAcor():
|
|
|
575
575
|
Mtau = self._compute_Mtau(Xw)
|
|
576
576
|
|
|
577
577
|
# eigendecomposition of S
|
|
578
|
-
eigvals, eigvecs = np.linalg.
|
|
578
|
+
eigvals, eigvecs = np.linalg.eigh(Mtau)
|
|
579
579
|
eigvecs_sorted = eigvecs[:,np.argsort(eigvals)]
|
|
580
580
|
|
|
581
581
|
# get linear transformation
|
|
@@ -777,7 +777,7 @@ class WaSSAf():
|
|
|
777
777
|
S = self._compute_S(Xw)
|
|
778
778
|
|
|
779
779
|
# eigendecomposition of S
|
|
780
|
-
eigvals, eigvecs = np.linalg.
|
|
780
|
+
eigvals, eigvecs = np.linalg.eigh(S)
|
|
781
781
|
eigvecs_sorted = eigvecs[:,np.argsort(eigvals)]
|
|
782
782
|
|
|
783
783
|
# get linear transformation
|
|
@@ -937,7 +937,7 @@ class WaSSAr():
|
|
|
937
937
|
S = self._compute_S(Xw)
|
|
938
938
|
|
|
939
939
|
# eigendecomposition of S
|
|
940
|
-
eigvals, eigvecs = np.linalg.
|
|
940
|
+
eigvals, eigvecs = np.linalg.eigh(S)
|
|
941
941
|
eigvecs_sorted = eigvecs[:,np.argsort(eigvals)]
|
|
942
942
|
|
|
943
943
|
# get linear transformation
|
|
@@ -1067,7 +1067,7 @@ class BSSnonstat():
|
|
|
1067
1067
|
T, D = X0.shape
|
|
1068
1068
|
|
|
1069
1069
|
# matrix used during optimisation
|
|
1070
|
-
M = X0.T @ Xlag + Xlag.T @ X0
|
|
1070
|
+
M = (X0.T @ Xlag + Xlag.T @ X0) / T
|
|
1071
1071
|
|
|
1072
1072
|
# collect projection vectors
|
|
1073
1073
|
W = []
|
|
@@ -1084,12 +1084,12 @@ class BSSnonstat():
|
|
|
1084
1084
|
e1 = np.zeros(shape=w.shape)
|
|
1085
1085
|
e2 = np.zeros(shape=w.shape)
|
|
1086
1086
|
|
|
1087
|
-
for i in range(T
|
|
1087
|
+
for i in range(T):
|
|
1088
1088
|
ztau = Xlag[i,:].reshape(-1,1)
|
|
1089
1089
|
zt = X0[i,:].reshape(-1,1)
|
|
1090
1090
|
|
|
1091
|
-
e1 += (zt @ w.T @ zt @ (w.T @ ztau)**2)/
|
|
1092
|
-
e2 += (ztau @ w.T @ ztau @ (w.T @ zt)**2) /
|
|
1091
|
+
e1 += (zt @ w.T @ zt @ (w.T @ ztau)**2)/T
|
|
1092
|
+
e2 += (ztau @ w.T @ ztau @ (w.T @ zt)**2) / T
|
|
1093
1093
|
|
|
1094
1094
|
w = e1 + e2 - 2*w - M @ w @ (w.T @ M @ w)
|
|
1095
1095
|
w = w / np.linalg.norm(w)
|
|
@@ -95,7 +95,7 @@ class TLPC():
|
|
|
95
95
|
Sigma = Ctau @ np.linalg.pinv(C0)
|
|
96
96
|
|
|
97
97
|
# eigendecomposition of I - Sigma^2
|
|
98
|
-
eigvals, eigvecs = np.linalg.eig(np.eye(Sigma.shape[0]) - Sigma @ Sigma)
|
|
98
|
+
eigvals, eigvecs = np.real(np.linalg.eig(np.eye(Sigma.shape[0]) - Sigma @ Sigma))
|
|
99
99
|
eigvecs_sorted = eigvecs[:,np.argsort(eigvals)]
|
|
100
100
|
|
|
101
101
|
# get linear transformation
|
|
@@ -244,18 +244,17 @@ class PrCA():
|
|
|
244
244
|
|
|
245
245
|
else:
|
|
246
246
|
|
|
247
|
-
#
|
|
248
|
-
E = np.zeros((T - (self.p + self.lag), D))
|
|
247
|
+
# prediction errors have T - (p + lag - 1) rows
|
|
248
|
+
E = np.zeros((T - (self.p + self.lag - 1), D))
|
|
249
249
|
|
|
250
|
-
# for each feature/variable
|
|
251
250
|
for i in range(D):
|
|
252
251
|
|
|
253
252
|
# data to use for predictions
|
|
254
253
|
x = X[:,i]
|
|
255
|
-
x_p = self._tde(x[:-
|
|
254
|
+
x_p = self._tde(x[:-self.lag].reshape(-1,1), self.p, 1) # drop last `lag` points
|
|
256
255
|
|
|
257
256
|
# data to predict
|
|
258
|
-
y = x[self.p + self.lag:]
|
|
257
|
+
y = x[self.p - 1 + self.lag:]
|
|
259
258
|
|
|
260
259
|
# fit a model using x_p and y
|
|
261
260
|
if self.model == 'linear_reg':
|
|
@@ -426,12 +425,11 @@ class DiCCA():
|
|
|
426
425
|
# initialise AR weights beta
|
|
427
426
|
beta = np.eye(self.s)[:,0]
|
|
428
427
|
|
|
429
|
-
# prediction (Ubeta) and prediction error (Utilde)
|
|
430
|
-
Ubeta = sum([U_list[i]*beta[i] for i in range(self.s)])
|
|
431
|
-
Utilde = Us - Ubeta
|
|
432
|
-
|
|
433
428
|
# iteratively optimize transformation w and AR weights beta
|
|
434
429
|
for _ in range(100):
|
|
430
|
+
# prediction (Ubeta) and prediction error (Utilde)
|
|
431
|
+
Ubeta = sum([U_list[i]*beta[i] for i in range(self.s)])
|
|
432
|
+
Utilde = Us - Ubeta
|
|
435
433
|
w = PCA().fit(Utilde).components_.T[:,-1]
|
|
436
434
|
t = U @ w
|
|
437
435
|
Ts = [beta[0] * U_list[0] @ w]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|