Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
Merge branch 'pr/15'
Browse files Browse the repository at this point in the history
  • Loading branch information
capcarr committed Dec 30, 2016
2 parents b2b9db1 + ab1f0e8 commit 2acfff7
Show file tree
Hide file tree
Showing 19 changed files with 294 additions and 204 deletions.
16 changes: 11 additions & 5 deletions biosppy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
# -*- coding: utf-8 -*-
"""
biosppy
-------
biosppy
-------
A toolbox for biosignal processing written in Python.
A toolbox for biosignal processing written in Python.
:copyright: (c) 2015 by Instituto de Telecomunicacoes
:license: BSD 3-clause, see LICENSE for more details.
:copyright: (c) 2015-2017 by Instituto de Telecomunicacoes
:license: BSD 3-clause, see LICENSE for more details.
"""

# compat
from __future__ import absolute_import, division, print_function

# get version
from .version import version as __version__

# allow lazy loading
from .signals import bvp, ecg, eda, eeg, emg, resp, tools
93 changes: 49 additions & 44 deletions biosppy/biometrics.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
# -*- coding: utf-8 -*-
"""
biosppy.biometrics
------------------
This module provides classifier interfaces for identity recognition
(biometrics) applications. The core API methods are:
* enroll: add a new subject;
* dismiss: remove an existing subject;
* identify: determine the identity of collected biometric dataset;
* authenticate: verify the identity of collected biometric dataset.
:copyright: (c) 2015 by Instituto de Telecomunicacoes
:license: BSD 3-clause, see LICENSE for more details.
biosppy.biometrics
------------------
This module provides classifier interfaces for identity recognition
(biometrics) applications. The core API methods are:
* enroll: add a new subject;
* dismiss: remove an existing subject;
* identify: determine the identity of collected biometric dataset;
* authenticate: verify the identity of collected biometric dataset.
:copyright: (c) 2015-2017 by Instituto de Telecomunicacoes
:license: BSD 3-clause, see LICENSE for more details.
"""

# Imports
# compat
from __future__ import absolute_import, division, print_function
from six.moves import range
import six

# built-in
import collections

Expand Down Expand Up @@ -247,7 +252,7 @@ def list_subjects(self):
"""

subjects = self._subject2label.keys()
subjects = list(self._subject2label)

return subjects

Expand Down Expand Up @@ -356,7 +361,7 @@ def batch_train(self, data=None):
if data is None:
raise TypeError("Please specify the data to train.")

for sub, val in data.iteritems():
for sub, val in six.iteritems(data):
if val is None:
try:
self.dismiss(sub, deferred=True)
Expand Down Expand Up @@ -399,10 +404,10 @@ def update_thresholds(self, fraction=1.):

# gather data to test
data = {}
for subject, label in self._subject2label.iteritems():
for subject, label in six.iteritems(self._subject2label):
# select a random fraction of the training data
aux = self.io_load(label)
indx = range(len(aux))
indx = list(range(len(aux)))
use, _ = utils.random_fraction(indx, fraction, sort=True)

data[subject] = aux[use]
Expand All @@ -411,7 +416,7 @@ def update_thresholds(self, fraction=1.):
_, res = self.evaluate(data, ths)

# choose thresholds at EER
for subject, label in self._subject2label.iteritems():
for subject, label in six.iteritems(self._subject2label):
EER_auth = res['subject'][subject]['authentication']['rates']['EER']
self.set_auth_thr(label, EER_auth[self.EER_IDX, 0], ready=True)

Expand Down Expand Up @@ -639,7 +644,7 @@ def evaluate(self, data, thresholds=None, show=False):
thresholds = self.get_thresholds()

# get subjects
subjects = filter(lambda item: self.check_subject(item), data.keys())
subjects = [item for item in data if self.check_subject(item)]
if len(subjects) == 0:
raise ValueError("No enrolled subjects in test set.")

Expand Down Expand Up @@ -722,15 +727,15 @@ def cross_validation(cls, data, labels, cv, thresholds=None, **kwargs):
lbl = labels[item]
train_idx[lbl].append(item)

train_data = {sub: data[idx] for sub, idx in train_idx.iteritems()}
train_data = {sub: data[idx] for sub, idx in six.iteritems(train_idx)}

# test data set
test_idx = collections.defaultdict(list)
for item in test:
lbl = labels[item]
test_idx[lbl].append(item)

test_data = {sub: data[idx] for sub, idx in test_idx.iteritems()}
test_data = {sub: data[idx] for sub, idx in six.iteritems(test_idx)}

# instantiate classifier
clf = cls(**kwargs)
Expand Down Expand Up @@ -832,8 +837,8 @@ def _prepare(self, data, targets=None):

# target class labels
if targets is None:
targets = self._subject2label.values()
elif isinstance(targets, basestring):
targets = list(self._subject2label.values())
elif isinstance(targets, six.string_types):
targets = [targets]

return data
Expand Down Expand Up @@ -975,7 +980,7 @@ def _authenticate(self, data, label, threshold):
# select based on subject label
aux = []
ns = len(dists)
for i in xrange(ns):
for i in range(ns):
aux.append(dists[i, train_labels[i, :] == label])

dists = np.array(aux)
Expand All @@ -984,12 +989,12 @@ def _authenticate(self, data, label, threshold):
dists = dists[:, :self.k]

decision = np.zeros(ns, dtype='bool')
for i in xrange(ns):
for i in range(ns):
# compare distances to threshold
count = np.sum(dists[i, :] <= threshold)

# decide accept
if count > (self.k / 2):
if count > (self.k // 2):
decision[i] = True

return decision
Expand All @@ -1014,8 +1019,8 @@ def _get_thresholds(self):
return np.linspace(self.min_thr, 1., 100)

maxD = []
for _ in xrange(3):
for label in self._subject2label.values():
for _ in range(3):
for label in list(six.itervalues(self._subject2label)):
# randomly select samples
aux = self.io_load(label)
ind = np.random.randint(0, aux.shape[0], 3)
Expand Down Expand Up @@ -1064,14 +1069,14 @@ def _identify(self, data, threshold=None):
ns = len(dists)

labels = []
for i in xrange(ns):
for i in range(ns):
lbl, _ = majority_rule(train_labels[i, :], random=True)

# compare distances to threshold
count = np.sum(dists[i, :] <= thrFcn(lbl))

# decide
if count > (self.k / 2):
if count > (self.k // 2):
# accept
labels.append(lbl)
else:
Expand Down Expand Up @@ -1102,8 +1107,8 @@ def _prepare(self, data, targets=None):

# target class labels
if targets is None:
targets = self._subject2label.values()
elif isinstance(targets, basestring):
targets = list(six.itervalues(self._subject2label))
elif isinstance(targets, six.string_types):
targets = [targets]

dists = []
Expand Down Expand Up @@ -1415,7 +1420,7 @@ def _authenticate(self, data, label, threshold):
aux = aux[sel, :]

decision = []
for i in xrange(ns):
for i in range(ns):
# determine majority
predMax, count = majority_rule(aux[:, i], random=True)
rate = float(count) / norm
Expand Down Expand Up @@ -1483,7 +1488,7 @@ def _identify(self, data, threshold=None):
norm = 1.0

labels = []
for i in xrange(ns):
for i in range(ns):
# determine majority
predMax, count = majority_rule(aux[:, i], random=True)
rate = float(count) / norm
Expand Down Expand Up @@ -1524,11 +1529,11 @@ def _prepare(self, data, targets=None):

# target class labels
if self._nbSubjects == 1:
pairs = self._models.keys()
pairs = list(self._models)
else:
if targets is None:
pairs = self._models.keys()
elif isinstance(targets, basestring):
pairs = list(self._models)
elif isinstance(targets, six.string_types):
labels = list(
set(self._subject2label.values()) - set([targets]))
pairs = [[targets, lbl] for lbl in labels]
Expand Down Expand Up @@ -1563,9 +1568,9 @@ def _train(self, enroll=None, dismiss=None):
dismiss = []

# process dismiss
pairs = self._models.keys()
pairs = list(self._models)
for t in dismiss:
pairs = filter(lambda p: t in p, pairs)
pairs = [p for p in pairs if t in p]

for p in pairs:
self._del_clf(p)
Expand All @@ -1590,11 +1595,11 @@ def _train(self, enroll=None, dismiss=None):

# check singles
if self._nbSubjects == 1:
label = self._subject2label.values()[0]
label = list(six.itervalues(self._subject2label))[0]
X = self.io_load(label)
self._get_single_clf(X, label)
elif self._nbSubjects > 1:
aux = filter(lambda p: '' in p, self._models.keys())
aux = [p for p in self._models if '' in p]
if len(aux) != 0:
for p in aux:
self._del_clf(p)
Expand Down Expand Up @@ -1850,7 +1855,7 @@ def get_subject_results(results=None,
R = np.zeros(nth, dtype='float')
CM = []

for i in xrange(nth): # for each threshold
for i in range(nth): # for each threshold
# authentication
for k, lbl in enumerate(subject_idx): # for each subject
subject_tst = subjects[k]
Expand Down Expand Up @@ -2163,7 +2168,7 @@ def combination(results=None, weights=None):
weights = {}

# compile results to find all classes
vec = results.values()
vec = list(six.itervalues(results))
if len(vec) == 0:
raise CombinationError("No keys found.")

Expand All @@ -2182,13 +2187,13 @@ def combination(results=None, weights=None):
# multi-class
counts = np.zeros(nb, dtype='float')

for n in results.iterkeys():
for n in results:
# ensure array
res = np.array(results[n])
ns = float(len(res))

# get count for each unique class
for i in xrange(nb):
for i in range(nb):
aux = float(np.sum(res == unq[i]))
w = weights.get(n, 1.)
counts[i] += ((aux / ns) * w)
Expand Down
37 changes: 21 additions & 16 deletions biosppy/clustering.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
# -*- coding: utf-8 -*-
"""
biosppy.clustering
------------------
biosppy.clustering
------------------
This module provides various unsupervised machine learning (clustering)
algorithms.
This module provides various unsupervised machine learning (clustering)
algorithms.
:copyright: (c) 2015 by Instituto de Telecomunicacoes
:license: BSD 3-clause, see LICENSE for more details.
:copyright: (c) 2015-2017 by Instituto de Telecomunicacoes
:license: BSD 3-clause, see LICENSE for more details.
"""

# Imports
# compat
from __future__ import absolute_import, division, print_function
from six.moves import map, range, zip
import six

# 3rd party
import numpy as np
import scipy.cluster.hierarchy as sch
Expand Down Expand Up @@ -134,7 +139,7 @@ def hierarchical(data=None,
'ward', 'weighted']:
raise ValueError("Unknown linkage criterion '%r'." % linkage)

if not isinstance(metric, basestring):
if not isinstance(metric, six.string_types):
raise TypeError("Please specify the distance metric as a string.")

N = len(data)
Expand Down Expand Up @@ -405,19 +410,19 @@ def create_coassoc(ensemble=None, N=None):
nparts = len(ensemble)
assoc = 0
for part in ensemble:
nsamples = np.array([len(part[key]) for key in part.iterkeys()])
dim = np.sum(nsamples * (nsamples - 1)) / 2
nsamples = np.array([len(part[key]) for key in part])
dim = np.sum(nsamples * (nsamples - 1)) // 2

I = np.zeros(dim)
J = np.zeros(dim)
X = np.ones(dim)
ntriplets = 0

for v in part.itervalues():
for v in six.itervalues(part):
nb = len(v)
if nb > 0:
for h in xrange(nb):
for f in xrange(h + 1, nb):
for h in range(nb):
for f in range(h + 1, nb):
I[ntriplets] = v[h]
J[ntriplets] = v[f]
ntriplets += 1
Expand Down Expand Up @@ -539,7 +544,7 @@ def mdist_templates(data=None,
clusters = {0: np.arange(len(data), dtype='int')}

# cluster labels
ks = clusters.keys()
ks = list(clusters)

# remove the outliers' cluster, if present
if '-1' in ks:
Expand Down Expand Up @@ -631,7 +636,7 @@ def centroid_templates(data=None, clusters=None, ntemplates=1):
raise TypeError("Please specify a data clustering.")

# cluster labels
ks = clusters.keys()
ks = list(clusters)

# remove the outliers' cluster, if present
if '-1' in ks:
Expand Down Expand Up @@ -839,7 +844,7 @@ def outliers_dmean(data=None,
outliers.append(i)

outliers = np.unique(outliers)
normal = np.setdiff1d(range(len(data)), outliers, assume_unique=True)
normal = np.setdiff1d(list(range(len(data))), outliers, assume_unique=True)

# output
clusters = {-1: outliers, 0: normal}
Expand Down Expand Up @@ -987,7 +992,7 @@ def _merge_clusters(clusters):
"""

keys = clusters.keys()
keys = list(clusters)

# outliers
if -1 in keys:
Expand Down
Loading

0 comments on commit 2acfff7

Please sign in to comment.