Forked from aythamimm/keystroke_btas15_scoring/1
Algorithms have at least one input and one output. All algorithm endpoints are organized in groups. Groups are used by the platform to indicate which inputs and outputs are synchronized together. The first group is automatically synchronized with the channel defined by the block in which the algorithm is deployed.
Endpoint Name | Data Format | Nature |
---|---|---|
comparison_ids | system/array_1d_text/1 | Input |
keystroke | tutorial/atvs_keystroke/1 | Input |
probe_client_id | system/text/1 | Input |
scores | elie_khoury/string_probe_scores/1 | Output |
Endpoint Name | Data Format | Nature |
---|---|---|
template_client_id | system/text/1 | Input |
template_id | system/text/1 | Input |
model_template | aythamimm/keystroke_model/8 | Input |
Parameters allow users to change the configuration of an algorithm when scheduling an experiment
Name | Description | Type | Default | Range/Choices |
---|---|---|---|---|
field | Data field used to generate the feature template | string | given_name | given_name, family_name, email, nationality, id_number, all_five |
distance | Distance to obtain the matching score | string | Modified Scaled Manhattan | Scaled Manhattan, Modified Scaled Manhattan, Combined Manhattan-Mahalanobis, Mahalanobis + Nearest Neighbor |
xxxxxxxxxx
import numpy
def modified_scaled_distance(in1,in2,in3): #Funcion que funciona con la media, la std , y el vector de prueba
##This is the distance 1 based on the manhattan distance or
##city block and a normalization by standard deviation
dif=[]
mean_gal_features=in1
std_gal_features=in2
probe_features=in3
l_features=len(probe_features)
std_threshold=0.2*numpy.mean(std_gal_features);
for i in range( l_features):
if std_gal_features[i] < std_threshold:
std_gal_features[i]=std_threshold
for i_dif in range(l_features):
dif.append((abs(mean_gal_features[i_dif]-probe_features[i_dif]))/std_gal_features[i_dif])
score = 1/numpy.average(dif)
return score
def scaled_distance(in1,in2,in3):#distancia que funciona con la media, la std , y el vector de prueba
##This is the distance 1 based on the manhattan distance or
##city block and a normalization by standard deviation
dif=[]
mean_gal_features=in1
mad_gal_features=in2;
probe_features=in3
l_features=len(probe_features)
for i_dif in range(l_features):
dif.append((abs(mean_gal_features[i_dif]-probe_features[i_dif]))/mad_gal_features[i_dif])
score = 1/numpy.sum(dif)
return score
class Algorithm:
def __init__(self): #Difinimos variables globales
self.templates = None #por defecto None la primera vez
self.field='given_name' #Por defecto el nombre
self.distance='given_name'
def setup(self, parameters): #Funcion que define los parametros
self.field = parameters.get('field', self.field)#si el parametro field no toma valor se deja el nombre si toma valor se pondra el que sea(correo,DNI,etc)?
self.distance = parameters.get('distance', self.distance)
return True
def process(self, inputs, outputs):
# retrieve all the templates once
if self.templates is None:#La primera vez entra aqui
self.templates = {}#define un diccionario
group = inputs.groupOf('model_template')#mira en la entrada el grupo con model_template
while group.hasMoreData():#Mientras tenga datos se ejecuta
group.next()#no se que hace? pedir dato nuevo
template_id = group['template_id'].data.text #string
if self.field == 'given_name':#Si es el nombre se ejecuta esto y guardamos la media,std y mad en cada template
template1=group['model_template'].data.given_name_average
template2=group['model_template'].data.given_name_std
template3=group['model_template'].data.given_name_mad
if self.field == 'family_name':
template1=group['model_template'].data.family_name_average
template2=group['model_template'].data.family_name_std
template3=group['model_template'].data.family_name_mad
if self.field == 'email':
template1=group['model_template'].data.email_average
template2=group['model_template'].data.email_std
template3=group['model_template'].data.email_mad
if self.field == 'nationality':
template1=group['model_template'].data.nationality_average
template2=group['model_template'].data.nationality_std
template3=group['model_template'].data.nationality_mad
if self.field == 'id_number':
template1=group['model_template'].data.id_number_average
template2=group['model_template'].data.id_number_std
template3=group['model_template'].data.id_number_mad
if self.field == 'all_five':#si es todos lo hace con cada uno
template11=group['model_template'].data.given_name_average
template12=group['model_template'].data.given_name_std
template13=group['model_template'].data.given_name_mad
template21=group['model_template'].data.family_name_average
template22=group['model_template'].data.family_name_std
template23=group['model_template'].data.family_name_mad
template31=group['model_template'].data.email_average
template32=group['model_template'].data.email_std
template33=group['model_template'].data.email_mad
template41=group['model_template'].data.nationality_average
template42=group['model_template'].data.nationality_std
template43=group['model_template'].data.nationality_mad
template51=group['model_template'].data.id_number_average
template52=group['model_template'].data.id_number_std
template53=group['model_template'].data.id_number_mad
if self.field != 'all_five':#si no son todos entra en el if y crea un diccionario en la posicion template_id que es el usuario?
self.templates[template_id] = dict(
client_id = group['template_client_id'].data.text,
model_average = template1,
model_std = template2,
model_mad = template3,
)
if self.field == 'all_five':#si es todos hace esto, es un diccionario con todos
self.templates[template_id] = dict(
client_id = group['template_client_id'].data.text,
model_average1 = template11,
model_std1 = template12,
model_mad1 = template13,
model_average2 = template21,
model_std2 = template22,
model_mad2 = template23,
model_average3 = template31,
model_std3 = template32,
model_mad3 = template33,
model_average4 = template41,
model_std4 = template42,
model_mad4 = template43,
model_average5 = template51,
model_std5 = template52,
model_mad5 = template53,
)
# process the probe
comparison_ids = inputs['comparison_ids'].data.text#string? creo que es el identificador de comparacion
data = inputs['keystroke'].data #coge una de las muestras de ese usuario que entran
if self.field == 'given_name':#si es el nombre coge el hotdtime y rplatency
f1 = data.holdtime.given_name
f2 = data.rplatency.given_name
if self.field == 'family_name':
f1 = data.holdtime.family_name
f2 = data.rplatency.family_name
if self.field == 'email':
f1 = data.holdtime.email
f2 = data.rplatency.email
if self.field == 'nationality':
f1 = data.holdtime.nationality
f2 = data.rplatency.nationality
if self.field == 'id_number':
f1 = data.holdtime.id_number
f2 = data.rplatency.id_number
if self.field == 'all_five':#Si es todo coge los cinco
f11 = data.holdtime.given_name
f12 = data.rplatency.given_name
f21 = data.holdtime.family_name
f22 = data.rplatency.family_name
f31 = data.holdtime.email
f32 = data.rplatency.email
f41 = data.holdtime.nationality
f42 = data.rplatency.nationality
f51 = data.holdtime.id_number
f52 = data.rplatency.id_number
if self.field != 'all_five':#si es distinto de los 5 pasw solo lo hace para uno
feature_vector=[] #definimos una lista
l_f=len(f1)#longitud de la lista
for i_k in range(l_f):#vamos poniendo los valores en una fila y transformando a float
feature_vector.append(float(f1[i_k]))
l_f=len(f2)
for i_k in range(l_f):#igual pero con rplatency
feature_vector.append(float(f2[i_k]))
probe_features=feature_vector#igualamos el vector, se podria hacer en un paso?
if self.field == 'all_five':#con los cindo si es all_five
feature_vector1=[]
l_f=len(f11)
for i_k in range(l_f):
feature_vector1.append(float(f11[i_k]))
l_f=len(f12)
for i_k in range(l_f):
feature_vector1.append(float(f12[i_k]))
feature_vector2=[]
l_f=len(f21)
for i_k in range(l_f):
feature_vector2.append(float(f21[i_k]))
l_f=len(f22)
for i_k in range(l_f):
feature_vector2.append(float(f22[i_k]))
feature_vector3=[]
l_f=len(f31)
for i_k in range(l_f):
feature_vector3.append(float(f31[i_k]))
l_f=len(f32)
for i_k in range(l_f):
feature_vector3.append(float(f32[i_k]))
feature_vector4=[]
l_f=len(f41)
for i_k in range(l_f):
feature_vector4.append(float(f41[i_k]))
l_f=len(f42)
for i_k in range(l_f):
feature_vector4.append(float(f42[i_k]))
feature_vector5=[]
l_f=len(f51)
for i_k in range(l_f):
feature_vector5.append(float(f51[i_k]))
l_f=len(f52)
for i_k in range(l_f):
feature_vector5.append(float(f52[i_k]))
probe_features1=feature_vector1
probe_features2=feature_vector2
probe_features3=feature_vector3
probe_features4=feature_vector4
probe_features5=feature_vector5
scores = []#difinimos score como lista
for comparison_id in comparison_ids:
template_client_identity = self.templates[comparison_id]['client_id']
if self.field != 'all_five':#Hacemos las distancias para solo un pasw
if self.distance == 'Modified Scaled Manhattan':
score=modified_scaled_distance(self.templates[comparison_id]['model_average'],self.templates[comparison_id]['model_std'],probe_features);
if self.distance == 'Scaled Manhattan':
score=scaled_distance(self.templates[comparison_id]['model_average'],self.templates[comparison_id]['model_mad'],probe_features);
if self.field == 'all_five':#para los cinco pasw
score=[] #podria quitarse?
if self.distance == 'Modified Scaled Manhattan':
score.append(modified_scaled_distance(self.templates[comparison_id]['model_average1'],self.templates[comparison_id]['model_std1'],probe_features1))
score.append(modified_scaled_distance(self.templates[comparison_id]['model_average2'],self.templates[comparison_id]['model_std2'],probe_features2))
score.append(modified_scaled_distance(self.templates[comparison_id]['model_average3'],self.templates[comparison_id]['model_std3'],probe_features3))
score.append(modified_scaled_distance(self.templates[comparison_id]['model_average4'],self.templates[comparison_id]['model_std4'],probe_features4))
score.append(modified_scaled_distance(self.templates[comparison_id]['model_average5'],self.templates[comparison_id]['model_std5'],probe_features5))
if self.distance == 'Scaled Manhattan':
score.append(scaled_distance(self.templates[comparison_id]['model_average1'],self.templates[comparison_id]['model_std1'],probe_features1))
score.append(scaled_distance(self.templates[comparison_id]['model_average2'],self.templates[comparison_id]['model_std2'],probe_features2))
score.append(scaled_distance(self.templates[comparison_id]['model_average3'],self.templates[comparison_id]['model_std3'],probe_features3))
score.append(scaled_distance(self.templates[comparison_id]['model_average4'],self.templates[comparison_id]['model_std4'],probe_features4))
score.append(scaled_distance(self.templates[comparison_id]['model_average5'],self.templates[comparison_id]['model_std5'],probe_features5))
score=numpy.average(score)#media de todos los scores por fila
scores.append({
'template_identity': template_client_identity,
'score': score,
})#difinimos dentro de la lista scores diccionarios con dos campos
outputs['scores'].write({
'client_identity': inputs['probe_client_id'].data.text,
'scores': scores
},
)
return True
The code for this algorithm in Python
The ruler at 80 columns indicate suggested POSIX line breaks (for readability).
The editor will automatically enlarge to accomodate the entirety of your input
Use keyboard shortcuts for search/replace and faster editing. For example, use Ctrl-F (PC) or Cmd-F (Mac) to search through this box
For a given set of feature vectors and enrollment set, the modified manhattan scaled distance is obtained. See [1] for details.
AGREEMENT ON THE USE OF THIS CODE AND ANY GENERATED DATA
I agree:
[1] A. Morales, M. Falanga, J. Fierrez, C. Sansone and J. Ortega-Garcia, "Keystroke Dynamics Recognition based on Personal Data: A Comparative Experimental Evaluation Implementing Reproducible Research ", in Proc. the IEEE Seventh International Conference on Biometrics: Theory, Applications and Systems, Arlington, Virginia, USA, September 2015