Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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
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 ]
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
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]
Relacinlinealentredosvariables
Enesteapartadoutilizaremoselpaqueteestadsticodescipy,queseimportacon:
"importscipy.statsass"
CoeficientedecorrelacinrdePearson
In [45]: r, p = s.pearsonr(x,y)
print r, p
0.966159857324 4.88820573698e-12
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 [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');
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]);
Ahora,elmismoejemploutilizandofigureyaxisexplcitamente:
Acontinuacinharemosunhistograma2d,debajaresolucinparapoderanalizarlo
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.]]
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')
Pero,supongamosquesoloqueremosloscontornosynoqueremosrepresentarlafiguradelhistograma.
Enesecasoelhistogramalogeneramosconnumpy
Veamosahoraquesignificanormalizarloshistogramas.Empecemosconeldecontornos:
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
Heatmaps
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:
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);
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
Ejemplocompletodeclustering
ParaesteejemplotenemosqueleerunficherodedatosenelformatobinariopropietariodeR:RData.Por
esolomejoresleerloconRydespuespasarloaundataframedePandas
prueba
prueba2.csv
prueba3.csv
prueba4.csv
prueba4.txt samsungData.rda
prueba5.txt warnings
prueba.csv
prueba.html
prueba
prueba2.csv
prueba3.csv
prueba4.csv
prueba4.txt samsungData.csv
prueba5.txt samsungData.rda
prueba.csv warnings
prueba.html
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]:
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'
Conclusin:lasdosprimerasvariablesnonospermitendiscriminarportiposdeactividad
Ahoravamosaprobarahacerunagrupamientojerrquicobasadoenlastresprimerascolumnas,aversi
estonospermitesepararporgruposconuntipodeactividad
Vamosaprobarahoraconlascolumnas9y10
Continuaremosesteejemplomsadelanteunavezhayamosvistoelanlisisdecomponentesprincipales
(PCA)
In []: