Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace histogram feature implementation #167

Merged
merged 2 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions tests/test_calc_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def test_input_list_window_multi_axis_multi(self):
)
np.testing.assert_array_equal(
features0.shape,
(16, 495),
(16, 468),
)

def test_input_array_window_tosplit_axis_single(self):
Expand All @@ -92,7 +92,7 @@ def test_input_array_window_tosplit_axis_single(self):

np.testing.assert_array_equal(
features1.shape,
(16, 165),
(16, 156),
)

def test_input_series_window_tosplit_axis_single(self):
Expand All @@ -108,7 +108,7 @@ def test_input_series_window_tosplit_axis_single(self):

np.testing.assert_array_equal(
features2.shape,
(16, 165),
(16, 156),
)

def test_input_dataframe_window_single_axis_multi(self):
Expand Down Expand Up @@ -152,7 +152,7 @@ def test_input_series_window_single_axis_single(self):

np.testing.assert_array_equal(
features5.shape,
(1, 40),
(1, 31),
)

def test_input_array_window_single_axis_single(self):
Expand Down Expand Up @@ -183,14 +183,14 @@ def test_personal_features(self):

np.testing.assert_array_equal(
features7.shape,
(1, 169),
(1, 160),
)

def test_get_number_features(self):
feature_sets_size = [get_number_features(get_features_by_domain(domain)) for domain in domains]
np.testing.assert_array_equal(
feature_sets_size,
[40, 14, 124, 6], # 184 is the total
[31, 14, 124, 6], # 184 is the total
)

def test_dataset_extractor(self):
Expand Down
36 changes: 20 additions & 16 deletions tests/test_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,38 +34,42 @@ class TestFeatures(unittest.TestCase):
# ############################################### STATISTICAL FEATURES ############################################### #
def test_hist(self):
np.testing.assert_almost_equal(
hist(const0, 10, 5)["values"],
(0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0),
hist_mode(const0, 10),
0.050000000000000044,
decimal=5,
)
np.testing.assert_almost_equal(
hist(const1, 10, 5)["values"],
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0),
hist_mode(const1, 10),
1.05,
decimal=5,
)
np.testing.assert_almost_equal(
hist(constNeg, 10, 5)["values"],
(0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0, 0.0, 0.0, 0.0),
hist_mode(constNeg, 10),
-0.95,
decimal=5,
)
np.testing.assert_almost_equal(
hist(constF, 10, 5)["values"],
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, 0.0),
hist_mode(constF, 10),
2.55,
decimal=5,
)
np.testing.assert_almost_equal(
hist(lin, 10, 5)["values"],
(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 2),
hist_mode(lin, 10),
0.95,
)
np.testing.assert_almost_equal(
hist(wave, 10, 5)["values"],
(0.0, 0.0, 0.0, 0.0, 499, 496, 5, 0.0, 0.0, 0.0),
hist_mode(wave, 10),
-0.9,
decimal=5,
)
np.testing.assert_almost_equal(
hist(offsetWave, 10, 5)["values"],
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 499, 496, 5, 0.0),
hist_mode(offsetWave, 10),
1.1,
decimal=5,
)
np.testing.assert_almost_equal(
hist(noiseWave, 10, 5)["values"],
(0.0, 0.0, 0.0, 48, 446, 450, 56, 0.0, 0.0, 0.0),
hist_mode(noiseWave, 10),
-0.8862517157830269,
decimal=5,
)

Expand Down
11 changes: 5 additions & 6 deletions tests/tests_tools/test_features.json
Original file line number Diff line number Diff line change
Expand Up @@ -430,14 +430,13 @@
"tag": "eeg",
"use": "yes"
},
"Histogram": {
"Histogram mode": {
"complexity": "log",
"description": "Computes histogram of the signal.",
"function": "tsfel.hist",
"n_features": "nbins",
"description": "Computes the mode of the signal's histogram.",
"function": "tsfel.hist_mode",
"n_features": 1,
"parameters": {
"nbins": 10,
"r": 1
"nbins": 10
},
"use": "yes"
},
Expand Down
11 changes: 5 additions & 6 deletions tsfel/feature_extraction/features.json
Original file line number Diff line number Diff line change
Expand Up @@ -355,15 +355,14 @@
"use": "yes",
"tag": "eeg"
},
"Histogram": {
"Histogram mode": {
"complexity": "log",
"description": "Computes histogram of the signal.",
"function": "tsfel.hist",
"description": "Computes the mode of the signal's histogram.",
"function": "tsfel.hist_mode",
"parameters": {
"nbins": 10,
"r": 1
"nbins": 10
},
"n_features": "nbins",
"n_features": 1,
"use": "yes"
},
"Interquartile range": {
Expand Down
43 changes: 13 additions & 30 deletions tsfel/feature_extraction/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@
+ " data points."
)

future_warn_flag = False
warnings.simplefilter("once", FutureWarning)

# ############################################# TEMPORAL DOMAIN ##################################################### #


Expand Down Expand Up @@ -473,45 +470,31 @@ def entropy(signal, prob="standard"):


@set_domain("domain", "statistical")
def hist(signal, nbins=10, r=1):
"""Computes histogram of the signal.
def hist_mode(signal, nbins=10):
"""Compute the mode of a histogram using a given number of (linearly spaced)
bins.

Feature computational cost: 1

Parameters
----------
signal : nd-array
Input from histogram is computed
signal : np.ndarray
Input signal from which the histogram is computed.
nbins : int
The number of equal-width bins in the given range
r : float
The lower(-r) and upper(r) range of the bins
The number of equal-width bins in the given range, by default 10.

Returns
-------
nd-array
The values of the histogram
float
The mode of the histogram (the midpoint of the bin with the highest
count).
"""
global future_warn_flag

if not future_warn_flag:
warnings.warn(
(
"The histogram feature was deprecated in version 0.1.8 and will be replaced by the mode of histogram in 0.1.9."
" From then on, only a single feature value will be returned."
),
FutureWarning,
)
future_warn_flag = True

# TODO: r value must be revised!
histsig, bin_edges = np.histogram(signal, bins=nbins, range=[-r, r])

names = [
str(np.around(bin_edges[i], 2)) + ":" + str(np.around(bin_edges[i + 1], 2)) for i in range(len(bin_edges) - 1)
]
hist_values, bin_edges = np.histogram(signal, bins=nbins)
max_bin_idx = np.argmax(hist_values)
mode_value = (bin_edges[max_bin_idx] + bin_edges[max_bin_idx + 1]) / 2.0

return {"names": names, "values": histsig}
return mode_value


@set_domain("domain", "statistical")
Expand Down
Loading