Skip to content

Commit 49ad993

Browse files
committed
cross validation and minor changes. README
1 parent 7a11bec commit 49ad993

File tree

4 files changed

+466
-23
lines changed

4 files changed

+466
-23
lines changed

README.md

Lines changed: 352 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,352 @@
1-
# calssifier
1+
<div id="table-of-contents">
2+
<h2>Table of Contents</h2>
3+
<div id="text-table-of-contents">
4+
<ul>
5+
<li><a href="#orgheadline1">1. Introduccion</a></li>
6+
<li><a href="#orgheadline4">2. Implementacion</a>
7+
<ul>
8+
<li><a href="#orgheadline2">2.1. Clasificador Euclideo</a></li>
9+
<li><a href="#orgheadline3">2.2. Clasificador Estadistico</a></li>
10+
</ul>
11+
</li>
12+
<li><a href="#orgheadline5">3. Resultados UCI</a></li>
13+
<li><a href="#orgheadline6">4. Validacion Cruzada UCI</a></li>
14+
<li><a href="#orgheadline7">5. Dataset MNIST</a></li>
15+
<li><a href="#orgheadline8">6. Validacion cruzada MNIST</a></li>
16+
<li><a href="#orgheadline9">7. Anexo</a></li>
17+
</ul>
18+
</div>
19+
</div>
20+
21+
22+
# Introduccion<a id="orgheadline1"></a>
23+
24+
Esta es la practica propuesta por la asignaura **Reconocimiento de Formas** de la
25+
Universidad Politecnica de Madrid (UPM), Espana<sup><a id="fnr.1" class="footref" href="#fn.1">1</a></sup>.
26+
27+
La practica consiste en programar 2 reconocedores, uno basado en distancias euclideas
28+
y otro en probabilidades gausianas. Es cierto que la practica se propuso para ser
29+
hecha en python pero, debido a ciertos errores causados por el sistema de tipos
30+
en el que, al almacenar datos propios de la libreria *Numpy* <sup><a id="fnr.1.100" class="footref" href="#fn.1">1</a></sup> en estructuras built-in
31+
de python, los valores de las variables variaban al ser redondeadas o truncadas. Por
32+
ello he decidido hacer la practica en **Julia** <sup><a id="fnr.2" class="footref" href="#fn.2">2</a></sup>, un lenguaje de programacion matematico
33+
al estilo de Matlab <sup><a id="fnr.3" class="footref" href="#fn.3">3</a></sup>.
34+
35+
Antes de nada, decir que es mi primer programa hecho en julia y, por tanto, no es
36+
de extraniar que el codigo no sea el mas optimo asi como que ciertas funciones esten
37+
tipadas y otras se haga uso de la inferencia de julia.
38+
39+
# Implementacion<a id="orgheadline4"></a>
40+
41+
NOTA: Toda la implementacion se puede encontrar aqui <https://github.com/Yawolf/calssifier>
42+
43+
La implementacion de los clasificadores es sencilla. Como he mencionado antes, han sido
44+
programados en Julia, lo que nos permite un manejo de matrices muy bueno, facilitandonos
45+
la programacion.
46+
47+
## Clasificador Euclideo<a id="orgheadline2"></a>
48+
49+
Este clasificador se ajusta al siguiente algoritmo:
50+
51+
<div class="VERBATIM">
52+
get<sub>matrix</sub> from file
53+
get<sub>classes</sub> from matrix
54+
get<sub>average</sub> from matrix and classes
55+
categorize using matrix, classes and average
56+
57+
</div>
58+
59+
1. En primer lugar se obtiene la matriz leyendola del CSV o *.data*
60+
2. De la matriz que hemos leido se extraen las clases y se hace un *nub*<sup><a id="fnr.4" class="footref" href="#fn.4">4</a></sup> del vector
61+
resultante.
62+
3. Creando un diccionario usando las clases como key, calculamos la media de cada uno de
63+
los valores de los "vectores" de cada clase y se insertan como value.
64+
4. Una ve hecho todo lo anterior por cada elemento de la matriz se calcula su distancia
65+
euclidea con cada uno de los *averages* anteriores, el que este mas cerca sera la
66+
clase que se le asigne y se comparara con la que se nos da para ver si es verdad.
67+
68+
Como se puede observar, el funcionamiento e implementacion de dicho reconocedor es
69+
sencillo.
70+
71+
## Clasificador Estadistico<a id="orgheadline3"></a>
72+
73+
Este clasificador tiene un algoritmo mas complejo de implementacion:
74+
75+
<div class="VERBARIM">
76+
get training and testing from file
77+
separate training by classes
78+
get covariance from classes
79+
get mean from classes
80+
classify using testing, classes, mean and covariance
81+
82+
</div>
83+
84+
1. En primer lugar se hace un split de la matriz dando lugar a 2 "submatrices", una
85+
sera la matriz de entrenamiento, otra sera la de testing
86+
2. Una vez obtenida la matriz de entrenamiento, esta se subdivide en otras matrices
87+
mas pequenias en la que todos los elementos de cada una de ellas pertenecen a la
88+
misma clase. Esto es, submatrices por clases.
89+
3. Una vez conseguidas las matrices de clases, se calcula la covarianza de cada una
90+
de ellas.
91+
4. Usando otra vez las matrices de clases se calcula la media de cada uno de los
92+
parametros de cada clase.
93+
5. Usando el subset *testing*, las matrices de clases, sus covarianzas y sus
94+
medias, se calcula la probabilidad de que, cada elemento del dataset *testing*
95+
pretenezca a una u otra clase, para ello se usa la formula de la distribucion
96+
gaussiana y se compara el resultado de la mejor opcion con el original.
97+
98+
Siguiendo estos pasos se consigue reconocer estadisticamente cada elemnto.
99+
100+
# Resultados UCI<a id="orgheadline5"></a>
101+
102+
Ahora se presentaran los resultados para los dataset sacados de la UCI <sup><a id="fnr.5" class="footref" href="#fn.5">5</a></sup>. Estos
103+
dataset son los siquientes:
104+
105+
- wine.data
106+
- cancer.data
107+
- iris.data
108+
- wineR.data
109+
- cancerR.data
110+
- irisR.data
111+
112+
Todos ellos se pueden encontrar en la carpeta *test* de este repositorio. Cabe destacar
113+
que los dataset cuyo nombre termina en una 'R' cotienen los mismos datos que sus
114+
equivalentes sin 'R', solo que sus datos han sido desordenados para obetener una mejor
115+
aleatoriedad.
116+
117+
$> sort -R wine.data >> wineR.data
118+
119+
Se presentan ahora las tasas de acierto de los clasificadores, tanto el euclidiano como el
120+
estadistico:
121+
122+
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
123+
124+
125+
<colgroup>
126+
<col class="org-left" />
127+
128+
<col class="org-right" />
129+
130+
<col class="org-right" />
131+
132+
<col class="org-right" />
133+
</colgroup>
134+
<thead>
135+
<tr>
136+
<th scope="col" class="org-left">Clasificador</th>
137+
<th scope="col" class="org-right">wine.data</th>
138+
<th scope="col" class="org-right">iris.data</th>
139+
<th scope="col" class="org-right">cancer.data</th>
140+
</tr>
141+
</thead>
142+
143+
<tbody>
144+
<tr>
145+
<td class="org-left">Euclideo</td>
146+
<td class="org-right">72.47191011235955%</td>
147+
<td class="org-right">92.66666666666666%</td>
148+
<td class="org-right">61.86291739894551%</td>
149+
</tr>
150+
151+
152+
<tr>
153+
<td class="org-left">Estadistico</td>
154+
<td class="org-right">99.43820224719101%</td>
155+
<td class="org-right">98.0%</td>
156+
<td class="org-right">97.36379613356766%</td>
157+
</tr>
158+
</tbody>
159+
</table>
160+
161+
Notese que la precision del clasificador estadistico es superior en muchos sentidos a la
162+
del euclideo, siendo este mas sencillo de programar, pero mas ineficiente a la hora de
163+
clasificar
164+
165+
Un ejemplo de como se ejecutan los test:
166+
167+
# Dentro del mismo direcotrio del src
168+
$> julia
169+
julia> include("clasific_eucl.jl")
170+
julia> include("clasific_estad.jl")
171+
julia> include("clasific_gauss.jl")
172+
julia> euclideo.start("wine.data") # euclideo
173+
...
174+
julia> gauss.start("wine.data") # estadistico gaussiano
175+
176+
# Validacion Cruzada UCI<a id="orgheadline6"></a>
177+
178+
Ahora se van a presentar los resultados de la validacion cruzada, para ello se ha
179+
decidido que el fichero de entrenamiento y el de test sea el mismo, se han hecho
180+
10 folds para estar acorde al apartado siguiente. Los resultados son los siquientes
181+
182+
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
183+
184+
185+
<colgroup>
186+
<col class="org-left" />
187+
188+
<col class="org-right" />
189+
190+
<col class="org-right" />
191+
192+
<col class="org-right" />
193+
</colgroup>
194+
<thead>
195+
<tr>
196+
<th scope="col" class="org-left">Clasificador</th>
197+
<th scope="col" class="org-right">wine.data</th>
198+
<th scope="col" class="org-right">iris.data</th>
199+
<th scope="col" class="org-right">cancer.data</th>
200+
</tr>
201+
</thead>
202+
203+
<tbody>
204+
<tr>
205+
<td class="org-left">Euclideo</td>
206+
<td class="org-right">71.99197860962568%</td>
207+
<td class="org-right">92.66666666666666%</td>
208+
<td class="org-right">59.68614718614719%</td>
209+
</tr>
210+
211+
212+
<tr>
213+
<td class="org-left">Estadistico</td>
214+
<td class="org-right">99.43820224719101%</td>
215+
<td class="org-right">98.0%</td>
216+
<td class="org-right">97.36379613356766%</td>
217+
</tr>
218+
</tbody>
219+
</table>
220+
221+
# Dataset MNIST<a id="orgheadline7"></a>
222+
223+
Ahora se usara el dataset MNIST <sup><a id="fnr.6" class="footref" href="#fn.6">6</a></sup>, la cual cuentiene 60.000 elementos con 10
224+
variables cada uno de ellos.
225+
226+
Para ejecutar se usan estos mandatos:
227+
228+
# Dentro del mismo direcotrio del src
229+
$> julia
230+
julia> include("clasific_eucl.jl")
231+
julia> include("clasific_estad.jl")
232+
julia> include("clasific_gauss.jl")
233+
julia> gauss.start("datos_procesados.npy",(1,500),1) # estadistico gaussiano
234+
235+
En este caso estamos usando las primeras 500 filas del CSV para entrenar y, al haber
236+
pasado un 1 como argumento, usaremos el mismo subset para entrenar y para testear.
237+
Cambiando dicho flag, se usara el segundo subset para testear.
238+
239+
julia> euclideo.start("datos_procesados.npy",(1,500),2)
240+
...
241+
julia> gauss.start("datos_procesados.npy",(1,500),2)
242+
243+
Los resultados son los siquientes:
244+
245+
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
246+
247+
248+
<colgroup>
249+
<col class="org-left" />
250+
251+
<col class="org-right" />
252+
253+
<col class="org-right" />
254+
</colgroup>
255+
<thead>
256+
<tr>
257+
<th scope="col" class="org-left">&#xa0;</th>
258+
<th scope="col" class="org-right">Estadistico</th>
259+
<th scope="col" class="org-right">Euclideo</th>
260+
</tr>
261+
</thead>
262+
263+
<tbody>
264+
<tr>
265+
<td class="org-left">D1 and D1</td>
266+
<td class="org-right">84.90420168067226%</td>
267+
<td class="org-right">88.6%</td>
268+
</tr>
269+
</tbody>
270+
271+
<tbody>
272+
<tr>
273+
<td class="org-left">D1 and D2</td>
274+
<td class="org-right">94.6%</td>
275+
<td class="org-right">85.8890756302521%</td>
276+
</tr>
277+
278+
279+
<tr>
280+
<td class="org-left">&#xa0;</td>
281+
<td class="org-right">&#xa0;</td>
282+
<td class="org-right">&#xa0;</td>
283+
</tr>
284+
</tbody>
285+
</table>
286+
287+
Se observa que para cantidades pequenias, el euclideo y el estadistico tienen una
288+
diferencia mucho menor que en el caso de tener muchos elementos.
289+
290+
# Validacion cruzada MNIST<a id="orgheadline8"></a>
291+
292+
Igual que en el apartado de validacion cruzada con UCI, aqui se ha subdividido la
293+
matriz en 10 submatrices.
294+
295+
Los resultados son los siquientes:
296+
297+
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
298+
299+
300+
<colgroup>
301+
<col class="org-left" />
302+
303+
<col class="org-right" />
304+
305+
<col class="org-right" />
306+
</colgroup>
307+
<thead>
308+
<tr>
309+
<th scope="col" class="org-left">&#xa0;</th>
310+
<th scope="col" class="org-right">Euclideo</th>
311+
<th scope="col" class="org-right">Estadistico</th>
312+
</tr>
313+
</thead>
314+
315+
<tbody>
316+
<tr>
317+
<td class="org-left">D1 and D1</td>
318+
<td class="org-right">88.6%</td>
319+
<td class="org-right">84.90420168067229%</td>
320+
</tr>
321+
</tbody>
322+
323+
<tbody>
324+
<tr>
325+
<td class="org-left">D1 and D2</td>
326+
<td class="org-right">85.8890756302521%</td>
327+
<td class="org-right">94.6%</td>
328+
</tr>
329+
</tbody>
330+
</table>
331+
332+
# Anexo<a id="orgheadline9"></a>
333+
334+
<div id="footnotes">
335+
<h2 class="footnotes">Footnotes: </h2>
336+
<div id="text-footnotes">
337+
338+
<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1">1</a></sup> <div class="footpara">ETSIINF-UPM: <https://www.fi.upm.es/></div></div>
339+
340+
<div class="footdef"><sup><a id="fn.2" class="footnum" href="#fnr.2">2</a></sup> <div class="footpara">Numpy: <http://www.numpy.org/></div></div>
341+
342+
<div class="footdef"><sup><a id="fn.3" class="footnum" href="#fnr.3">3</a></sup> <div class="footpara">Julia-lang: <http://julialang.org/></div></div>
343+
344+
<div class="footdef"><sup><a id="fn.4" class="footnum" href="#fnr.4">4</a></sup> <div class="footpara">nub: <http://hackage.haskell.org/package/base-4.8.1.0/docs/Data-List.html#v:nub></div></div>
345+
346+
<div class="footdef"><sup><a id="fn.5" class="footnum" href="#fnr.5">5</a></sup> <div class="footpara">UCI: <http://archive.ics.uci.edu/ml/></div></div>
347+
348+
<div class="footdef"><sup><a id="fn.6" class="footnum" href="#fnr.6">6</a></sup> <div class="footpara">MNIST: <http://yann.lecun.com/exdb/mnist/></div></div>
349+
350+
351+
</div>
352+
</div>

src/clasific_estad.jl

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,14 @@ using NPZ
44
import euclideo
55

66
function handle_data(file::AbstractString,
7-
training::Float64=0.6)
7+
training)
88

9-
if file[end-3:end] == ".npy" || file[end-3:end] == ".npz"
10-
matrix = npzread(file)
11-
else
12-
matrix = euclideo.get_matrix(file)
13-
end
9+
matrix = euclideo.get_matrix(file)
1410
rows = size(matrix,1)
15-
training_matrix = matrix[1:convert(Int64,trunc(rows*training)), 1:end]
11+
training_matrix = matrix[training[1]:training[2], 1:end]
1612

17-
if training != 1.0
18-
testing_matrix = matrix[convert(Int64,trunc(rows*training)+1):end,1:end]
13+
if training != (0,0)
14+
testing_matrix = matrix[training[2]+1:end,1:end]
1915
return (training_matrix,testing_matrix)
2016
else
2117
return (training_matrix,training_matrix)

0 commit comments

Comments
 (0)