complexeva 0.1.5__tar.gz → 0.1.7__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.
- {complexeva-0.1.5 → complexeva-0.1.7}/PKG-INFO +1 -1
- complexeva-0.1.7/complexeva/measures/__init__.py +6 -0
- complexeva-0.1.7/complexeva/measures/dimension_1/__init__.py +0 -0
- {complexeva-0.1.5/complexeva/measures → complexeva-0.1.7/complexeva/measures/dimension_1}/higuchi.py +4 -4
- complexeva-0.1.7/complexeva/measures/dimension_1/lempel_ziv.py +201 -0
- complexeva-0.1.7/complexeva/measures/dimension_2/__init__.py +0 -0
- complexeva-0.1.7/complexeva/measures/network_space/__init__.py +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva/measures/validate.py +13 -7
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva.egg-info/PKG-INFO +1 -1
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva.egg-info/SOURCES.txt +7 -4
- {complexeva-0.1.5 → complexeva-0.1.7}/setup.py +1 -1
- complexeva-0.1.5/complexeva/measures/__init__.py +0 -5
- complexeva-0.1.5/complexeva/measures/co_activation.py +0 -100
- {complexeva-0.1.5 → complexeva-0.1.7}/README.md +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva/__init__.py +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva/dummies/__init__.py +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva/dummies/matrix.py +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva/dummies/networks.py +0 -0
- {complexeva-0.1.5/complexeva/measures → complexeva-0.1.7/complexeva/measures/dimension_2}/cbb_matrix.py +0 -0
- {complexeva-0.1.5/complexeva/measures → complexeva-0.1.7/complexeva/measures/network_space}/cbb_networkx.py +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva/utils/__init__.py +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva/utils/convert_image_matrix.py +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva/utils/convert_matrix_network.py +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva/utils/device.py +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva.egg-info/dependency_links.txt +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/complexeva.egg-info/top_level.txt +0 -0
- {complexeva-0.1.5 → complexeva-0.1.7}/setup.cfg +0 -0
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from .dimension_1.lempel_ziv import lempel_ziv
|
|
2
|
+
from .dimension_1.higuchi import hfd_matlab_equivalent, hfd_pyeeg
|
|
3
|
+
from .dimension_2.cbb_matrix import FractalHandlerMatrix
|
|
4
|
+
from .network_space.cbb_networkx import FractalHandlerNetworkX
|
|
5
|
+
|
|
6
|
+
__all__ = ["lempel_ziv", "hfd_matlab_equivalent", "hfd_pyeeg", "FractalHandlerMatrix", "FractalHandlerNetworkX"]
|
|
File without changes
|
{complexeva-0.1.5/complexeva/measures → complexeva-0.1.7/complexeva/measures/dimension_1}/higuchi.py
RENAMED
|
@@ -8,7 +8,7 @@ from donware import inspect_package
|
|
|
8
8
|
from numba import njit
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
def hfd_matlab_equivalent(data, k_max):
|
|
11
|
+
def hfd_matlab_equivalent(data, k_max=16):
|
|
12
12
|
"""
|
|
13
13
|
[translated from MATLAB code]
|
|
14
14
|
|
|
@@ -37,7 +37,7 @@ def hfd_matlab_equivalent(data, k_max):
|
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
@njit
|
|
40
|
-
def compute_L_x(X, k_max):
|
|
40
|
+
def compute_L_x(X, k_max=16):
|
|
41
41
|
N = len(X)
|
|
42
42
|
L = numpy.zeros(k_max)
|
|
43
43
|
x = numpy.zeros(k_max)
|
|
@@ -55,14 +55,14 @@ def compute_L_x(X, k_max):
|
|
|
55
55
|
return x, L
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
def hfd_pyeeg(X, k_max):
|
|
58
|
+
def hfd_pyeeg(X, k_max=16):
|
|
59
59
|
x, L = compute_L_x(X, k_max)
|
|
60
60
|
A = numpy.column_stack((x, numpy.ones_like(x)))
|
|
61
61
|
beta, _, _, _ = numpy.linalg.lstsq(A, L, rcond=None)
|
|
62
62
|
return beta[0]
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
def _hfd_pyeeg(X, k_max):
|
|
65
|
+
def _hfd_pyeeg(X, k_max=16):
|
|
66
66
|
"""
|
|
67
67
|
[from PyEEG package]
|
|
68
68
|
Higuchi Fractal Dimension of a time series X. kmax is an HFD parameter
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/Users/donyin/miniconda3/envs/rotation-1/bin/python
|
|
2
|
+
|
|
3
|
+
import numpy
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def lempel_ziv(time_series, method="median"):
|
|
7
|
+
"""
|
|
8
|
+
- compared to other implementations, this implementation is makes the most sense
|
|
9
|
+
|
|
10
|
+
Lempel-Ziv complexity as described in Kaspar and Schuster, Phys. Rev. A.
|
|
11
|
+
Counts the number of distinct patterns that need to be copied to reproduce the sequence.
|
|
12
|
+
Returns: int: The number of distinct patterns (complexity measure)
|
|
13
|
+
"""
|
|
14
|
+
sequence = time_series_to_binary(time_series, method=method)
|
|
15
|
+
|
|
16
|
+
history_pos = 0 # Position in history we're comparing against
|
|
17
|
+
current_len = 1 # Length of current pattern we're checking
|
|
18
|
+
max_pattern_len = 1 # Length of longest matching pattern found
|
|
19
|
+
seq_pos = 1 # Current position in sequence
|
|
20
|
+
complexity = 1 # Start with 1 as first character is always a new pattern
|
|
21
|
+
seq_len = len(sequence)
|
|
22
|
+
|
|
23
|
+
while seq_pos + current_len <= seq_len:
|
|
24
|
+
# Check if current pattern matches what's in history
|
|
25
|
+
if sequence[history_pos + current_len - 1] == sequence[seq_pos + current_len - 1]:
|
|
26
|
+
current_len += 1
|
|
27
|
+
else:
|
|
28
|
+
# Update longest matching pattern length if needed
|
|
29
|
+
if current_len > max_pattern_len:
|
|
30
|
+
max_pattern_len = current_len
|
|
31
|
+
|
|
32
|
+
history_pos += 1
|
|
33
|
+
|
|
34
|
+
# If we've checked all history, we found a new pattern
|
|
35
|
+
if history_pos == seq_pos:
|
|
36
|
+
complexity += 1
|
|
37
|
+
seq_pos += max_pattern_len
|
|
38
|
+
|
|
39
|
+
# Reset for next pattern search
|
|
40
|
+
history_pos = 0
|
|
41
|
+
current_len = 1
|
|
42
|
+
max_pattern_len = 1
|
|
43
|
+
else:
|
|
44
|
+
# Try next position in history
|
|
45
|
+
current_len = 1
|
|
46
|
+
|
|
47
|
+
return complexity
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def time_series_to_binary(vector, method="median"):
|
|
51
|
+
"""
|
|
52
|
+
- convert a time series to a binary sequence based on a threshold.
|
|
53
|
+
- returns: str: A binary sequence as a string of '0's and '1's.
|
|
54
|
+
- https://doi.org/10.1101/2021.09.23.461002 this paper used median, making median the default method.
|
|
55
|
+
- diff also makes somewhat sense
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
vector = numpy.array(vector)
|
|
59
|
+
|
|
60
|
+
if method == "mean":
|
|
61
|
+
threshold = numpy.mean(vector)
|
|
62
|
+
binary_seq = "".join(["1" if x > threshold else "0" for x in vector])
|
|
63
|
+
elif method == "median":
|
|
64
|
+
threshold = numpy.median(vector)
|
|
65
|
+
binary_seq = "".join(["1" if x > threshold else "0" for x in vector])
|
|
66
|
+
elif method == "diff":
|
|
67
|
+
diffs = numpy.diff(
|
|
68
|
+
vector
|
|
69
|
+
) # this measures whether the value is increasing or decreasing as compared to the previous value
|
|
70
|
+
binary_seq = "".join(["1" if x > 0 else "0" for x in diffs])
|
|
71
|
+
else:
|
|
72
|
+
raise ValueError("Method must be 'mean', 'median', or 'diff'.")
|
|
73
|
+
|
|
74
|
+
return binary_seq
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def lempel_ziv_v1(time_series: numpy.ndarray) -> int:
|
|
78
|
+
r"""Manual implementation of the Lempel-Ziv complexity.
|
|
79
|
+
|
|
80
|
+
It is defined as the number of different substrings encountered as the stream is viewed from begining to the end.
|
|
81
|
+
As an example:
|
|
82
|
+
|
|
83
|
+
>>> s = '1001111011000010'
|
|
84
|
+
>>> lempel_ziv_complexity(s) # 1 / 0 / 01 / 11 / 10 / 110 / 00 / 010
|
|
85
|
+
8
|
|
86
|
+
|
|
87
|
+
Marking in the different substrings the sequence complexity :math:`\mathrm{Lempel-Ziv}(s) = 8`: :math:`s = 1 / 0 / 01 / 11 / 10 / 110 / 00 / 010`.
|
|
88
|
+
|
|
89
|
+
- See the page https://en.wikipedia.org/wiki/Lempel-Ziv_complexity for more details.
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
Other examples:
|
|
93
|
+
|
|
94
|
+
>>> lempel_ziv_complexity('1010101010101010') # 1, 0, 10, 101, 01, 010, 1010
|
|
95
|
+
7
|
|
96
|
+
>>> lempel_ziv_complexity('1001111011000010000010') # 1, 0, 01, 11, 10, 110, 00, 010, 000
|
|
97
|
+
9
|
|
98
|
+
>>> lempel_ziv_complexity('100111101100001000001010') # 1, 0, 01, 11, 10, 110, 00, 010, 000, 0101
|
|
99
|
+
10
|
|
100
|
+
|
|
101
|
+
- Note: it is faster to give the sequence as a string of characters, like `'10001001'`, instead of a list or a numpy array.
|
|
102
|
+
- Note: see this notebook for more details, comparison, benchmarks and experiments: https://Nbviewer.Jupyter.org/github/Naereen/Lempel-Ziv_Complexity/Short_study_of_the_Lempel-Ziv_complexity.ipynb
|
|
103
|
+
- Note: there is also a Cython-powered version, for speedup, see :download:`lempel_ziv_complexity_cython.pyx`.
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
sequence = time_series_to_binary(time_series, method="median")
|
|
107
|
+
|
|
108
|
+
sub_strings = set()
|
|
109
|
+
|
|
110
|
+
ind = 0
|
|
111
|
+
inc = 1
|
|
112
|
+
while True:
|
|
113
|
+
if ind + inc > len(sequence):
|
|
114
|
+
break
|
|
115
|
+
sub_str = sequence[ind : ind + inc]
|
|
116
|
+
if sub_str in sub_strings:
|
|
117
|
+
inc += 1
|
|
118
|
+
else:
|
|
119
|
+
sub_strings.add(sub_str)
|
|
120
|
+
ind += inc
|
|
121
|
+
inc = 1
|
|
122
|
+
return len(sub_strings)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def lempel_ziv_v2(time_series):
|
|
126
|
+
"""
|
|
127
|
+
Compute the Lempel-Ziv complexity of a binary sequence.
|
|
128
|
+
|
|
129
|
+
Parameters:
|
|
130
|
+
sequence (str): The binary sequence as a string of '0' and '1'.
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
int: The Lempel-Ziv complexity.
|
|
134
|
+
"""
|
|
135
|
+
sequence = time_series_to_binary(time_series, method="median")
|
|
136
|
+
|
|
137
|
+
sub_strings = set()
|
|
138
|
+
n = len(sequence)
|
|
139
|
+
ind = 0
|
|
140
|
+
count = 0
|
|
141
|
+
|
|
142
|
+
while ind < n:
|
|
143
|
+
inc = 1
|
|
144
|
+
# Find the shortest substring not already in sub_strings
|
|
145
|
+
while sequence[ind : ind + inc] in sub_strings and ind + inc <= n:
|
|
146
|
+
inc += 1
|
|
147
|
+
|
|
148
|
+
# Add the new substring to the set
|
|
149
|
+
sub_strings.add(sequence[ind : ind + inc])
|
|
150
|
+
count += 1
|
|
151
|
+
ind += inc
|
|
152
|
+
|
|
153
|
+
return count
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def lempel_ziv_v4(time_series):
|
|
157
|
+
"""
|
|
158
|
+
Computes the Lempel-Ziv complexity of the input sequence s.
|
|
159
|
+
|
|
160
|
+
Parameters:
|
|
161
|
+
s (str): The input sequence (e.g., a binary string).
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
int: The Lempel-Ziv complexity of the sequence.
|
|
165
|
+
"""
|
|
166
|
+
|
|
167
|
+
sequence = time_series_to_binary(time_series, method="median")
|
|
168
|
+
n = len(sequence)
|
|
169
|
+
i = 0
|
|
170
|
+
c = 1 # Complexity starts at 1 since the first character is always new
|
|
171
|
+
k = 1
|
|
172
|
+
l = 1
|
|
173
|
+
|
|
174
|
+
while l + k <= n:
|
|
175
|
+
# Check if the substring s[l:l+k] has occurred in s[0:l]
|
|
176
|
+
if sequence[l : l + k] in sequence[0:l]:
|
|
177
|
+
k += 1
|
|
178
|
+
if l + k - 1 == n:
|
|
179
|
+
c += 1
|
|
180
|
+
break
|
|
181
|
+
else:
|
|
182
|
+
c += 1
|
|
183
|
+
l = l + k
|
|
184
|
+
k = 1
|
|
185
|
+
|
|
186
|
+
return c
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
if __name__ == "__main__":
|
|
190
|
+
sequence = "1001111011000010"
|
|
191
|
+
print(lempel_ziv_v1(sequence))
|
|
192
|
+
print(lempel_ziv_v2(sequence))
|
|
193
|
+
print(lempel_ziv(sequence))
|
|
194
|
+
print(lempel_ziv_v4(sequence))
|
|
195
|
+
|
|
196
|
+
signal = numpy.random.rand(1000)
|
|
197
|
+
binary_sequence = time_series_to_binary(signal, method="median")
|
|
198
|
+
print(lempel_ziv_v1(binary_sequence))
|
|
199
|
+
print(lempel_ziv_v2(binary_sequence))
|
|
200
|
+
print(lempel_ziv(binary_sequence))
|
|
201
|
+
print(lempel_ziv_v4(binary_sequence))
|
|
File without changes
|
|
File without changes
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
#!/Users/donyin/miniconda3/envs/rotation-1/bin/python
|
|
2
2
|
|
|
3
|
+
"""
|
|
4
|
+
- validating measures of complexity is actually working using synthetic data on various Hurst exponents
|
|
5
|
+
"""
|
|
3
6
|
|
|
4
7
|
import numpy
|
|
5
8
|
from scipy.fft import fft, ifft
|
|
6
9
|
import matplotlib.pyplot as plt
|
|
7
10
|
from donware import inspect_package
|
|
8
|
-
from complexeva.measures.higuchi import hfd_pyeeg, hfd_matlab_equivalent
|
|
11
|
+
from complexeva.measures.dimension_1.higuchi import hfd_pyeeg, hfd_matlab_equivalent
|
|
12
|
+
from complexeva.measures.dimension_1.lempel_ziv import lempel_ziv_v1, lempel_ziv_v2, lempel_ziv, lempel_ziv_v4
|
|
9
13
|
|
|
10
14
|
|
|
11
|
-
class
|
|
12
|
-
def __init__(self, funcs,
|
|
13
|
-
self.funcs, self.
|
|
15
|
+
class ComplexityMeasuresValidator2D:
|
|
16
|
+
def __init__(self, funcs, timeseries_len=1000, num_hurst=200):
|
|
17
|
+
self.funcs, self.num_hurst, self.timeseries_len = funcs, num_hurst, timeseries_len
|
|
14
18
|
|
|
15
19
|
def fbm(self, hurst):
|
|
16
20
|
"""
|
|
@@ -52,7 +56,7 @@ class HiguchiMethodValidate:
|
|
|
52
56
|
hfd_results = []
|
|
53
57
|
|
|
54
58
|
for func in self.funcs:
|
|
55
|
-
hfd_results.append([func(series
|
|
59
|
+
hfd_results.append([func(series) for series in fBm_series])
|
|
56
60
|
|
|
57
61
|
# ---- plotting ----
|
|
58
62
|
fig, axs = plt.subplots(3, 1, figsize=(9, 10))
|
|
@@ -91,6 +95,8 @@ class HiguchiMethodValidate:
|
|
|
91
95
|
|
|
92
96
|
|
|
93
97
|
if __name__ == "__main__":
|
|
94
|
-
|
|
95
|
-
validator
|
|
98
|
+
validator = ComplexityMeasuresValidator2D([hfd_pyeeg, hfd_matlab_equivalent])
|
|
99
|
+
validator.plot_hfd_vs_hurst()
|
|
100
|
+
|
|
101
|
+
validator = ComplexityMeasuresValidator2D([lempel_ziv_v1, lempel_ziv_v2, lempel_ziv, lempel_ziv_v4])
|
|
96
102
|
validator.plot_hfd_vs_hurst()
|
|
@@ -9,11 +9,14 @@ complexeva/dummies/__init__.py
|
|
|
9
9
|
complexeva/dummies/matrix.py
|
|
10
10
|
complexeva/dummies/networks.py
|
|
11
11
|
complexeva/measures/__init__.py
|
|
12
|
-
complexeva/measures/cbb_matrix.py
|
|
13
|
-
complexeva/measures/cbb_networkx.py
|
|
14
|
-
complexeva/measures/co_activation.py
|
|
15
|
-
complexeva/measures/higuchi.py
|
|
16
12
|
complexeva/measures/validate.py
|
|
13
|
+
complexeva/measures/dimension_1/__init__.py
|
|
14
|
+
complexeva/measures/dimension_1/higuchi.py
|
|
15
|
+
complexeva/measures/dimension_1/lempel_ziv.py
|
|
16
|
+
complexeva/measures/dimension_2/__init__.py
|
|
17
|
+
complexeva/measures/dimension_2/cbb_matrix.py
|
|
18
|
+
complexeva/measures/network_space/__init__.py
|
|
19
|
+
complexeva/measures/network_space/cbb_networkx.py
|
|
17
20
|
complexeva/utils/__init__.py
|
|
18
21
|
complexeva/utils/convert_image_matrix.py
|
|
19
22
|
complexeva/utils/convert_matrix_network.py
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
#!/Users/donyin/miniconda3/envs/rotation-1/bin/python
|
|
2
|
-
|
|
3
|
-
"""
|
|
4
|
-
- now we have two 1d series as signals make dummy data using numpy
|
|
5
|
-
- use either a sliding window or regression method to produce a new signal that represents the co-activation between the two signals
|
|
6
|
-
- in the sliding_window method, the window_size parameter is used to determine the size of the window used to calculate the co-activation
|
|
7
|
-
- it moves one step at a time and calculates the correlation between the two signals in the window
|
|
8
|
-
- in the regression method, the two signals are used as independent and dependent variables in a linear regression model
|
|
9
|
-
- the resulting signal is the predicted dependent variable
|
|
10
|
-
- if we use the sliding_window method, the window_size parameter must be an integer greater than 0
|
|
11
|
-
- if we use the regression method, we must plot the two signal and the resulting signal
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
import numpy as np
|
|
15
|
-
from sklearn.linear_model import LinearRegression
|
|
16
|
-
import matplotlib.pyplot as plt
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def get_co_activation(
|
|
20
|
-
signal_1: np.ndarray, signal_2: np.ndarray, method: str, window_size: int = None, save_plot_as=None
|
|
21
|
-
) -> np.ndarray:
|
|
22
|
-
"""
|
|
23
|
-
Get a measure of co-activation between two 1D signals.
|
|
24
|
-
|
|
25
|
-
Args:
|
|
26
|
-
signal_1: First 1D time series signal
|
|
27
|
-
signal_2: Second 1D time series signal
|
|
28
|
-
method: Either 'sliding_window' or 'regression'
|
|
29
|
-
window_size: Size of the window for 'sliding_window' method (must be an integer greater than 0)
|
|
30
|
-
|
|
31
|
-
Returns:
|
|
32
|
-
np.ndarray: A new signal representing the co-activation between the two signals
|
|
33
|
-
"""
|
|
34
|
-
match method:
|
|
35
|
-
case "sliding_window":
|
|
36
|
-
if window_size is None or window_size <= 0:
|
|
37
|
-
raise ValueError("window_size must be an integer greater than 0 for sliding_window method")
|
|
38
|
-
correlations = []
|
|
39
|
-
num_windows = len(signal_1) - window_size + 1
|
|
40
|
-
for i in range(num_windows):
|
|
41
|
-
window_signal_1 = signal_1[i : i + window_size]
|
|
42
|
-
window_signal_2 = signal_2[i : i + window_size]
|
|
43
|
-
corr = np.corrcoef(window_signal_1, window_signal_2)[0, 1]
|
|
44
|
-
correlations.append(corr)
|
|
45
|
-
|
|
46
|
-
# Plot signals and correlations
|
|
47
|
-
correlations = np.array(correlations)
|
|
48
|
-
if save_plot_as:
|
|
49
|
-
plt.figure(figsize=(10, 5))
|
|
50
|
-
plt.plot(signal_1, label="Signal 1", alpha=0.7)
|
|
51
|
-
plt.plot(signal_2, label="Signal 2", alpha=0.7)
|
|
52
|
-
plt.plot(
|
|
53
|
-
np.arange(window_size // 2, len(correlations) + window_size // 2),
|
|
54
|
-
correlations,
|
|
55
|
-
label="Sliding Window Correlation",
|
|
56
|
-
linestyle="--",
|
|
57
|
-
)
|
|
58
|
-
plt.legend()
|
|
59
|
-
plt.title(f"Sliding Window Method Co-Activation (window size={window_size})")
|
|
60
|
-
plt.savefig(save_plot_as, dpi=320)
|
|
61
|
-
plt.close()
|
|
62
|
-
|
|
63
|
-
return correlations
|
|
64
|
-
|
|
65
|
-
case "regression":
|
|
66
|
-
# Reshape signals for regression
|
|
67
|
-
X = signal_1.reshape(-1, 1)
|
|
68
|
-
y = signal_2
|
|
69
|
-
|
|
70
|
-
# Fit linear regression
|
|
71
|
-
model = LinearRegression()
|
|
72
|
-
model.fit(X, y)
|
|
73
|
-
|
|
74
|
-
# Predict y
|
|
75
|
-
y_pred = model.predict(X)
|
|
76
|
-
|
|
77
|
-
# Plot signals
|
|
78
|
-
if save_plot_as:
|
|
79
|
-
plt.figure(figsize=(10, 5))
|
|
80
|
-
plt.plot(signal_1, label="Signal 1 (IV)")
|
|
81
|
-
plt.plot(signal_2, label="Signal 2 (DV)")
|
|
82
|
-
plt.plot(y_pred, label="Predicted DV", linestyle="--")
|
|
83
|
-
plt.legend()
|
|
84
|
-
plt.title("Regression Method Co-Activation")
|
|
85
|
-
plt.savefig(save_plot_as, dpi=320)
|
|
86
|
-
plt.close()
|
|
87
|
-
|
|
88
|
-
return y_pred
|
|
89
|
-
|
|
90
|
-
case _:
|
|
91
|
-
raise ValueError("method must be 'sliding_window' or 'regression'")
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if __name__ == "__main__":
|
|
95
|
-
t = np.linspace(0, 10, 1000)
|
|
96
|
-
signal1 = np.sin(2 * np.pi * 0.5 * t) + 0.2 * np.random.randn(1000)
|
|
97
|
-
signal2 = 0.8 * np.sin(2 * np.pi * 0.5 * t + np.pi / 4) + 0.2 * np.random.randn(1000)
|
|
98
|
-
|
|
99
|
-
get_co_activation(signal1, signal2, method="sliding_window", window_size=32, save_plot_as="coactivation_sliding_window.png")
|
|
100
|
-
get_co_activation(signal1, signal2, method="regression", save_plot_as="coactivation_regression.png")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|