Sei sulla pagina 1di 30

TutorialsobreestadsticaenPython:I

Distribuciones,grficos,clustering
In [1]: import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as s
In [2]: print np.__version__
import scipy
print scipy.__version__
print matplotlib.__version__
1.8.0
0.9.0
1.3.1

Referencias
Este es un tutorial sobre anlisis estadstico en Python:
(http://www.randalolson.com/2012/08/06/statisticalanalysismadeeasyinpython/)
Esta
es
la
documentacin
de
la
librera
(http://docs.scipy.org/doc/scipy/reference/tutorial/stats.html)

estadstica

de

tutorial

SciPy:

R.

Olson

scipy.stats

OtrotutorialtambinsobreanlisisestadsticoyPython,enformadenotebook:StatisticalDataAnalysisin
Python (https://github.com/fonnesbeck/statisticalanalysispythontutorial), con una parte interesante
dedicadaamodelos
Y un curso con el material disponible en forma de notebooks: Coursera data analysis course, done in
Python(https://github.com/herrfz/dataanalysis).Aunquehedescargadotodoslosnotebooksenlacarpeta
Coursera_dataanalysis,
lo
mejor
es
utilizar
el
ndice
del
fichero
readme
(https://github.com/herrfz/dataanalysis/blob/master/README.md)
El material completo del curso de Cursera est aqu: Coursera Data Analysis
(https://github.com/jtleek/dataanalysis) , aunque los pdf de las lecciones los he descargado en
Dropbox/personal/Rproyectos
ElblogMicropore(http://micropore.wordpress.com/)tienebastantescosasdePythonyastronoma

GeneracindevaloresaleatoriosconNumpy

In [3]: # generacin de valores aleatorios segn distribucin normal


# normal(loc=0.0, scale=1.0, size=None)
# loc es la media, scale la desviacin estndar
# size es un un valor entero
# o una tupla con el shape deseado
alturas = np.random.normal(188, 3, 20)
print alturas
[ 190.09944441
187.08032995
196.58267576
191.81629275

193.31053145
190.53477337
187.70675913
185.77887953

192.10140399
188.38027873
191.99139412
189.25968599

189.08948296
190.74397206
188.14624532
183.90044742

194.01804315
191.10964306
190.57930883
187.989887 ]

In [4]: # Cuando deseamos valores segn la distribucin normal estndar


# (mean=0, stdev =1), podemos utilizar
# standard_normal(size), donde size puede ser un valor entero o un shap
e
np.random.standard_normal((4,2))
Out[4]: array([[-0.12656278, 1.04534887],
[ 0.96472613, -0.95483344],
[ 0.40339144, -2.29152082],
[-1.15241441, 0.73026361]])
In [22]: # Generacin de valores aleatorios segn distribucin binomial
# binomial(n, p, size)
coinFlips = np.random.binomial(1, 0.5, 10)
print coinFlips
[0 1 1 1 1 1 0 0 1 1]

In [9]: # Generacin de valores aleatorios segn la distribucin uniforme


# En un intervalo semiabierto [low, high)
# uniform(low=0.0, high=1.0, size=1)
# size puede ser un entero o una tupla indicando un shape
np.random.uniform(size=10)
Out[9]: array([ 0.5526518 , 0.59462721, 0.13537618, 0.91364061, 0.59570865,
0.24854146, 0.7054177 , 0.17873533, 0.70354042, 0.30468929])

In [15]: # Generacin de valores aleatorios enteros segn la distribucin unifor


me
# en el intervalo semiabierto [low, high)
# o bien, si high se omite, en [0, low)
# size es un entero o una tupla indicando un shape
#randint(low, high=None, size=None)
print np.random.randint(0,12,(3,4))
# Tambin se puede utilizar random_integers, similar a la anterior
# pero que genera valores enteros en el intervalo cerrado
#[low, high]
print
print np.random.random_integers(1,6, size=10)
[[ 5 2 0 8]
[ 8 11 11 7]
[11 9 0 9]]
[6 6 3 4 1 4 1 6 6 1]

ObtencindemuestrasconNumpy
In [16]: # random.choice(a, size=None, replace=True, p=None)
# a es un array 1-D obligatoriamente, o bien un num. entero
# (ver ejemplo siguiente)
# size es un valor entero o una tupla indicando un shape
# p es un array de probabilidades de igual longitud que a
# si se omite se supone distribucin uniforme para a
# replace=False si se desea una muestra sin remplazamiento
np.random.choice(alturas, size=5, replace=False)
Out[16]: array([ 196.58267576, 190.74397206, 189.25968599, 191.99139412,
189.08948296])
In [18]: # Otra posibilidad es hacer a igual a un valor entero n
# Viene bien para por ejemplo indexar con l
# En este caso las muestras se toman del array arange(n)
np.random.choice(10, size = (2,3), replace=False)
Out[18]: array([[1, 2, 8],
[3, 9, 4]])

Fijarunasemilla

In [71]: # Vamos obteniendo valores diferentes en cada llamada a la funcin


np.random.seed(12345)
print np.random.random_integers(1,6, size=10)
print np.random.random_integers(1,6, size=10)
print np.random.random_integers(1,6, size=10)
[3 6 6 2 5 2 6 3 6 2]
[2 4 2 4 1 3 2 4 6 3]
[2 3 4 6 1 6 2 4 5 1]

In [76]: # Y si volvemos a activar la semilla, recomenzamos la misma secuencia


np.random.seed(12345)
print np.random.random_integers(1,6, size=10)
print np.random.random_integers(1,6, size=10)
print np.random.random_integers(1,6, size=10)
[3 6 6 2 5 2 6 3 6 2]
[2 4 2 4 1 3 2 4 6 3]
[2 3 4 6 1 6 2 4 5 1]

In [77]: # Sin embargo una nueva celda del notebook


# comienza simepre con una semilla aleatoria
# a menos que volvamos a fijar una semilla
print np.random.random_integers(1,6, size=10)
print np.random.random_integers(1,6, size=10)
print np.random.random_integers(1,6, size=10)
[4 5 5 6 4 4 2 4 6 3]
[6 4 1 6 3 5 6 4 4 5]
[4 1 4 1 1 4 6 3 5 5]

Estadsticadescriptiva
Media

In [295]: np.random.seed(12345)
x =np.random.randint(0,12,(3,4))
print x
# Obtener la media de todos los valores del array
print "media total: ", x.mean()
# Obtener la media de cada columna
print "media calculada variando la fila: ", x.mean(axis=0)
# Obtener la media de cada fila
print "media calculada variando la columna: ", x.mean(axis=1)
[[ 2 5 1 4]
[ 9 5 2 1]
[ 6 1 11 9]]
media total: 4.66666666667
media calculada variando la fila: [ 5.66666667 3.66666667 4.66666667
4.66666667]
media calculada variando la columna: [ 3.
4.25 6.75]

Varianzaydesviacinestndar
In [291]: # varianza muestral (dividiendo por n-1)
print x.var(ddof=1)
print x.var(ddof=1, axis=0)
print x.var(ddof=1, axis=1)
12.2424242424
[ 12.33333333 5.33333333 30.33333333 16.33333333]
[ 3.33333333 12.91666667 18.91666667]

In [292]: # Desviacin tpica muestral


print x.std(ddof=1)
print x.std(ddof=1, axis=0)
print x.std(ddof=1, axis=1)
3.49891758154
[ 3.51188458 2.30940108 5.50757055 4.04145188]
[ 1.82574186 3.59397644 4.34932945]

Relacinlinealentredosvariables
Enesteapartadoutilizaremoselpaqueteestadsticodescipy,queseimportacon:
"importscipy.statsass"

CoeficientedecorrelacinrdePearson

In [54]: # Construyamos dos arrays x e y con los que experimentar


np.random.seed(12345)
x = np.random.uniform(0,10,size=20)
noise = np.random.uniform(0, 3, size=20)
y = 5 + x + noise
plt.scatter(x,y);

In [45]: r, p = s.pearsonr(x,y)
print r, p
0.966159857324 4.88820573698e-12

El coeficiente de determinacin es el cuadrado del coeficiente de correlacin r, y se interpreta como el


porcentajedevariabilidaddelavariabley queesexplicadoporelmodelolineal.
In [39]: # El valor de r**2 es el coeficiente de determinacin,
# que indica la fortaleza de la relacin entre ambas variables
print u"El coeficiente de determinacin es %.2f" %r**2
# El 93% de la variacin de y se puede explicar por la variable x,
# el resto ser debido a causas desconocidas, variables ocultas
# o variabilidad inherente
El coeficiente de determinacin es 0.93

Regresinlineal
Clculodelosparmetrosdelarectaderegresinlinealsehacenconlafuncinlinregress()deScipy.
http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.mstats.linregress.html
In [48]: slope, intercept, r_value, p_value, std_err = s.linregress(x, y)

In [49]: print r_value


0.966159857324

In [53]: plt.scatter(x,y)
plt.plot([0, 10], [intercept, slope * 10 + intercept], '-r', lw=2);

Factores/variablescategricas
In [228]: # Los factores de R equivalen a las variables categricas de Pandas
ciudades = np.array(['Madrid', 'Cuenca', 'Toledo', 'Madrid', 'Soria', '
Toledo', 'Madrid'])
cF = pd.Categorical.from_array(ciudades)
cF
Out[228]: Categorical:
[Madrid, Cuenca, Toledo, Madrid, Soria, Toledo, Madrid]
Levels (4): Index(['Cuenca', 'Madrid', 'Soria', 'Toledo'], dtype=object)
In [231]: # Los niveles de la variable categrica son los valores diferentes que
toma
cF.levels
Out[231]: Index([u'Cuenca', u'Madrid', u'Soria', u'Toledo'], dtype=object)
In [232]: # Los labels son el contenido de la variable, codificada numricamente
# haciendo referencia a los levels
cF.labels
Out[232]: array([1, 0, 3, 1, 2, 3, 1])

LasdistribucionesdeprobabilidadconScipy
Cuestionesdenotacin

Dada una variable aleatoria X , el rango de X , RX es el conjunto de valores que puede tomar. Cada
valor x RX es llamado un cuantil, y la probabilidad de que X tome el valor x se designa por
P (X = x)

Un"randomvariate"esunresultadoparticulardeunavariablealeatoria.
VamosautilizarelpaquetestatsdeScipy,quenormalmenteseimportacon:"importscipy.statsass".
Todas las distribuciones de probabilidad tienen en este paquete un tratamiento similar, con los mismos
mtodosentodasellas.Porejemplo,paraverlosmtodosdeladistribucinnormal,hacer:
prints.norm.doc

Ladistribucinnormal
In [12]: # pdf: Probability Density Function
# s.norm.pdf(array x de cuantiles, loc, scale)
# loc es la media, scale es la desviacin estndar
x = np.linspace(-5, 5, num=100)
normalDensity = s.norm.pdf(x, loc=0, scale=1)
plt.plot(x, normalDensity)
plt.xlabel('cuantiles');

In [13]: # cdf: Cumulative Distribution Function


# s.norm.pdf(array de cuantiles, loc, scale)
# loc es la media, scale la desviacin estndar
# Probabilidad de |X| < sigma
sigma = 4
print "%.3f %%" %(s.norm.cdf(sigma, loc=0, scale=sigma)-s.norm.cdf(-sig
ma, loc=0, scale=sigma))
0.683 %

In [15]: # ppf: Percent Point Function (Inversa de CDF)


s.norm.ppf(0.683/2 + 0.5, loc=0, scale=1)
Out[15]: 1.0006418287624492
In [16]: # Devuelve la media y varianza de la distribucin
s.norm.stats(loc=3, scale=4)
Out[16]: (array(3.0), array(16.0))
In [17]: # rvs: generacin de valores aleatorios (random variates)
# bajo la variable aleatoria considerada ( la normal en el ejemplo)
s.norm.rvs(loc=5, scale=2, size=10)
Out[17]: array([ 2.07049884, 5.71139329, 5.58134749, 6.19376692, 5.92728227,
4.37584035, 4.60381517, 7.66738297, 8.44622194, 1.63065077])
"Freezing"
Conelfindenotenerqueescribirencadacasolosparmetroslocyscaledeunadistribucin,sepuede
definirunavariablealeatoriacon"rv"deltipoyconlosparmetrosdeseados,ydespuesreferirnosaella
con el nombre de la variable que le hayamos dado. Es decir, el objeto que hemos definido tiene los
mismosmtodosqueladistribucinoriginal
In [21]: mi_rv = s.norm(loc=5, scale=2)
mi_rv.stats()
Out[21]: (array(5.0), array(4.0))
In [24]: mi_rv.rvs(size=10)
Out[24]: array([ 6.16432526, 5.48459398, 3.25193664, 3.58073744, 7.89030591,
6.35598259, 4.12032957, 4.99845849, 6.55752111, 3.26517431])

Distribucinbinomial
In [34]: # pmf: Probability Mass Function
# Sustituye a pdf en las variables discretas
# pmf(x, n, pr)
x=[0,1,2]
s.binom.pmf(x,2, 0.5)
Out[34]: array([ 0.25, 0.5 , 0.25])

Grficosexploratorios
Representarmuchospuntos

In [297]: x = np.random.normal(size=1e4)
y = np.random.normal(size=1e4)
plt.scatter(x, y);
# con plt.plot(x,y, 'o') hubieramos obtenido el mismo resultado
Out[297]: <matplotlib.collections.PathCollection at 0x268a7950>

Aqu no se ve nada, una posibilidad es representar una muestra (consideramos los valores de x e y
emparejados)
In [298]: r = np.random.choice(10**4, size=1000, replace=False)
plt.scatter(x[r], y[r]);

In [309]: # Tambin puede intentarse variar la transperencia


# y tamao de los puntos
plt.scatter(x, y, edgecolors='none', alpha=0.025, s=60);

In [310]: # Y otra opcin es utilizar un grfico de R


%load_ext rmagic
%Rpush x y
%R smoothScatter(x, y, nrpoints=0)
The rmagic extension is already loaded. To reload it, use:
%reload_ext rmagic

In [8]: # Se puede aadir como opcin un color map, por ejemplo:


# cmap=plt.cm.Greys
# cmap=plt.cm.Reds
# # cmap=plt.cm.hot
plt.hexbin(x, y) # El color en cada hexgono corresponde a la frecuenci
a
# Tambin se puede utilizar la opcin bins=n para norm
alizar
cb=plt.colorbar()
cb.set_label('frecuencias')
fig = plt.gcf() # Get current figure
fig.set_size_inches(10,8)

Ahora,elmismoejemploutilizandofigureyaxisexplcitamente:

In [9]: fig, ax = plt.subplots()


fig.set_size_inches(10,8)
im = ax.hexbin(x,y)
fig.colorbar(im, ax=ax);

Acontinuacinharemosunhistograma2d,debajaresolucinparapoderanalizarlo

In [40]: fig, ax = plt.subplots()


fig.set_size_inches(10,8)
hist, xedges, yedges, im = ax.hist2d(x,y, bins=(10,10),
range=[[-4.,4.], [-4., 4.]])
fig.colorbar(im, ax=ax);

Vamosaverloquesignificacadaunadelasvariablesdevueltasporhist2d:
In [26]: # hist es la frecuencia en cada bin, en este caso un grid de 10x10
print hist.shape
print hist
(10, 10)
[[ 0.
0.
0.
[ 0.
0.
7.
[ 0.
4. 26.
[ 0. 10. 62.
[ 2. 17. 134.
[ 4. 19. 130.
[ 0.
9. 93.
[ 1.
4. 24.
[ 1.
0.
6.
[ 0.
0.
0.

1.
18.
69.
234.
445.
456.
239.
90.
12.
0.

2.
17.
136.
449.
845.
824.
451.
137.
13.
0.

5.
19.
151.
455.
823.
824.
435.
151.
20.
3.

0.
0.
10.
6.
61. 16.
220. 67.
477. 135.
447. 147.
253. 72.
78. 20.
15.
6.
2.
0.

0.
0.
6.
9.
27.
23.
14.
3.
0.
0.

0.]
0.]
0.]
2.]
2.]
2.]
1.]
0.]
0.]
0.]]

In [31]: # xbins e ybins son los lmites de los intervalos semiabiertos


# que definen cada bin
print xbins
print ybins
[-4. -3.2 -2.4 -1.6 -0.8 0.
[-4. -3.2 -2.4 -1.6 -0.8 0.

0.8 1.6 2.4 3.2 4. ]


0.8 1.6 2.4 3.2 4. ]

Ahoravamosavercomopodemosrepresentarundiagramadecontornossobrelapropiafigura.Loque
queremosrepresentarcomoterceramagnitudsonlasfrecuenciasencadacelda...
Hayunejemploen:http://micropore.wordpress.com/2011/10/01/2ddensityplotor2dhistogram/
In [263]: fig, ax = plt.subplots()
fig.set_size_inches(10, 8)
# Rango de valores en cada eje
rango = [[-4., 4.],[-4., 4.]]
# Generamos el histograma y el grfico a la vez
# Valores de bins elevados dan mucha fragmentacin en las curvas
hist, xedges, yedges, im = ax.hist2d(x,y, bins=(30,30),
range=rango, cmap=plt.cm.Greys)
fig.colorbar(im, ax=ax);
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
# Niveles para las curvas de nivel
niveles = [30, 50, 70, 90]
colores=['green', 'blue', 'yellow', 'red']
cset = ax.contour(hist, niveles, linewidths=2, extent=extent, colors=co
lores)
ax.clabel(cset, inline=1, fontsize=15, fmt='%d')

Out[263]: <a list of 4 text.Text objects>

Pero,supongamosquesoloqueremosloscontornosynoqueremosrepresentarlafiguradelhistograma.
Enesecasoelhistogramalogeneramosconnumpy

In [262]: fig, ax = plt.subplots()


fig.set_size_inches(8, 8)
# Rango de valores en cada eje
rango = [[-4., 4.],[-4., 4.]]
# Generamos un histograma wD de frecuencias con numpy
hist, xedges, yedges= np.histogram2d(x,y, bins=(30,30),
range=rango)
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
# Niveles para las curvas de nivel de las frecuencias
niveles = [30, 50, 70, 90]
colores=['green', 'blue', 'yellow', 'red']
cset = ax.contour(hist, niveles, linewidths=2, extent=extent, colors=co
lores)
ax.clabel(cset, inline=1, fontsize=15, fmt='%d');

Veamosahoraquesignificanormalizarloshistogramas.Empecemosconeldecontornos:

In [200]: rango = [[-4., 4.],[-4., 4.]]


hist, xedges, yedges= np.histogram2d(x,y, bins=(30,30),
range=rango)
total_count = sum(hist)
print total_count
print hist[14:16,14:16]
9998.0
[[ 111. 115.]
[ 100. 111.]]

Ahora normalizamos. El array 2D ahora contiene la densidad en cada bin, es decir, el nmero de
observacionesenelbindivididoporelreadelbin.
In [229]: rango = [[-4., 4.],[-4., 4.]]
hist, xedges, yedges= np.histogram2d(x,y, bins=(30,30),
range=rango)
histn, xedges, yedges= np.histogram2d(x,y, bins=(30,30),
range=rango, normed=True)
print "el resultado es:"
print histn[14:16,14:16]
# obtenido del siguiente modo:
hist_suma_1 = hist/sum(hist)
print '\n'
area = 8. * 8. / (30*30)
print hist_suma_1[14:16,14:16]/area
el resultado es:
[[ 0.15612497 0.1617511 ]
[ 0.14065313 0.15612497]]
[[ 0.15612497 0.1617511 ]
[ 0.14065313 0.15612497]]

Dehecho,siconsideramosquelamatrizhistnesunamatrizdedensidades,cumplir:
suma(densidad_ixareabin_i)=64/900xsuma(densidad_i)=64/900*sum(histn)=1
Enefecto:
In [232]: 64./900 * sum(histn)
Out[232]: 0.99999999999999833

In [236]: # Este es un ejemplo con valores normalizados. Las curvas dicen


# Que por ejemplo la densidad es superior a 0.01 dentro de la curva
fig, ax = plt.subplots()
fig.set_size_inches(8, 8)
# Rango de valores en cada eje
rango = [[-4., 4.],[-4., 4.]]

histn, xedges, yedges= np.histogram2d(x,y, bins=(30,30),


range=rango, normed=True)
extent = [yedges[0], yedges[-1], xedges[0], xedges[-1]]
# Niveles para las curvas de nivel de las densidades
niveles = [0.01,0.05, 0.1, 0.15]
colores=['green', 'blue', 'yellow', 'red']
cset = ax.contour(histn, niveles, linewidths=2, extent=extent, colors=c
olores)
ax.clabel(cset, inline=1, fontsize=15, fmt='%.2f');

Heatmaps

En lugar de emplear la funcin plt.hist2d, tambin se puede generar un histograma 2D con


numpy.histogram2dy,yrepresentarloconimshow():

imshow()seempleapararepresentarimgenes.Ennuestrocasolaimagenserunamatrizbidimensional,
generadaconhistogram2d(),dondecadaceldacorrespondeaunbin,yenellahayunvalorentero(una
cuentadeobservacionesquecaendentrodelbin).Demodoqueimshow()lointerpretacomounaimagen
enescaladegrises,aunquelopinteencolor,dependiendodelmapadecolorqueutilicemos.Estotiene
comoconsecuenciaqueimshow()suavizalaimagen(losbins/pixels)nosemuestranconclaridad.
In [270]: # generamos datos de test con la distribucin normal estndar
x = np.random.randn(8873)
y = np.random.randn(8873)
heatmap, xedges, yedges = np.histogram2d(x, y, bins=50) # genera un hea
tmap 50x50
extent = [xedges[0], xedges[-1], yedges[0], yedges[-1]]
plt.imshow(heatmap, extent=extent);

En cambio, matshow() representa la matriz sin hacer ningun suavizado. Por ello matshow es la mejor
opcincuandosequiereutilizarunmapadecoloresparavercomosedistribuyenlasobservaciones.
In [273]: plt.matshow(heatmap, extent=extent);

Clustering

Agrupamientojerrquico(hierarchicalclustering)
La idea del clustering o agrupamiento jerrquico es construir un arbol de smilaridades basado en
distanciasentrecadadosobservaciones.
Referencia
a
la
librera
scipy.cluster.hierarchy
(http://docs.scipy.org/doc/scipy/reference/cluster.hierarchy.html#modulescipy.cluster.hierarchy)
Referencia
a
la
librera
(http://docs.scipy.org/doc/scipy/reference/spatial.distance.html)
In [89]: from scipy.spatial.distance import pdist, squareform
from scipy.cluster.hierarchy import linkage, dendrogram

scipy.spatial.distance

In [90]: np.random.seed(12345)
clase1 = np.random.normal(loc=1,scale=0.2,size=(4,2))
clase2 = np.random.normal(loc=2,scale=0.2,size=(4,2))
clase3 = np.random.normal(loc=3,scale=0.2,size=(4,2))
clases = vstack((clase1, clase2, clase3))
x = clases[:,0]
y = clases[:,1]
plt.scatter(x,y, s=60)
for i in range(12):
plt.text(x[i]-0.025, y[i]+0.1,i)

Vamosacrearundataframeconlas12observaciones:

In [109]: df = pd.DataFrame(clases, columns=['x', 'y'])


df
Out[109]:

0.959058 1.095789

0.896112 0.888854

1.393156 1.278681

1.018582 1.056349

2.153805 2.249287

2.201438 1.740756

2.054998 2.045783

2.270583 2.177286

2.599673 2.925631

3.333805 2.912286

10 2.892052 3.095397
11 3.649789 2.795754

Lafuncinpdist()calculaladistanciadecadaunodelos12puntosconrespectoalosdems.Secreaun
arrayden(n 1)/2 valores
In [93]: dm = pdist(df,metric='euclidean')
dm.shape
Out[93]: (66,)

Acontinuacin,hacemoselclustering
In [101]: z = linkage(dm, method='complete')
z.shape
Out[101]: (11, 4)
Yconstruimosundendrograma

In [102]: dendrogram(z);

In [106]: # Se pueden buscar otras orientaciones


dendrogram(z, orientation='right');

Porcuriosidad,lasdistanciastambinsepuedenponerenformadematrizcuadrada,aunquecomoseha
visto,noesprecisoparacalcularelclustering:
In [94]: distxy = squareform(dm)
distxy.shape
Out[94]: (12, 12)
In [95]: # Como vemos, es una matriz simtrica con 0 en la diagonal
distxy[0:3,0:3]
Out[95]: array([[ 0.
, 0.21629657, 0.47105247],
[ 0.21629657, 0.
, 0.63167861],
[ 0.47105247, 0.63167861, 0.
]])

kclustering

El algoritmo "kmeans" toma como entrada el nmero de clusters a generar, k (esto es su principal
limitacin) y un conjunto de vectores resultado de observaciones (en nuestro caso los 12 pares de
coordenadas x,y). Devuelve un conjunto de k centroides, uno por cada cluster. Las observaciones son
clasificadasmedianteelnmerodelcluster(elindexdelcentroidemsprximo).
Este proceso se conoce a veces como "cuantificacin" de los vectores de las observaciones. Al cluster
index de un vector se le llama el "cdigo" y la tabla que asocia cdigos y centroides se conoce como el
"codebook"
In [107]: from scipy.cluster.vq import kmeans, vq
In [127]: codebook, varianza = kmeans(df,3)
-------------------------------------------------------------------------TypeError
Traceback (most recent call la
st)
<ipython-input-127-06fc099cba65> in <module>()
----> 1 codebook, varianza = kmeans(df,3)
/usr/lib/python2.7/dist-packages/scipy/cluster/vq.pyc in kmeans(obs, k_o
r_guess, iter, thresh)
505
for i in range(iter):
506
#the intial code book is randomly selected from obse
rvations
--> 507
guess = take(obs, randint(0, No, k), 0)
508
book, dist = _kmeans(obs, guess, thresh = thresh)
509
if dist < best_dist:
/usr/local/lib/python2.7/dist-packages/numpy/core/fromnumeric.pyc in tak
e(a, indices, axis, out, mode)
116
except AttributeError:
117
return _wrapit(a, 'take', indices, axis, out, mode)
--> 118
return take(indices, axis, out, mode)
119
120
TypeError: take() takes at most 4 arguments (5 given)
In [128]: # parece que a la funcin kmeans no le gustan los dtaframes de pandas
codebook, varianza = kmeans(np.vstack(zip(x,y)),3)
In [129]: # sin embargo... pasandolo a array de numpy, funciona
codebook, varianza = kmeans(df.values,3)
In [132]: # En realidad, esto no lo necesitamos para nada
print distortion
0.262435264634

In [131]: # estos son los centroides de los tres grupos:


print codebook
[[ 1.0667271 1.07991825]
[ 2.17020602 2.05327779]
[ 3.11882952 2.93226726]]

In [133]: # A continuacin, la funcin vq() asigna nmeros de clusters (cdigos d


el codebook) a las observaciones:
In [134]: code,distance = vq(df.values,codebook)
In [136]: # As obtenemos el cdigo de cada observacin
code
Out[136]: array([0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2])
In [138]: colores = ['red', 'blue', 'green']
c = [colores[i] for i in code]
print c
['red', 'red', 'red', 'red', 'blue', 'blue', 'blue', 'blue', 'green', 'g
reen', 'green', 'green']

In [139]: plt.scatter(x,y, s=60, c=c)


Out[139]: <matplotlib.collections.PathCollection at 0x5927650>

Ejemplocompletodeclustering
ParaesteejemplotenemosqueleerunficherodedatosenelformatobinariopropietariodeR:RData.Por
esolomejoresleerloconRydespuespasarloaundataframedePandas

In [148]: !ls ./datos


foods-2011-10-03.json
hola
phoenix.html
phoenix-tidied.html

prueba
prueba2.csv
prueba3.csv
prueba4.csv

prueba4.txt samsungData.rda
prueba5.txt warnings
prueba.csv
prueba.html

In [144]: %load_ext rmagic


In [149]: %%R
load("./datos/samsungData.rda")
write.csv(samsungData,file="./datos/samsungData.csv")
In [150]: !ls ./datos
foods-2011-10-03.json
hola
phoenix.html
phoenix-tidied.html

prueba
prueba2.csv
prueba3.csv
prueba4.csv

prueba4.txt samsungData.csv
prueba5.txt samsungData.rda
prueba.csv warnings
prueba.html

In [151]: samsungData = pd.read_csv('./datos/samsungData.csv')


In [152]: samsungData.tail()
Out[152]: <class 'pandas.core.frame.DataFrame'>
Int64Index: 5 entries, 7347 to 7351
Columns: 564 entries, Unnamed: 0 to activity
dtypes: float64(561), int64(2), object(1)
In [153]: samsungData.shape
Out[153]: (7352, 564)
In [165]: # Nombres de las 10 primeras columnas
samsungData.columns[0:10]
Out[165]: Index([u'tBodyAcc-mean()-X', u'tBodyAcc-mean()-Y', u'tBodyAcc-mean()-Z',
u'tBodyAcc-std()-X', u'tBodyAcc-std()-Y', u'tBodyAcc-std()-Z', u'tBodyA
cc-mad()-X', u'tBodyAcc-mad()-Y', u'tBodyAcc-mad()-Z', u'tBodyAcc-max()X'], dtype=object)
In [168]: # Nombres de las 10 ltimas columnas
samsungData.columns[-10:]
Out[168]: Index([u'fBodyBodyGyroJerkMag-kurtosis()', u'angle(tBodyAccMean,gravity)
', u'angle(tBodyAccJerkMean),gravityMean)', u'angle(tBodyGyroMean,gravit
yMean)', u'angle(tBodyGyroJerkMean,gravityMean)', u'angle(X,gravityMean)
', u'angle(Y,gravityMean)', u'angle(Z,gravityMean)', u'subject', u'activ
ity'], dtype=object)
In [161]: samsungData = samsungData.drop('Unnamed: 0', axis=1)

In [162]: samsungData.columns[0:10]
Out[162]: Index([u'tBodyAcc-mean()-X', u'tBodyAcc-mean()-Y', u'tBodyAcc-mean()-Z',
u'tBodyAcc-std()-X', u'tBodyAcc-std()-Y', u'tBodyAcc-std()-Z', u'tBodyA
cc-mad()-X', u'tBodyAcc-mad()-Y', u'tBodyAcc-mad()-Z', u'tBodyAcc-max()X'], dtype=object)
In [163]: samsungData['activity'].value_counts()
Out[163]: laying
1407
standing
1374
sitting
1286
walk
1226
walkup
1073
walkdown
986
dtype: int64
In [178]: # para hacernos una idea de como viene codificado el dataframe
# vamos a listar un subconjunto:
samsungData.ix[985:995,[0,1,2,3,4,5,-2,-1]]
Out[178]:

tBodyAcc tBodyAcc tBodyAcc tBodyAcc tBodyAcc tBodyAcc


subject activ
mean()X mean()Y mean()Z std()X
std()Y
std()Z
985 0.198992

0.002455

0.117281

0.100775

0.355080

0.266647

walku

986 0.158101

0.040474

0.134750

0.063741

0.265524

0.299606

walku

987 0.281287

0.034803

0.089352

0.064575

0.314012

0.280909

walku

988 0.418010

0.016577

0.153921

0.047141

0.283657

0.178543

walku

989 0.428925

0.037568

0.169470

0.033747

0.300829

0.229894

walku

990 0.292996

0.036746

0.111782

0.953571

0.863929

0.870786

stand

991 0.276552

0.028512

0.110449

0.987560

0.945003

0.944290

stand

992 0.271818

0.032274

0.113994

0.995988

0.959353

0.955563

stand

993 0.275229

0.010966

0.089999

0.995814

0.958768

0.976571

stand

994 0.279222

0.005795

0.092436

0.996173

0.969167

0.980864

stand

995 0.276892

0.018711

0.109727

0.994897

0.972814

0.963744

stand

Hayunalneaporsujetoylecturadelosaccelermetros,yacadavectordeobservacionesseasignauna
actividad.Acontinuacinvamosairprobandovariablesdelsujeto1,yviendosiestasvariablesdiscriminan
bienentreactividades:
In [205]: # Array de actividades
acts = samsungData['activity'].unique()
# secuencia de colores
cols = 'bgrcmy'

In [206]: # Crear un diccionario de colores


dic_col = {acts[i]:cols[i] for i in range(len(acts))}
dic_col
Out[206]: {'laying': 'r',
'sitting': 'g',
'standing': 'b',
'walk': 'c',
'walkdown': 'm',
'walkup': 'y'}
In [207]: # Seleccionamos las filas del primer sujeto
subj1 = samsungData[samsungData['subject']==1]
# Ahora creamos un objeto "groupby" para agrupar por actividad
grouped = subj1.groupby('activity')
In [212]: #En abcisas vamos a representar los valores de la primera variable
# Y en ordenadas el nmero de la observacin (la lectura)
# Siempre referido al sujeto 1
fig, (ax1, ax2) = plt.subplots(1,2, sharey=True)
fig.set_size_inches(10, 5)
for act, df in grouped:
ax1.scatter(df.ix[:,0], df.index, c=dic_col[act], label=act)
ax2.scatter(df.ix[:,1], df.index, c=dic_col[act], label=act)
ax1.set_xlabel(samsungData.columns[0])
ax1.set_ylabel(u'# Observacin')
ax2.set_xlabel(samsungData.columns[1])
ax2.legend(loc='upper left')

Conclusin:lasdosprimerasvariablesnonospermitendiscriminarportiposdeactividad
Ahoravamosaprobarahacerunagrupamientojerrquicobasadoenlastresprimerascolumnas,aversi
estonospermitesepararporgruposconuntipodeactividad

In [233]: # Construimos una variable categrica (factor) con las actividades


# Ya que de esta manera actF.labels contendr la actividad
# codificada numricamente de 0 a 5
actF = pd.Categorical.from_array(subj1['activity'])
In [243]: dm = pdist(subj1.ix[:,0:3],metric='euclidean')
z = linkage(dm, method='complete')
# plt.figure(figsize=(5, 10))
# Una forma de dar el tamao de la fi
gura
dendrogram(z, orientation='right', color_threshold=0.2,
leaf_label_func=lambda n : 'X' * (actF.labels[n] + 1));
fig = plt.gcf() # Get current figure
fig.set_size_inches(5,10) # Otra forma de dar el tamao

Vamosaprobarahoraconlascolumnas9y10

In [245]: #En abcisas vamos a representar los valores de la primera variable


# Y en ordenadas el nmero de la observacin (la lectura)
# Siempre referido al sujeto 1
fig, (ax1, ax2) = plt.subplots(1,2, sharey=True)
fig.set_size_inches(10, 5)
for act, df in grouped:
ax1.scatter(df.ix[:,9], df.index, c=dic_col[act], label=act)
ax2.scatter(df.ix[:,10], df.index, c=dic_col[act], label=act)
ax1.set_xlabel(samsungData.columns[9])
ax1.set_ylabel(u'# Observacin')
ax2.set_xlabel(samsungData.columns[10])
ax2.legend(loc='upper left')

Continuaremosesteejemplomsadelanteunavezhayamosvistoelanlisisdecomponentesprincipales
(PCA)
In []:

Potrebbero piacerti anche