Source code for bluepyefe.target
"""EFeatureTarget class"""
"""
Copyright (c) 2022, EPFL/Blue Brain Project
This file is part of BluePyEfe <https://github.com/BlueBrain/BluePyEfe>
This library is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License version 3.0 as published
by the Free Software Foundation.
This library is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
import numpy
import logging
logger = logging.getLogger(__name__)
[docs]
class EFeatureTarget():
"""E-feature target defined by an efeature to compute for a given protocol
and amplitude. Contains the resulting values"""
def __init__(
self,
efeature_name,
efel_feature_name,
protocol_name,
amplitude,
tolerance,
efel_settings=None,
):
"""Constructor.
Args:
efeature_name (str): name of the feature (can be different than
the efel_feature_name - e.g. Spikecount_phase1)
efel_feature_name (str): name of the eFeature in the eFEL library
(ex: 'AP1_peak')
protocol_name (str): name of the recording from which the efeature
should be computed
amplitude (float): amplitude of the current stimuli for which the
efeature should be computed (expressed as a percentage of the
threshold amplitude (rheobase))
tolerance (float): tolerance around the target amplitude in which
an experimental recording will be seen as a hit during
efeatures extraction (expressed as a percentage of the
threshold amplitude (rheobase))
efel_settings (dict): target specific efel settings.
"""
self.efeature_name = efeature_name
if self.efeature_name is None:
self.efeature_name = efel_feature_name
self.efel_feature_name = efel_feature_name
self.protocol_name = protocol_name
self.amplitude = amplitude
self.tolerance = tolerance
self.efel_settings = efel_settings
if self.efel_settings is None:
self.efel_settings = {}
self._values = []
self._files = []
self._auto_thresholds = []
@property
def values(self):
"""Return all values."""
return self._values
@property
def mean(self):
"""Average of the e-feature value at target"""
return numpy.nanmean(self._values)
@property
def std(self):
"""Standard deviation of the e-feature value at target"""
return numpy.nanstd(self._values)
@property
def sample_size(self):
"""Number of value that matched the target present"""
return len(self._values)
[docs]
def append(self, value, files=None):
"""Append a feature value to the present target"""
if not isinstance(value, (int, float)):
raise TypeError("Expected value of type int or float")
if numpy.isnan(value) or value is None:
logger.info(
"Trying to append {} to efeature {} for protocol {} {}. Value "
"will be ignored".format(
value,
self.efel_feature_name,
self.protocol_name,
self.amplitude
)
)
return
self._values.append(value)
if files:
self._files += files
[docs]
def clear(self):
"""Clear the list of feature values"""
self._values = []
self._files = []
[docs]
def add_effective_threshold(self):
"""If auto threshold detection was used during feature extraction,
update the efel settings with the Threshold that was actually used"""
if self._auto_thresholds:
self.efel_settings["Threshold"] = numpy.median(self._auto_thresholds)
[docs]
def as_dict(self, save_files_used=False, default_std_value=1e-3):
"""Returns the target in the form of a dictionary in a legacy format"""
self.add_effective_threshold()
std = self.std
if std == 0.0:
logger.warning(
"Standard deviation for efeatures {} stimulus {} is 0 and "
"will be set to {}".format(
self.efel_feature_name, self.protocol_name, default_std_value
)
)
std = default_std_value
feature_dict = {
"feature": self.efel_feature_name,
"val": [self.mean, std],
"n": self.sample_size,
"efel_settings": self.efel_settings
}
if self.efeature_name:
feature_dict['efeature_name'] = self.efeature_name
if save_files_used:
feature_dict['files'] = self.files
return feature_dict
def __str__(self):
"""String representation"""
str_form = "Target E-Feature {} for protocol {} {:.1f}%:\n".format(
self.efel_feature_name, self.protocol_name, self.amplitude
)
str_form += "Sample size (n): {}".format(self.sample_size)
if self.sample_size:
str_form += "\nMean: {:.5f}\nStandard deviation: {:.5f}".format(
self.mean, self.std
)
return str_form