Contenidos de «Complementos de Estadística»
Índice
- 1. R y Python
- 1.1. Instalación
- 1.2. Repaso de lo visto en el grado (con Rcmdr)
- 1.2.1. instalación y carga del paquete Rcmdr
- 1.2.2. Obtener datos
- 1.2.3. Guardar datos
- 1.2.4. Descriptivos
- 1.2.5. Modificar datos
- 1.2.6. Distribuciones de probabilidad
- 1.2.7. Contrastes de hipótesis sobre medias, proporciones…
- 1.2.8. Contrastes de hipótesis sobre independencia
- 1.2.9. Regresión lineal
- 1.3. Lenguaje
- 1.4. Repaso de lo visto (en lenguaje de programación)
- 2. filtrado
- 3. descriptiva
- 4. probabilidad
- 5. inferencia
- 6. modelos lineales
1 R y Python
1.1 Instalación
1.1.1 R
1.1.1.1 ReactOS y Windows
- Descargar el último R desde https://cran.r-project.org/bin/windows/base
- Interfases opcionales:
- el paquete
Rcmdr
(commander); instalarlo desde el menú Paquetes del RGui o escribiendo en la R Console la siguiente orden:install.packages ("Rcmdr")
- RStudio
- Emacs Speaks Statistics desde Emacs para Windows
- el paquete
1.1.1.2 Debian y Ubuntu
apt install r-cran-rcmdr rkward ess
1.1.2 Python
1.1.2.1 ReactOS y Windows
- Descargar el instalador de https://www.python.org/downloads/release
- Una vez instalado, ejecutar en el terminal
cmd.exe
(quizá haya que pulsar intro alguna vez):py -m pip install --user --upgrade pip py -m pip install --user numpy scipy pandas statsmodels matplotlib sklearn
1.1.2.2 Debian y Ubuntu
apt install python3-pandas python3-dill python3-sklearn # módulos necesarios para tratar datos apt install python-numpy-doc python-scipi-doc python-pandas-doc python-sklearn-doc # documentación
El editor usado en el aula P3:
apt install idle-python3.5
1.2 Repaso de lo visto en el grado (con Rcmdr)
Guiones de la asignatura Estadística del primer curso del grado.
1.2.1 instalación y carga del paquete Rcmdr
Instalarlo como paquete de R:
install.packages ("Rcmdr")
Cargarlo:
library ("Rcmdr") # o bien: library(Rcmdr)
Si se cierra el Rcmdr sin salir de R, para volver a abrirlo hay que ejecutar
Commander()
Fijarse especialmente en la Ventana de instrucciones.
1.2.2 Obtener datos
1.2.2.1 De ejemplo
- Menú Datos, submenú Conjunto de datos en paquetes.
1.2.2.2 En formato nativo de R
- Menú Datos, opción Cargar conjunto de datos.
- Habitualmente, dichos ficheros tienen extensión
.rda
ó.RData
. - Pueden contener
- un solo conjunto de datos (cuyo nombre puede coincidir o no con el nombre del fichero)
- múltiples conjuntos de datos, además de variables, funciones, etc. (entorno de trabajo de R)
1.2.2.3 En formatos ajenos
- Menú Datos, submenú Importar datos.
- De especial interés es la importación de datos de texto (CSV)
- ¿campos delimitados o de anchura fija?
- codificación: utf-8 (unicode) o latin-1 (iso-8859-1, -15)
- Ejercicio: importar los siguientes conjuntos de datos
- vacas.csv
- vacas.txt
- los participantes del campus virtual
- vacas.blancos1
- vacas.blancos2
1.2.3 Guardar datos
- Menú Fichero, submenú Guardar el entorno de trabajo R como….
- Guarda todas las variables, incluyendo funciones y conjuntos de datos.
- Menú Datos, submenú Conjunto de datos activo, opción Guardar el conjunto de datos activo.
- Lo guarda con el formato nativo de R,
.rda
ó.RData
.
- Lo guarda con el formato nativo de R,
- Menú Datos, submenú Conjunto de datos activo, opción Exportar el conjunto de datos activo.
- Lo guarda en formato de tabla: registros separados por salto de renglón; campos separados por coma o punto-y-coma o tabulador… (llamado habitualmente CSV)
- Ejercicio:
- Guardar el entorno de trabajo de R como
iot-estadistica.rda
. Salir de R, volver a entrar en R, cargar dicho fichero y comprobar que se conservan todos los datos. - Cargar el conjunto de datos de ejemplo llamado
mtcars
. Exportarlo a un ficheromtcars.rda
y a un ficheromtcars.csv
.
- Guardar el entorno de trabajo de R como
1.2.4 Descriptivos
- Menú Estadísticos, submenú Resúmenes, opción Conjunto de datos activo.
- Ídem, opción Distribución de frecuencias.
- Ídem, opción Resúmenes numéricos.
- Menú Gráficas, opciones
- gráfica de barras
- gráfica de sectores
- histograma
- diagrama de caja
- Ejercicio:
- Realizar un informe descriptivo univariante de
mtcars
.
- Realizar un informe descriptivo univariante de
1.2.5 Modificar datos
- Menú Datos: Modificar variables…: Calcular…
- Menú Datos: Modificar variables…: Recodificar…
- Menú Datos: Modificar variables…: Reordenar niveles…
- Filtrar
- Ejercicio:
- Convertir al «sistema métrico» las siguientes variables de
mtcars
: wt, disp, hp, mpg - Cargar los datos de ejemplo
Chile
y crear un conjunto de datos llamadoChile.f
que contenga los registros tales quesex
seaF
y tales queage
sea menor que 50. - Hacer un diagrama de barras de la variable
education
con el orden correcto.
- Convertir al «sistema métrico» las siguientes variables de
1.2.6 Distribuciones de probabilidad
- Menú Distribuciones
- uniforme, gausiana, exponencial, binomial, puasón
- Ejercicio:
- Generar un conjunto de cien mil valores aleatorias de la variable
altura
como valores gausianos de media 170 y desviación típica 10. - Generar un conjunto de cien mil registros aleatorios que contenga la variable
trabaja
con valoressí
(probabilidad 30%) yno
(probabilidad 70%).
- Generar un conjunto de cien mil valores aleatorias de la variable
1.2.7 Contrastes de hipótesis sobre medias, proporciones…
- Menú Estadísticos: Resúmenes: Test de normalidad de Shapiro.
- Menú Estadísticos: Medias: Test t para una muestra.
- Menú Estadísticos: Proporciones: Test de proporciones para una muestra.
- Menú Estadísticos: Test no paramétricos: Test de Wilcoxon para una muestra
- Menú Estadísticos: Proporciones: Test de proporciones para dos muestras.
- Menú Estadísticos: Varianzas: Test F para dos varianzas.
- Menú Estadísticos: Medias: Test t para muestras independientes.
- Menú Estadísticos: Medias: Test t para muestras relacionadas.
- Menú Estadísticos: Test no paramétricos: Test de Wilcoxon para dos muestras
- Menú Estadísticos: Test no paramétricos: Test de Wilcoxon para muestras pareadas
- Ejercicio:
- ¿Existen diferencias significativas entre los «consumos» (mpg)
de los coches de
mtcars
con distintas =am»? - ¿Es una muestra aleatoria simple?
- ¿Existen diferencias significativas entre los «consumos» (mpg)
de los coches de
1.2.9 Regresión lineal
- Estadísticos: Resúmenes: Matriz de correlaciones
- Gráficas: Matriz de diagrama de dispersión
- Gráficas: Diagrama de dispersión
- Estadísticos: Ajuste de modelos: Regresión lineal
- Modelos: Gráficos: Gráficas básicas de diagnóstico
- Pronósticos mediante
predict
- Ejercicio:
- Proponer un modelo para predecir el «consumo» a partir del resto de
variables de
mtcars
. - Aplicar el modelo para un caso concreto.
- Proponer un modelo para predecir el «consumo» a partir del resto de
variables de
1.3 Lenguaje
En cada sección compararemos con Python:
1.3.1 ayuda
1.3.1.1 R
Para encontrar ayuda sobre un comando de R, por ejemplo rep
, puedes usar
?rep
Para algunos comandos con nombres especiales, hay que usar comillas; por ejemplo,
?"[" ?"if"
Si sólo conocemos parte del nombre del comando (p.ej. norm
), usamos
apropos("norm")
Si queremos encontrar información relacionada con un concepto, podemos usar:
??variance help.search("variance")
1.3.1.2 Python
help("variance") help("modules variance")
1.3.2 tipos de datos del lenguaje
1.3.2.1 simples
- especiales
- lógicos (booleanos)
- R
TRUE
yFALSE
- operadores «lanzados» (funcionan vectorialmente): «&» «|» «!» (y, o, no)
TRUE & FALSE; TRUE | !FALSE c(TRUE,FALSE) & c(FALSE,TRUE) FALSE & sqrt(-1) # produce aviso porque se evalúan ambos operandos TRUE & sqrt(-1) # ídem
- operadores «cortocircuito» (sólo escalares): «&&», «||»
FALSE && sqrt(-1) # no produce aviso TRUE || sqrt(-1) # tampoco
- Python
True
yFalse
- operadores «lanzados» (no funcionan vectorialmente): «&» «|» (y, o, no)
import math as m False & m.sqrt(-1) # da error
- operadores «cortocircuito»: «and» «or»
False and m.sqrt(-1) # sin error
- se pueden usar «&» «|» «~» (y, o, no) a la manera vectorial mediante
pandas
- R
- numéricos
- caracteres
- R
- "cadena de texto"
- 'cadena de texto'
- las dos formas anteriores son equivalentes; si se quiere incluir una comilla o un apóstrofo en la cadena,
se debe usar el delimitador apropiado (el otro) o «escapar» el carácter mediante una retrobarra «\»:
'me dijo "gracias, tío"' "me dijo \"gracias, tío\"" "ye'l mio güelu" 'ye\'l mio güelu'
- para extraer parte de una cadena se usa «substr» ó «substring»
> substr ("cadena", 2, 4) [1] "ade" > substring ("cadena", 2, 4) [1] "ade" > substring ("cadena", 2) [1] "adena"
- para tratar caracteres como números, puede hacer falta retocar la cadena:
as.numeric ("2.71") as.numeric (gsub (",", ".", "3,14"))
- ojo, porque el primer argumento de 'gsub' es una expresión regular;
por ejemplo, esto no funciona bien:
gsub (".", ",", "3.14")
hay que refinar la instrucción de alguna de estas maneras:
gsub ("\\.", ",", "3.14") # se utiliza «\» para «escapar» el punto en la expresión regular; ## a su vez, la retrobarra está escapada «\\» porque también es un carácter especial en R; gsub (".", ",", "3.14", fixed=TRUE) # interpreta la cadena como tal, no como expresión regular
- Python
- "cadena de texto"
- 'cadena de texto'
- las dos formas anteriores son equivalentes; si se quiere incluir una comilla o un apóstrofo en la cadena,
se debe usar el delimitador apropiado (el otro) o «escapar» el carácter mediante una retrobarra «\»:
- 'me dijo "gracias, tío"'
- "me dijo \"gracias, tío\""
- "ye'l mio güelu"
- 'ye\'l mio güelu'
- para extraer parte de una cadena se usan lonchas
>>> "cadena"[2:5] 'den' >>> "cadena"[2:] 'dena' >>> "cadena"[:2] 'ca'
- para tratar caracteres como números, puede hacer falta retocar la cadena:
float ("2.71") import re; float (re.sub (",", ".", "3,14"))
- ojo con los caracteres especiales:
re.sub (".",",","3.14") re.sub ("\.",",","3.14")
- tabla de elementos habituales de una expresión regular
- «
.
» corresponde a cualquier carácter (salvo fin de renglón) - «
^
» corresponde a inicio de renglón - «
$
» corresponde a fin de renglón - «
*
» cero o más presencias de lo precedente - «
+
» una o más presencias de lo precedente - «
|
» o bien lo de la izquierda o bien lo de la derecha - «
\
» cambia el significado del signo siguiente - «
\w
» corresponde a un signo alfanumérico - «
\d
» corresponde a un dígito decimal - «
cosa
» corresponde a la cadena «cosa»
- «
- R
1.3.2.2 compuestos
- vectores
- R
c(10,15,-3)
10:30
seq(-4,4,.1)
c("uno","dos","tres")
v <- 10:40 # asignación a variable; podría escribirse también así: v = 10:40
v[10]
v[-10]
v[2:4] # del segundo al cuarto elementos
v[c(1,2,4)]
v[-c(1,2,4)]
- selección mediante booleanos:
v <- seq (10, 100, 10)
v[8] <- NA
(para ver la diferencia al usarwhich
)v > 55
v[v>55]
v[which(v>55)]
l <- letters[1:10]
l[v>55]; l[which(v>55)]
- todos los escalares son vectores de longitud 1
- los vectores son homogéneos; los elementos promocionan al tipo más general:
c (0, 1, 2, TRUE, FALSE) # produce 0 1 2 1 0 c( 0, 1, TRUE, FALSE, "hola") # produce "0" "1" "TRUE" "FALSE" "hola"
- vectores como conjuntos (sean
v1 <- c(2, 4, 6), v2 <- 1:3
)- pertenencia
1 %in% v1; v2 %in% v1
- unión
union (v1, v2)
- intersección
intersect (v1, v2)
- diferencia
setdiff (v1, v2)
- pertenencia
- vectores con nombres
> v <- c(alfa=3,beta=88,gama=-5) > v alfa beta gama 3 88 -5 > names (v) [1] "alfa" "beta" "gama" > names (v) <- c("A","B","C") > v A B C 3 88 -5 > v["B"] B 88 > w <- c(primero=TRUE,segundo=FALSE) > w primero segundo TRUE FALSE > as.numeric(w) # pierde nombres [1] 1 0 > +w # forma más rápida de mantenerlos: https://stackoverflow.com/questions/37951199 primero segundo 1 0
- Python
El tipo básico más similar sería la lista, que es heterogénea:
[10, 15, -3, "hola"]
Pueden crearse vectores homogéneos como en R recurriendo al módulo
numpy
:from numpy import array
a = array ([10, 15, -3]) # de enteros
a = array ([10, 15, -3.0]) # de reales
- =3 * a # permiten operaciones elemento a elemento
Los rangos deben convertirse explícitamente:
list(range(10,31)) # desde 10 hasta 30
from numpy import arange; list(arange(-4.0,4.0,.1)) # hasta 3,9
["uno", "dos", "tres"]
v = range(10,40) # del 10 al 39
v[0] # el primer elemento
v[29] # el último
v[-1] # el último elemento
v[1:4] # del segundo al cuarto elementos
[v[i] for i in 0,1,3]
[v[i] for i in range(0,30) if not(i in [0,1,3])]
- selección mediante booleanos:
v = arange (10.0, 101, 10)
(nan
no es entero, sino real)from numpy import nan; v[8] = nan
v > 55
(elnan
produceFalse
)v[v>55]
- los escalares no son listas de longitud 1:
3+4; [3]+[4]
(comparar con arrayes:array([3])+array([4])
- la asignación de listas o arrayes en Python crea referencias, punteros; no como en R, que crea copias:
R> x = c(5,6); y = x; y[1] = 10; x # produce: 5 6 python>>> x = [5,6]; y = x; y[0] = 10; x # produce: 10 6
Para los conjuntos se usan llaves en vez de corchetes:
w1 = set ([1, 2, 3])
w2 = {2, 4, 6}
- pertenencia
1 in w1
- unión
w1.union(w2)
- intersección
w1.intersection(w2)
- diferencia
w1.difference(w2)
Para usar etiquetas para los elementos, recurriremos a diccionarios de Python básico o a Series de Python-Pandas:
v = {"alfa": 3, "beta": 88, "gama": -5} v.keys() import pandas as pd, numpy as np s = pd.Series([1,3,5,np.nan,6,8]) s = pd.Series ([1,3,5,np.nan,6,8], index=["uno","dos","tres","cuatro","cinco","seis"]) s.keys() w = pd.Series (v)
- R
- matrices
- R
m <- matrix (1:9, 3)
- submatriz:
m[1:2,2:3]
- fila:
m[1,]
- columna:
m[,1]
- si se quiere mantener como matriz columna:
m[,1,drop=FALSE]
- asignación:
m[2,3] <- 11
- traspuesta:
t(m)
- inversa:
solve(m)
- determinante:
det(m)
- producto matricial:
m%*%m
- Python
import numpy as np
m = np.array ([[0,1,2], [3,4,5], [6,7,8]]) # a partir de lista de listas
m = np.reshape (range(9), [3,3]) # igual al anterior; notar: empieza en 0 y rellena por filas
- submatriz:
m[0:2,1:3]
- primera fila:
m[0]; m[0,:]
- primera columna:
m[:,0]
- asignación:
m[1,2] = 11
- traspuesta:
np.transpose(m)
from numpy.linalg import inv; inv(m)
from numpy.linalg import det; det(m)
np.dot (m, m)
- R
- listas
- R
- son como vectores pero, en cada celda, pueden contener cualquier objeto (incluso listas):
l <- list (a=23, b=v, c=m)
- sublistas:
l[2] l["b"] l[c(1,3)] l[c("a","c")]
- extraer un elemento (no es lo mismo que una sublista de tamaño 1):
l[[3]] # la matriz l[[3]][,1] # l[3][,1] no funcionaría l[["c"]] l$c l$c[,1]
- son como vectores pero, en cada celda, pueden contener cualquier objeto (incluso listas):
- python
Se llama lista a las colecciones heterogéneas creadas con corchetes:
a = [1, 2, "hola", ["otra", "lista"]] a[0] # el primer elemento a[0:1] # una sublista que contiene sólo al primer elemento
Para usar etiquetas hace falta un diccionario…
v = {'beta': 88, 'alfa': 3, 'gama': -5} l = {"a":23, "b":v, "c":[1,2,3]} l["b"] # extraer un elemento l["b"]["alfa"] {i:l[i] for i in ["a","c"]} # subdiccionario
…o una
Series
depandas
:import pandas as pd; L = pd.Series(l)
- subseries:
L[[1]]; L[["b"]] L[[0,2]]; L[["a","c"]]
- extraer un elemento:
L[1]; L["b"] L[1]["alfa"] L["b"]["alfa"]
- subseries:
- R
- dataframes
- R
- parecen matrices, con columnas heterogéneas (como las listas):
d <- data.frame (x = 1:5, y = c("uno","dos","tres","cuatro","cinco")) d[3,2] d[[1]] d$x d[["x"]] d[1:2,c("y","x")] ; d[1:2,2:1] d$y [d$x > 3] # filtrar una variable según los valores de otra d [d$x >3, ] # nuevo dataframe, subconjunto del dataframe original
- los dataframes son visibles desde
Rcmdr
- parecen matrices, con columnas heterogéneas (como las listas):
- Python
import pandas as pd d = pd.DataFrame ({"x" : list(range(1,6)), "y" : ["uno","dos","tres","cuatro","cinco"]}) d.y list (d.y) d.y[2] d["y"] d[["y","x"]] ; d[[1,0]] d.y [d.x > 3]; list (d.y [d.x > 3]) d [d.x > 3]
http://pandas.pydata.org/pandas-docs/stable/comparison_with_r.html
- R
- factores o categóricas
- R
- implementan variables cualitativas:
sexo <- c("M","M","H","H","H","M") sexo.f <- factor (sexo) levels (sexo.f)
factor
genera un factors = c ("M", "M", "M", "H", "M", "H", "H", "HH", "HM") f = factor (s)
- un factor se parece a un vector de caracteres, pero no es:
as.character (f) as.numeric (f) nchar(s) # funciona nchar(f) # no
factor
también elimina los niveles sobrantesf1 = f[nchar(as.character(f))==1] f1 = factor(f1)
- los
NA
en principio no aparecen como niveles:factor(c(1,1,3,NA)) factor(c(1,1,3,NA),exclude=NULL)
- para imponer un orden
factor (c("bien","mal","regular","bien")) factor (c("bien","mal","regular","bien"), levels=c("mal","regular","bien"))
- implementan variables cualitativas:
- Python
Quizá no tan básicos como en R.
- implementan variables cualitativas:
import pandas as pd sexo = pd.Series(["M","M","H","H","H","M"]) sexo_f = sexo.astype("category") list(sexo_f.values.categories)
- para eliminar los niveles sobrantes
sexo_f2 = sexo_f[0:2] sexo_f2 = pd.Series(list(sexo_f2)).astype("category")
- los
nan
no aparecen como niveles:import numpy as np pd.Series([1,1,3,np.nan]).astype("category")
- para imponer un orden
pd.Series (pd.Categorical (["bien", "mal", "regular", "bien"], categories = ["mal", "regular", "bien"]))
http://pandas.pydata.org/pandas-docs/stable/categorical.html
- implementan variables cualitativas:
- R
- fechas y horas
- R
- Trasformar cadena en fecha:
as.Date ("1978-1-31") # 31 de enero de 1978
- Acepta formatos arbitrarios con estas plantillas:
plantilla representa %d día del mes %m mes (número) %b mes (abreviado) %B mes (nombre completo) %y año (dos cifras) %Y año (cuatro cifras) as Date ("31/1/78", format="%d/%m/%y") as.Date ("Ene 31, 1978", format="%b %d, %Y")
- Si el ordenador no está en español, para lo anterior habría que ejecutar antes:
Sys.setlocale ("LC_TIME", "es_ES.UTF-8")
Asimismo, para leer fechas del sistema operativo (en idioma
POSIX
oC
) podría hacerse así:Sys.setlocale ("LC_TIME", "C") as.Date ("Jan 31, 1978", format="%b %d, %Y")
- Las fechas pueden restarse, o se les puede sumar o restar un entero.
as.Date ("1978-1-31") - as.Date ("1977-1-31") # podría aplicarse "as.numeric" as.Date ("1978-1-31") + 1
- Dada una fecha, el correspondiente día de la semana puede obtenerse con
weekdays
weekdays (as.Date ("1978-1-31"))
- Para pasar cadenas a horas, se usa
strptime
:strptime ("Oct 10 07:44:31", format = "%b %d %H:%M:%S")
Acepta plantillas
%H
,%M
y%S
para horas minutos y segundo. Para otras, véase la ayuda destrptime
.
- Trasformar cadena en fecha:
- Python
- Trasformar cadena en fecha:
import pandas as pd pd.Timestamp("2012-05-01") pd.Timestamp("1/1/1974") pd.Timestamp("31/1/78") pd.Timestamp("31/1/18") pd.Timestamp("2/1/18") # ojo
- Las fechas pueden restarse:
td = pd.Timestamp("2018-10-01") - pd.Timestamp("1976-02-09") td.total_seconds() / 86400 / 365.25
- Dada una fecha, el correspondiente día de la semana puede obtenerse:
fecha = pd.Timestamp("2018-10-01") fecha.weekday() fecha.weekday_name
- También para horas acepta formatos variados:
pd.Timestamp("2012-05-01T12:30:15.3333333") pd.Timestamp("1-5-2012 12:30:15.3333333") # ojo
- Para pasar cadenas arbitrarias a horas, se puede usar
strptime
:import time; time.strptime("Oct 10 07:44:31", "%b %d %H:%M:%S")
Acepta plantillas
%H
,%M
y%S
para horas minutos y segundo.
- Trasformar cadena en fecha:
- R
1.3.3 control
1.3.3.1 R
- condicionales
Generemos un vector de temperaturas:
t <- runif (15, 10, 40)
Para combinar comparaciones vectorialmente, usamos
ifelse
y un operador «lanzado» («&» = «y»; «|» = «ó»):ifelse (t>20 & t<30, "agradable", "desagradable")
Para combinar comparaciones de forma que esperamos un único booleano, usamos operadores «cortocircuito» («&&» = «y»; «||» = «ó»):
n=10; if (is.numeric(n) && length(n)==1 && n>0) sqrt(n) else "no puedo"
- bloques de instrucciones mediante llaves «{}»; se usan en contextos donde tiene que ir más de una instrucción:
if (n > 5) {print("demasiado grande"); n<-5} else {print("demasiado pequeño"); n<-n+1}
El valor devuelto por un bloque es el valor devuelto por su última instrucción.
- bucles
for (i in 1:10) cat ("El cuadrado de", i, "es", i^2, "\n")
Detrás de «in» puede ir cualquier vector o lista; por ejemplo
for (i in letters) {cat (i); cat (toupper (i)); cat ("-")}; cat ("\n") for (i in iris) print (summary (i))
- bucles con acumulador
Se define una variable (acumulador) antes del bucle para que recoja los resultados:
suma <- 0; for (i in 1:10) suma <- suma+i; suma producto <- 1; for (i in 1:10) producto <- producto*i; producto bector <- c(); for (i in 1:10) bector <- c(bector,i^2); bector lista <- list(); for (i in 1:10) lista <- c(lista,list(1:i)); lista
1.3.3.2 Python
- condicionales
Para combinar comparaciones de forma que esperamos un único booleano, usamos operadores «cortocircuito» («and» = «y»; «or» = «ó»):
import math n=10 if ((isinstance(n,int) or isinstance(n,float)) and n>0): math.sqrt(n) else: "no puedo"
Generemos un vector de temperaturas:
import scipy.stats as st t = st.uniform.rvs (10, 40, 15)
Para combinar comparaciones vectorialmente, usamos
if
así:["agradable" if ti>20 and ti<30 else "desagradable" for ti in t]
- nótense los bloques de instrucciones tras dos puntos y con sangría:
if n > 5: print("demasiado grande") n = 5 else: print("demasiado pequeño") n++
- bucles
for i in range(10): print ("El cuadrado de", i, "es", i**2) mtcars = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/mtcars.csv") for v in mtcars: mtcars[v].describe()
- bucles con acumulador
Se define una variable (acumulador) antes del bucle para que recoja los resultados:
- numéricos
suma = 0 for i in range(1,11): suma += i
producto = 1 for i in range(1,11): producto *= i
- recolección
vector = [] for i in range(1,11): vector.append (i**2)
lista = [] for i in range(10): lista.append (list (range (i)))
1.3.4 funciones
1.3.4.1 R
- con nombre
f <- function(x) x^2 f(15)
- anónimas (útiles para definiciones al vuelo, como se ve en la sección siguiente)
(function(x) x^2) (15)
- pueden tener varios argumentos
var.ponderada <- function (x, pesos) # varianza ponderada { mp <- weighted.mean (x, pesos) # media ponderada weighted.mean ((x - mp) ^ 2, pesos) }
- cada argumento puede tener un valor por omisión
var.ponderada <- function (x, pesos = rep(1,length(x))) { mp <- weighted.mean (x, pesos) weighted.mean ((x - mp) ^ 2, pesos) }
- pueden pasar sus argumentos a otras funciones mediante «…»
var.ponderada <- function (x, pesos, ...) { mp <- weighted.mean (x, pesos, ...) weighted.mean ((x - mp) ^ 2, pesos, ...) }
Por ejemplo:
muestra <- c (1, 20, NA, 5); pesos <- c (1,2,3,4) weighted.mean (muestra, pesos); weighted.mean (muestra, pesos, na.rm=TRUE) var.ponderada (muestra, pesos) # produce NA var.ponderada (muestra, pesos, na.rm=TRUE) # pasa «na.rm=TRUE» a weighted.mean
1.3.4.2 Python
- con nombre
def f (x): return x**2 f(15)
- anónimas (útiles para definiciones al vuelo, como se ve en la sección siguiente)
(lambda x: x**2) (15)
sólo pueden contener una expresión;
- pueden tener varios argumentos
def media_ponderada (x, pesos): suma = 0 for i in range (len (x)): suma += x[i] * pesos[i] return suma / sum(pesos)
- cada argumento puede tener un valor por omisión
def media_ponderada (x, pesos = None): suma = 0 for i in range (len (x)): suma += x[i] * (pesos[i] if pesos else 1) return suma / (sum(pesos) if pesos else len(x))
- pueden pasar sus argumentos a otras funciones mediante un argumento con «*»
def var_ponderada (x, *otros): mp = media_ponderada (x, *otros) cuadrados = [(xi-mp)**2 for xi in x] return media_ponderada (cuadrados, *otros)
Por ejemplo:
muestra = [1, 20, 100, 5]; pesos = [1,2,3,4] media_ponderada (muestra) media_ponderada (muestra, pesos) var_ponderada (muestra) # pasa *otros como vacío var_ponderada (muestra, pesos) # pasa *otros como «pesos»
1.3.5 bucles sobre estructuras
1.3.5.1 R
- sobre secuencias (vectores o listas)
sapply
(cons
de simple) se usa para generar un vector (o una matriz, si el resultado de la función aplicada es vectorial)sapply (1:10, sqrt) # aplicar una función con nombre sapply (1:10, function(x) x**2) # aplicar una función anónima sapply (1:10, function(x) c(x^2,x^3)) # el resultado es una matriz
lapply
(conl
de lista) devuelve una listalapply (1:10, function(x) list (x, list(letters[i],month.name[i])))
apply
se usa para aplicar una función a filas o columnas de una matriz o dataframem <- matrix (1:12, 3) apply (m, 1, sum) # aplicar por filas apply (m, 2, sum) # aplicar por columnas
- para aplicar por grupos:
prod <- 1:20; sexo <- rep(c("M","H"),each=10) tapply (prod, sexo, mean) # por niveles de "sexo" by (prod, sexo, mean) # ídem
- la más general (mapeo)
mapply (rep, 1:4, 4:1) # aplica funciones con varios argumentos
- un comando muy habitual en simulaciones:
replicate (10000, {m <- rnorm(5); mean(m)})
Funciona parecido a
sapply (1:10000, function (i) {m <- rnorm(5); mean(m)})
donde la variable
i
es irrisoria; su valor no se usa.
1.3.5.2 Python
- trasformación por descripción (mapeo)
from math import sqrt [sqrt(i) for i in range(10)] list (map (sqrt, range(10))) # lo mismo list (map (lambda x: x**2, range(10))) # con función anónima
otra versión de la media ponderada anteriormente definida:
def media_ponderada (x, pesos): return sum (map (lambda xi,pi: xi*pi, x, pesos)) / sum(pesos)
otra versión con argumento opcional:
def media_ponderada (x, pesos = None): return sum (map (lambda xi,pi: xi*pi, x, [1]*len(x) if pesos is None else pesos)) / (sum(pesos) if pesos else len(x))
- aplicar una función a filas o columnas de un dataframe
from sklearn import datasets iris = datasets.load_iris() # datos de ejemplo import pandas as pd I = pd.DataFrame(iris.data, columns=iris.feature_names) I.apply(sum) # aplicar «sum» por columnas; equivale a I.sum() I.apply(sum,axis=0) # ídem I.apply(sum,axis=1) # aplicar «sum» por filas; equivale a I.sum(axis=1)
- para aplicar por grupos:
I["especie"] = pd.Series(pd.Categorical.from_codes(codes=iris.target,categories=iris.target_names)) I.groupby("especie").apply(lambda x: x.iloc[:,0:4].median()) # 0:4 para evitar "especie"
1.4 Repaso de lo visto (en lenguaje de programación)
1.4.1 Obtener datos
1.4.1.1 R
- De ejemplo (incluidos en la distribución de R)
- Listar los disponibles:
data ()
- En una sesión de R básico (sin Rcmdr) están disponibles varios dataframes, como «mtcars».
Para otros hay que cargar la biblioteca correspondiente; por ejemplo:
library (car) # para datos «Chile» summary (Chile)
- En una sesión de Rcmdr se ocultan los dataframes de ejemplo para que no molesten en la lista de datos disponibles.
Para trabajar con tales datos hay que cargar la biblioteca «datasets»:
library (datasets)
- Listar los disponibles:
- En formato nativo de R
- Habitualmente, el fichero con datos nativos tiene extensión
.rda
ó.RData
. - Pueden contener
- un solo conjunto de datos (cuyo nombre puede coincidir o no con el nombre del fichero)
- múltiples conjuntos de datos, además de variables, funciones, etc. (entorno de trabajo de R)
- Se carga con
load
:getwd () # directorio de trabajo load ("mi-fichero.rda") # en el directorio de trabajo load ("~/iot/datos/mi-fichero.rda") # en otro directorio, necesita ruta setwd ("~/iot/datos") # cambiar directorio de trabajo # puede usarse una URL como ruta: load (url ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/mtcoches.rda")) ls () # aparece mtcoches head (mtcoches)
- Habitualmente, el fichero con datos nativos tiene extensión
- En formatos ajenos
(Lo mismo en Python.)
- De especial interés es la importación de datos de texto (CSV)
- codificación: utf-8 (unicode) o latin-1 (iso-8859-1, -15)
datos <- read.table (........., encoding = "latin1") # para ISO-8859-1, originados en Windows habitualmente datos <- read.table (........., encoding = "UTF-8") # codificación más habitual para datos Unicode
- campos
- delimitados por un carácter solo (vacas.csv)
vacas1 <- read.csv2 (url ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/vacas.csv"))
- delimitados por varios espacios en blanco
(sin espacios dentro de campo: vacas.txt; con espacios: vacas.blancos1)
vacas2 <- read.table (url ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/vacas.txt"), header=TRUE) vacas3 <- read.table (url ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/vacas.blancos1"), head=TRUE)
- columnas de anchura fija (vacas.blancos2)
vacas4 <- read.fwf (url ("http://156.35.96.172/~carleos/master/iot/ces/datos/vacas.blancos2"), rep(30,11), TRUE)
- codificación: utf-8 (unicode) o latin-1 (iso-8859-1, -15)
- De especial interés es la importación de datos de texto (CSV)
1.4.1.2 Python
- De ejemplo (incluidon en python-sklearn)
from sklearn import datasets iris = datasets.load_iris()
- En formato nativo de Python (pickle)
Cualquier objeto de Python, incluyendo los dataframes de Pandas, puede serializarse (guardarse en un fichero):
import pandas as pd d = pd.DataFrame({'a':[1,2,3,4,5],'b':["uno","uno","onu","onu","uno"]}) d.to_pickle("/tmp/fichero.dat")
Para leer un dataframe de un fichero pickle:
datos = pd.read_pickle ("/tmp/fichero.dat")
- En formatos ajenos
(Lo mismo en R.)
- Importar Pandas
import pandas as pd
- Para datos de texto (CSV) hay
read_csv()
(comas) yread_table()
(tabuladores)- codificación: utf-8 (unicode) o latin-1 (iso-8859-1, -15)
datos = pd.read_table (........., encoding = "latin1") # para ISO-8859-1, originados en Windows habitualmente datos = pd.read_table (........., encoding = "UTF-8") # codificación más habitual para datos Unicode
- ¿campos delimitados o de anchura fija?
- delimitados por un carácter solo (vacas.csv)
vacas1 = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/vacas.csv", sep=";", encoding="utf-8")
- delimitados por varios espacios en blanco
(sin espacios dentro de campo: vacas.txt)
vacas2 = pd.read_table ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/vacas.txt", sep='\s+', engine='python')
- columnas de ancho fijo (vacas.blancos3)
vacas5 = pd.read_fwf ("http://156.35.96.172/~carleos/master/iot/ces/datos/vacas.blancos3", widths = [30] * 11)
- delimitados por un carácter solo (vacas.csv)
- codificación: utf-8 (unicode) o latin-1 (iso-8859-1, -15)
- Para datos con fechas, opción
parse_dates
:vacas5 = pd.read_fwf ("http://156.35.96.172/~carleos/master/iot/ces/datos/vacas.blancos3", widths = [30] * 11, parse_dates=[1,2]) # fechas en columnas segunda y tercera
- Importar Pandas
1.4.2 Guardar datos
1.4.2.1 R
- Guardar todo el entorno de trabajo (funciones, dataframes…)
save.image () # lo guarda en ./.RData (el fichero cargado al arrancar R) save.image (file = "~/trabajo/mi-sesión.rda") # en fichero arbitrario
- Guardar uno o varios objetos en formato nativo de R
save (mi.dataframe, mi.función, file = "~/trabajo/mis-objetos.rda")
- Guardar un dataframe como una tabla de texto (CSV)
write.table (mtcars, "/tmp/mtcars1.csv") # sep=" " dec="." sin campo de rownames en cabecera write.csv (mtcars, "/tmp/mtcars2.csv") # sep="," dec="." write.csv2 (mtcars, "/tmp/mtcars3.csv") # sep=";" dec=","
1.4.2.2 Python
- Guardar entorno de trabajo
import dill dill.dump_session ("/tmp/miTrabajo.pkl") # recuperar con dill.load_session
- Guardar un objeto en formato nativo de Python
misDatos.to_pickle ("/tmp/misDatos.pkl")
- Guardar un dataframe como una tabla de texto (CSV)
misDatos.to_csv ("/tmp/misDatos.csv")
1.4.3 Descriptivos
1.4.3.1 R
D <- mtcars # dataframe de ejemplo D$am <- factor (mtcars$am) # una cualitativa; también: D$am <- factor(D$am, labels=c("auto","manual")) summary (D) # resumen del dataframe T <- table (D$cyl) # frecuencias absolutas prop.table (T) # frecuencias relativas summary (D$hp) # media y cinco cuartiles mean (D$hp) # media var (D$hp) # varianza sd (D$hp) # desviación típica median (D$hp) # mediana quantile (D$hp, 0.95) # percentil 95 quantile (D$hp, 0:4/4) # cinco cuartiles IRQ (D$hp) # recorrido intercuartílico
En muchas funciones se puede incluir la opción na.rm=TRUE
para omitir los ausentes:
mean (c (1:10, NA)) mean (c (1:10, NA), na.rm=TRUE)
Gráficas:
barplot (table (D$cyl)) # diagrama de barras pie (table (D$am)) # diagramo de sectores hist (D$hp) # histograma boxplot (hp ~ am, D) # diagrama de cajas plot (mpg ~ hp, D) # diagrama de dispersión (nube de puntos) pdf ("fichero.pdf") # guarda gráficas subsiguientes en 1 fichero PDF (vectorial) for (i in 1:ncol(mtcars)) { if (is.numeric (mtcars[[i]])) hist (mtcars[[i]]) else barplot (table (mtcars[[i]])) } dev.off () # cierra el PDF png ("fichero%d.png") # guarda gráficas subsiguientes en ficheros PNG (pixelados) for (i in 1:3) boxplot (mtcars[[i]] ~ mtcars$am) dev.off () # cierra el PNG
Ejercicio:
- Escribir un programa en R que realice gráficas adecuadas para las variables del conjunto de datos «Chile» del paquete «car».
data (Chile, package="car") Chile$education <- factor (Chile$education, levels=c("P","S","PS"))
1.4.3.2 Python
Con los datos clásicos de flores iris:
import pandas as pd i = pd.read_csv ("datos/iris.csv") i.describe() # numérico i["Species"].describe() # moda iSn = i['Species'].value_counts() # recuentos iSn / iSn.sum() # frecuencias relativas i["Petal.Length"].mean() # media i["Petal.Length"].var() # varianza i["Petal.Length"].std() # desviación típica i["Petal.Length"].median() # mediana i["Petal.Length"].quantile(0.5) # ídem i["Petal.Length"].quantile([.05,.95]) # percentiles 5 y 95 import numpy as np # para «nan» pd.Series([1,2,np.nan,4]).mean() # excluye los ausentes
Gráficas:
import matplotlib.pyplot as plt i["Petal.Length"].plot(kind="hist") # histograma plt.show() # mostrar en pantalla i["Petal.Length"].value_counts().plot(kind="bar") # diagrama de barras plt.savefig("barras.png") # guardar en fichero i["Petal.Length"].value_counts().plot(kind="pie") # diagrama de sectores i["Petal.Length"].plot(kind="box") # diagrama de caja i.boxplot("Petal.Length","Species") # cajas por grupo
1.4.4 Modificar datos
1.4.4.1 R
- Crear nueva variable de un dataframe:
mtcars$consumo <- (3.8 / mtcars$mpg * 1.6) * 100
- Recodificar:
mtcars$am <- factor (mtcars$am, labels=c("auto","manual")) mtcars$consumo3 <- cut (mtcars$consumo, c(-Inf, 10, 20, 30, Inf), c("muy poco", "poco", "mucho", "demasiado"))
- Reordenar niveles de factor:
data (Chile, package="car") Chile$educación <- factor (Chile$education, levels = c("P","S","PS")) # P=primaria, S=secundaria, PS=postsecundaria
- Filtrar
edades.mujeres <- Chile$age [Chile$sex == "F"] mtcars4v <- mtcars [mtcars$cyl==4 & mtcars$vs==0, ] ?== # ayuda sobre < > == != ?& # ayuda sobre ! & |
1.4.4.2 Python
import pandas as pd Chile = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/Chile.csv")
- Crear nueva variable en un dataframe:
Chile.euro = 1.2 * Chile.income
- Recodificar:
Chile.sexo = Chile.sex.astype("category") Chile.sexo.values.categories = ["mujer", "varón"] Chile.clase = pd.cut (Chile.income, [-np.inf,30000,100000,np.inf], labels=["baja","media","alta"])
- Reordenar niveles de categórica:
Chile["educación"] = Chile["education"].astype("category",categories=["P","S","PS"])
- Filtrar:
edades_mujeres = Chile.age[Chile.sex=="F"] varones_jovenes = Chile[(Chile.sex=="M") & (Chile.age<35)]
Más en la documentación de Pandas.
1.4.5 Distribuciones de probabilidad
1.4.5.1 R
- letra inicial
r
para generar aleatoriosp
para la función de distribución \(F_X\,(t) = \Pr\,[X\leq t]\)d
para la función de densidad de variables continuas o la función de probabilidad (o de cuantía, o de masa) de variables discretas \(f_X\,(t) = \Pr\,[X=t]\)q
para la función cuantil
- abreviatura del nombre de la familia de la distribución
unif
uniformenorm
gausianaexp
exponencialbinom
binomialpois
puasónt
de Estiúdent (Student)chisq
\(\chi^2\) (ji-cuadrado)
runif (10, 0, 1) # genera 10 aleatorios con distribución uniforme entre 0 y 1 pnorm (150, 170, 15) # probabilidad de que una gausiana N(170;15) sea menor que 150 plot (x <- seq(0,5,.1), dexp(x,1)) # curva de densidad de una exponencial con media 1 qpois (0.5, 1.7) # mediana de una distribución de Puasón con media 1,7
1.4.5.2 Python
- métodos
rvs
para generar aleatorioscdf
función de distribución (cumulative density function)pdf
función de densidad (probability density function)pmf
función masa de probabilidad (probability mass function)mean
,var
,std
,median
- media, varianza, desviación típica, medianappf
función cuantil (percent point function)
- distribuciones
uniform
uniformenorm
gausianaexpon
exponencialbinom
binomialpois
puasónt
de Estiúdent (Student)chi2
ji-cuadrado (\(\chi^2\))
import scipy.stats as st st.uniform.rvs (2, 0.1, 30) # 30 valores uniformes entre 2 y 2+0,1 st.norm.cdf (200, 170, 10) # función de distribución en 200 de una N(170;10) import matplotlib.pyplot as plt # función de densidad (de la docstring de expon) fig, ax = plt.subplots(1, 1) x = np.linspace(expon.ppf(0.01), expon.ppf(0.99), 100) ax.plot(x, expon.pdf(x), 'r-', lw=5, alpha=0.6, label='exponencial') ## también se pueden fijar previamente los parámetros: v = st.binom (10, .3) # binomial n=10, p=0,3 v.mean(), v.var(), v.std() # media, varianza, desviación típica v = st.poisson (100) # puasón con media 100 v.ppf([.05,.95]) # percentiles 5 y 95
1.4.6 Contrastes de hipótesis sobre medias, proporciones…
1.4.6.1 R
?cars # velocidad y distancia de frenada library (car) # para datos Chile ## contraste de gausianidad shapiro.test (cars$speed) # comprobar mediante stem o hist shapiro.test (Chile$statusquo) shapiro.test (Chile$age) ## información del objeto "contraste" shapiro.test (cars$speed) -> contraste names (contraste) # "statistic" "p.value" "method" "data.name" contraste$p.value # nivel crítico o p-valor ## simulación n <- 100 # tamaño muestral m <- rnorm(n); stem(m); shapiro.test(m)$p.value # relación entre forma y p-valor mean (replicate (10000, shapiro.test(rnorm(n))$p.value) < 0.05) # proporción de rechazos ## contraste sobre la media t.test (cars$speed, mu=15) # bilateral t.test (cars$speed, mu=15, alternative="less") # H0: mu=15; H1: mu<15 t.test (cars$speed, mu=15, alternative="greater") # H0: mu=15; H1: mu>15 ## contraste sobre proporción summary (Chile$sex) ?prop.test prop.test (sum(Chile$sex=="F"), nrow(Chile), 0.5) # H0: p = 1:2; H1: p =/= 1:2 ## contraste sobre la mediana wilcox.test (cars$speed, mu=15) # bilateral wilcox.test (cars$speed, mu=15, alternative="less") # H0: mu=15; H1: mu<15 wilcox.test (cars$speed, mu=15, alternative="greater") # H0: mu=15; H1: mu>15 M <- rexp (25) # exponencial con media=1 Me <- qexp (.5) # mediana teórica = 0,693.147.2 wilcox.test (M, mu=Me) # poco recomendable porque exige simetría mean (replicate (100000, {M <- rexp(25); wilcox.test(M,mu=Me)$p.value<.05})) # 11% en vez de 5% prop.test (sum(M>Me), 25, .5) # prueba de signos: poco potente, pero cumple mean (replicate (100000, {M <- rexp(25); prop.test(sum(M>Me),25,.5)$p.value<.05})) # <5% mean (replicate (100000, {M <- rexp(25); t.test(M,mu=1)$p.value<.05})) # 7,5% (pero con media, no mediana) ## contraste sobre dos proporciones ## ¿es significativamente mayor la proporción de mujeres que votan Y? ## p = proporción que votan Y; H0: pF=pM; H1: pF>pM mujeres <- Chile [Chile$sex=="F" & !is.na(Chile$vote),] varones <- Chile [Chile$sex=="M" & !is.na(Chile$vote),] prop.test (c (sum (mujeres$vote=="Y"), sum (varones$vote=="Y")), c (nrow (mujeres), nrow (varones)), alternative = "greater") ## contraste de igualdad de varianzas (auxiliar para el de igualdad de medias) ? iris # comparar varianza de Petal.Length en «versicolor» y «virginica» with (iris, plot (Petal.Length, Petal.Width, col=Species)) boxplot (Petal.Length ~ Species, iris) with (iris, by (Petal.Length, Petal.Species, shapiro.test)) PLversicolor <- iris [iris$Species=="versicolor", "Petal.Length"] PLvirginica <- iris [iris$Species=="virginica", "Petal.Length"] var.test (PLversicolor, PLvirginica) # contraste de igualdad de varianzas var.test (Petal.Length ~ Species, iris, subset = Species %in% c("versicolor","virginica")) # lo mismo bartlett.test (Petal.Length ~ Species, iris, subset = Species %in% c("versicolor","virginica")) # otro similar ## contraste de igualdad de medias (muestras independientes) t.test (Petal.Length ~ Species, iris, subset = Species %in% c("versicolor","virginica")) # estimando dos varianzas distintas t.test (Petal.Length ~ Species, iris, subset = Species %in% c("versicolor","virginica"), var.equal = TRUE) # casi no cambia el p-valor ## contraste de igualdad de medias (muestras pareadas) ? ChickWeight # ¿Hay incremento significativo de peso a partir del día 20? boxplot (weight ~ Time, ChickWeight) cw <- ChickWeight [ChickWeight $ Time %in% c (20, 21), ] t.test (weight ~ Time, cw, alternative="less") # como si fueran independientes cw20 <- cw [cw$Time == 20,]; rownames(cw20) <- cw20$Chick cw21 <- cw [cw$Time == 21,]; rownames(cw21) <- cw21$Chick ambos <- intersect (rownames(cw20), rownames(cw21)) incremento <- cw21[ambos,"weight"] - cw20[ambos,"weight"] shapiro.test (incremento) # innecesario por el tamaño de muestra (45) t.test (cw20[ambos,"weight"], cw21[ambos,"weight"], paired=TRUE, alternative="less") t.test (incremento, mu=0, alternative="greater") # equivale al anterior ## contraste sobre la mediana de la diferencia (muestras independientes) ## comparar Petal.Width en «setosa» y «virginica» dentro del conjunto de datos «iris» ?iris shapiro.test (iris [iris$Species == "setosa", "Petal.Width"]) shapiro.test (iris [iris$Species == "versicolor","Petal.Width"]) t.test (Petal.Width ~ Species, iris, subset = Species %in% c("setosa","versicolor")) # suficiente tamaño muestral wilcox.test (Petal.Width ~ Species, iris, subset = Species %in% c("setosa","versicolor")) # resultado parecido ## contraste sobre la mediana de la diferencia (muestras pareadas) ?sleep # ¿hay diferencias significativas en sueño extra según somnífero? boxplot (extra ~ group, sleep) extra1 <- sleep$extra [sleep$group == '1'] extra2 <- sleep$extra [sleep$group == '2'] dif <- extra1 - extra2 shapiro.test (dif) wilcox.test (extra1, extra2, paired=TRUE) # asegurarse de que el orden se corresponde en ambos vectores wilcox.test (sleep ~ group, sleep, paired=TRUE) # otra forma de expresarlo wilcox.test (dif) # es equivalente a un contraste de Wilcoxon de 1 muestra t.test (extra1, extra2, paired=TRUE) # no muy distinto
- Otro ejemplo:
- Comparar las dos secuencias «x» y «y» de seudoaleatorios de cierto generador:
?randu # comparar «x» con «y» dif <- randu$x - randu$y shapiro.test (dif) # irrelevante por el tamaño muestral, en principio... wilcox.test (randu$x, randu$y, paired=TRUE) t.test (randu$x, randu$y, paired=TRUE) # ...pero allende el umbral del 5% wilcox.test (runif(400), runif(400), paired=TRUE) # comparar con seudoaleatorios decentes
- Comparar las dos secuencias «x» y «y» de seudoaleatorios de cierto generador:
1.4.6.2 Python
import numpy as np # para nan, isnan import pandas as pd # para dataframes from scipy import stats # para contrastes import matplotlib.pyplot as plt # para histograma cars = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/cars.csv") Chile = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/Chile.csv") ## contraste de gausianidad stats.shapiro (cars.speed) stats.shapiro (cars.speed) [1] # p-valor stats.shapiro (Chile.age [~ np.isnan (Chile.age)]) # hay NA ## simulación n = 100 # tamaño muestral ## relación entre forma y p-valor m = stats.norm.rvs(0,1,n); m.plot(kind="hist"); plt.show(); stats.shapiro(m)[1] (pd.Series([stats.shapiro(stats.norm.rvs(0,1,n))[1] for i in range(10)]) < 0.05) . mean() # proporción de rechazos ## contraste sobre la media pvalor2 = stats.ttest_1samp (cars.speed, 15) . pvalue # bilateral ## ya que mediamuestral = 15,4 > 15 entonces pvalor1 = pvalor2 / 2 # unilateral H0: mu=15; H1: mu>15 1 - pvalor1 # unilateral H0: mu=15; H1: mu<15 ## contraste sobre proporción H0: p = 1:2; H1: p =/= 1:2 Chile.sex.value_counts() n = Chile.sex.count() p = Chile.sex.value_counts(True)['F'] from math import sqrt 2 * (1 - stats.norm.cdf (abs ((p - 0.5) / sqrt (0.25/n)))) # p-valor bilateral stats.chisquare ([1379,1321]) . pvalue # otra posibilidad: usar contraste ji-2 equivalente ## contraste sobre la mediana M = stats.expon.rvs (0, 1, 25) # exponencial con media=1 Me = stats.expon.ppf (.5) # mediana teórica = 0,693.147.2 stats.wilcoxon (M - Me) # poco recomendable porque exige simetría nM = sum (M-Me > 0); stats.chisquare ([nM, len(M)-nM]) # prueba de signos: poco potente ## contraste sobre dos proporciones ## ¿es significativamente mayor la proporción de mujeres que votan Y? ## p = proporción que votan Y; H0: pF=pM; H1: pF>pM tabla = Chile.groupby(['sex','vote']).size().unstack() # tabla de contingencia stats.chi2_contingency(tabla)[1] # P-valor de contraste ji-2 de homogeneidad mujeres = Chile [(Chile.sex=="F") & ~pd.isnull(Chile.vote)] varones = Chile [(Chile.sex=="M") & ~pd.isnull(Chile.vote)] pvalor2 = stats.chi2_contingency([[sum(varones.vote=="Y"),sum(varones.vote!="Y")], [sum(mujeres.vote=="Y"),sum(mujeres.vote!="Y")]]) [1] pF = sum(mujeres.vote=="Y")/len(mujeres) # 37% pM = sum(varones.vote=="Y")/len(varones) # 32% pvalor1 = pvalor2 / 2 # porque pF > pM ## contraste de igualdad de varianzas (auxiliar para el de igualdad de medias) ## ¿hay diferencias significativas en sueño extra entre los dos grupos? sleep = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/sleep.csv") stats.shapiro (sleep.extra [sleep.group == 1]) stats.shapiro (sleep.extra [sleep.group == 2]) stats.bartlett (sleep.extra [sleep.group == 1], sleep.extra [sleep.group == 2]) ## contraste de igualdad de medias (muestras independientes) stats.ttest_ind (sleep.extra [sleep.group == 1], sleep.extra [sleep.group == 2]) # suponiendo varianzas iguales stats.ttest_ind (sleep.extra [sleep.group == 1], sleep.extra [sleep.group == 2], equal_var=False) ## contraste de igualdad de medias (muestras pareadas) ## ¿hay incremento significativo de peso a partir del día 20? CW = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/ChickWeight.csv") CW.boxplot ("weight", "Time") plt.show() CW.weight[CW.Time==20].mean() # menor CW.weight[CW.Time==21].mean() # mayor stats.ttest_ind (CW.weight[CW.Time==20], CW.weight[CW.Time==21]).pvalue/2 # como si fueran independientes cw = CW[CW.Time.isin([20,21])] cw20 = cw [cw.Time == 20]; cw20.index = cw20.Chick cw21 = cw [cw.Time == 21]; cw21.index = cw21.Chick ambos = cw20.index.intersection(cw21.index) stats.shapiro (cw20.loc[ambos,"weight"] - cw21.loc[ambos,"weight"]) # innecesario por el tamaño de muestra (45) stats.ttest_rel (cw20.loc[ambos,"weight"], cw21.loc[ambos,"weight"]).pvalue / 2 ## contraste sobre la mediana de la diferencia (muestras independientes) ## comparar Petal.Width en «setosa» y «virginica» dentro del conjunto de datos «iris» iris = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/iris.csv") stats.shapiro (iris.loc[iris.Species == "setosa", "Petal.Width"]) stats.shapiro (iris.loc[iris.Species == "virginica", "Petal.Width"]) stats.ttest_ind (iris.loc[iris.Species=="setosa","Petal.Width"], iris.loc[iris.Species=="virginica","Petal.Width"], equal_var=False) stats.mannwhitneyu (iris.loc[iris.Species=="setosa","Petal.Width"], iris.loc[iris.Species=="virginica","Petal.Width"], alternative='two-sided') # parecido ## contraste sobre la mediana de la diferencia (muestras pareadas) randu = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/randu.csv") # comparar «x» con «y» dif = randu.x - randu.y stats.shapiro (dif) # irrelevante por el tamaño muestral stats.wilcoxon (dif) stats.wilcoxon (randu.x, randu.y) # otra forma de hacer lo mismo stats.ttest_rel (randu.x, randu.y) # parecido stats.ttest_1samp (dif, 0) # lo mismo
1.4.7 Contrastes de hipótesis sobre independencia
1.4.7.1 R
library(car) # para Chile ### contraste ji-2 ## ¿hay relación entre región y sexo? table (Chile$region, Chile$sex) prop.table(table (Chile$region, Chile$sex), 1) chisq.test (table (Chile$region, Chile$sex)) ## ¿hay relación entre educación y sexo? ## ¿hay relación entre sexo y voto? ## ¿hay relación entre educación y voto? ### contraste de correlación lineal ## ¿hay relación entre población, edad, ingresos y statusquo? variables <- c("population", "age", "income", "statusquo") # names (which (sapply (Chile, is.numeric))) cor (Chile[variables], use="pair") sapply (Chile[variables], shapiro.test) # no gausianas => mejor Spearman plot (Chile$population, Chile$age) cor.test (Chile$population, Chile$age) # por omisión, Pearson (exige gausianidad) cor.test (Chile$population, Chile$age, method="spearman") plot (Chile$population, Chile$income) plot (jitter(Chile$population), jitter(Chile$income)) # jitter ayuda para representar discretas con pocos niveles ## etc.
1.4.7.2 Python
import numpy as np # para isnan import pandas as pd from scipy import stats import matplotlib.pyplot as plt # para scatter Chile = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/Chile.csv") ### contraste ji-2 ## ¿hay relación entre región y sexo? tabla = Chile.groupby(["region","sex"]).size().unstack() tabla = pd.crosstab (Chile.region, Chile.sex) # otra forma pd.crosstab (Chile.region, Chile.sex, normalize="index") # index=filas columns=columnas stats.chi2_contingency (tabla) ## ¿hay relación entre educación y sexo? ## ¿hay relación entre sexo y voto? ## ¿hay relación entre educación y voto? ### contraste de correlación lineal ## ¿hay relación entre población, edad, ingresos y statusquo? Chile.corr() variables = ["population", "age", "income", "statusquo"] Chile[variables].apply(stats.shapiro) # pero hay «nan»es Chile[variables].apply(lambda x:stats.shapiro(x[~np.isnan(x)])) # no gausianas => mejor Spearman plt.scatter (Chile.population, Chile.age) def cor_test (x, y): xsinnan = ~ np.isnan (x) ysinnan = ~ np.isnan (y) ambos = xsinnan & ysinnan return stats.pearsonr (x[ambos], y[ambos]) cor_test (Chile.population, Chile.age) # pearson stats.spearmanr (Chile.population, Chile.age) # spearman ## etc.
1.4.8 Regresión lineal
1.4.8.1 R
cor (mtcars) # buscamos predictor para «mpg» sort (abs (cor(mtcars)[,"mpg"])) # el peso parece el mejor predictor lineal plot (mpg ~ wt, mtcars) modelo <- lm (mpg ~ wt, mtcars) abline (modelo, col=2, lwd=3) # añade recta; lwd = linewidth = anchura summary (modelo) # coeficientes, R2, p-valor, estima de sigma ## p-valor del modelo = p-valor de la pendiente predict (modelo, data.frame(wt=3)) # para un coche de 3.000 libras coef(modelo) %*% c(1,3) # lo mismo; 1 multiplica al intercepto
1.4.8.2 Python
import pandas as pd mtcars = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/mtcars.csv") mtcars.corr() abs(mtcars.corr().mpg).sort_values() # «wt» parece el mejor predictor lineal import matplotlib.pyplot as plt x = mtcars.wt; y = mtcars.mpg x = x.values.reshape(-1,1); y = y.values.reshape(-1,1) plt.scatter (x, y) plt.show() from sklearn import linear_model regre = linear_model.LinearRegression() regre.fit (x, y) plt.scatter (x, y) plt.plot (x, regre.predict (x), color='red', linewidth=3) plt.show() regre.predict(3) # predicción para 3.000 libras regre.intercept_ + regre.coef_ * 3 # lo mismo regre.score (x, y) # R2
Con otro módulo (quizá requiera «apt install python-statsmodels»):
import pandas as pd mtcars = pd.read_csv ("http://bellman.ciencias.uniovi.es/~carleos/master/iot/ces/datos/mtcars.csv") import statsmodels.formula.api as smf regre = smf.ols ("mpg ~ wt", data = mtcars) resul = regre.fit() print (resul.summary ()) print (resul.summary2 ()) # incluye estimación de varianza residual (scale)
1.4.9 Ejercicio
- Analizar el conjunto de datos sobre soldabilidad.
- Las variables respuesta
"I1.110.V1.19..Diam.1.20" "I2.260.V2.26..diam.1.20" "I3.290.V3.28........diam.1.20"
expresan las incidencias leves (1), medias (1,5) y graves (2) producidas en tres condiciones distintas.
- Hallar qué variables están más relacionadas con la aparición de incidencias.
- Aplica la regla de Bonferroni por los muchos contrastes realizados.
- Las variables respuesta
s <- read.delim2 ("soldabilidad.csv", encoding="UTF-8") respuestas <- names(s) [grep ("^I", names(s))] # las variables que empiezan por I; vcuan <- names(s) [sapply (s, is.numeric)] # las variables cuantitativas; s$isum <- apply (s[respuestas], 1, sum) # suma de variables respuesta; # intento combinar las respuestas para conseguir # una relación más potento; no funciona; s$i222 <- + (s$isum >= 6) # produce una binaria 0/1; al menos tres incidencias graves; # binarizo la variable tras observar en # plot (jitter(isum) ~ jitter(DIAMETRO.PRIMARIA), s) # que los puntos se acumulan en torno a dos núcleos; s$i2 <- + (apply (s[respuestas]>=2, 1, sum) >= 1) # produce una binaria 0/1; al menos una incidencia grave; # categorías más igualadas en frecuencia que las de i222; respuestas <- c (respuestas, "isum", "i2", "i222") vcuan <- setdiff (vcuan, respuestas) # quito las respuestas del conjunto de cuantitativas; for (respuesta in respuestas) {print (respuesta) print (as.matrix (sort (sapply (vcuan, function (regresor) { cor.test (as.numeric (s[[respuesta]]), s[[regresor]], method = "spearman") $ p.value}))))} ### bonferroni: 0,05 / 35 = 0,0014 ### "I1.110.V1.19..Diam.1.20" ## DIAMETRO.PRIMARIA 0.002251121 ## DIAM.REAL 0.008152350 ## VELOCIDAD.B.H. 0.031407815 ## DIAMETRO.T..SOLD 0.048781893 ### "I2.260.V2.26..diam.1.20" ## DIAMETRO.PRIMARIA 0.0009058342 * ## DIAM.REAL 0.0017408604 ## DIAMETRO.T..SOLD 0.0155378535 ## VELOCIDAD.B.H. 0.0297429942 ## g.l.CuSO4..BALSA.COBREADO 0.0370335115 ### "I3.290.V3.28........diam.1.20" ## DIAM.REAL 2.357221e-06 * ## DIAMETRO.PRIMARIA 8.076238e-05 * ## DIAMETRO.T..SOLD 9.713180e-05 * ## VELOCIDAD.B.H. 1.172313e-04 * ## g.l.H2SO4.BALSA.LAVADO 2.239665e-02 ## g.l.CuSO4..BALSA.COBREADO 2.292582e-02 ## Kg.NaHCO3 2.824911e-02 ## ASPECTO 3.676416e-02 ### "i2" ## DIAM.REAL 4.039804e-13 * ## DIAMETRO.T..SOLD 6.133817e-10 * ## VELOCIDAD.B.H. 1.498757e-08 * ## DIAMETRO.PRIMARIA 3.215726e-08 * ## g.l.CuSO4..BALSA.COBREADO 1.467726e-04 * ## g.l.H2SO4.BALSA.LAVADO 2.252047e-03 ## g.l.Fe.BALSA.LAVADO 6.999013e-03 ## ASPECTO 9.023894e-02 ### "i222" ## DIAM.REAL 1.290101e-09 * ## DIAMETRO.T..SOLD 7.128282e-08 * ## DIAMETRO.PRIMARIA 1.259775e-07 * ## VELOCIDAD.B.H. 5.989867e-06 * ## g.l.CuSO4..BALSA.COBREADO 1.571575e-04 * wilcox.test (g.l.CuSO4..BALSA.COBREADO ~ i2, s) # P-val = 0,00023 wilcox.test (g.l.CuSO4..BALSA.COBREADO ~ i222, s) # P-val = 0,00025 vcual <- names(s) [sapply (s, is.factor)] # las variables cualitativas as.matrix (sort (sapply (vcual, function (var) chisq.test (s$i222, s[[var]]) $ p.value))) as.matrix (sort (sapply (vcual, function (var) chisq.test (s$i2, s[[var]]) $ p.value))) ## CARRETÓN..PRIMARIA 0.0004170954 * ## CAMBIO.HILERAS 0.0340978770 ## Nº.OPERARIO.1ª 0.0368501365 ## TURNO.1ª 0.0445130045 ### para refinar, binarizamos CAMBIO.HILERAS y eliminamos niveles con «y», «Y» ó «-» s$CAMBIO.HILERAS2 <- factor (s$CAMBIO.HILERAS != "NO") chisq.test (s$CAMBIO.HILERAS2, s$i2) # P-val = 0,782 sort (suppressWarnings (sapply (vcual, function (var) {pos <- grep ("y|Y|-", s[[var]]) sC <- if (length(pos) == 0) s else droplevels (s [-pos, ]) try (chisq.test (sC$i2, sC[[var]]) $ p.value)}))) ## CARRETÓN..PRIMARIA 0.0001112745 ## CAMBIO.HILERAS 0.0351196639 ## TURNO.1ª 0.0911208458 ## VELOCIDAD.PRIMARIA 0.1397938411 ## Nº.OPERARIO.1ª 0.1596331957
2 filtrado
2.1 ejecución remota
2.1.1 conexión con el servidor mediante SSH
2.1.1.1 programas útiles desde Windows
- PuTTY
- instalar desde https://putty.org
- trasferir ficheros
- abrir ventanas gráficas remotas localmente
- Xming
- instalar y ejecutar Xming (enlace directo)
- en PuTTY, activar Connection: SSH: X11: Enable X11 forwarding
- Cygwin
- otra posibilidad sería instalar Cygwin
- distribuye paquetes de ventanas X
- Xming
2.1.1.2 servidor
- conectar a
carleos2.epv.uniovi.es
- equivalentemente, a
156.35.173.1
- la conexión SSH usa la puerta 22
2.1.1.3 cuentas de usuario
- existen éstas:
abel daniel guillermo ivana javiers jorge jorgel
- para cambiar la contraseña:
passwd
- para evitar problemas por desconexión usar GNU screen
screen -DUR
ejecutar esa orden antes de empezar a trabajar y, en caso de desconexión, volver a ejecutarla para recuperar la sesión
- si quieres cambiar el idioma del sistema:
- entorno en español
export LC_ALL=es_ES.UTF-8
- es = idioma castellano
- ES = país España
- UTF-8 = codificación de Unicode
- entorno básico «internacional»
export LC_ALL=C
- mensajes en inglés
- codificación ASCII
- entorno en español
2.1.2 gestión de ficheros
Mediante GNU coreutils
2.1.2.1 ayuda
apropos compiler # buscar sobre un término man gcc # página de manual info # ayuda de GNU
2.1.2.2 carpetas (directorios)
pwd # conocer directorio actual ls # listar contenido ls -l # versión larga ls -lrt # deja al final los últimos modificados ls -h # tamaños legibles para humanos mkdir ejemplo1 # crear directorio «ejemplo1» cd ejemplo1 # entrar en «ejemplo1» cd .. # salir del directorio rmdir # borrar un directorio vacío (seguro) rm -rf # borrar un directorio y su contenido (atrevido)
- El directorio actual se representa por «
.
» - El directorio superior se representa por «
..
» - El directorio personal se representa por «
~
» - El directorio público está en «
~/public_html
»Los archivos que el usuario
mengano
meta en su directorio público serán accesibles desde un navegador de hipertexto a través de la direcciónhttp://carleos2.epv.uniovi.es/~mengano
(salvo que, por ejemplo, se cree un fichero
index.html
en ese directorio).
2.1.2.3 ficheros
touch fichero.txt # crear fichero vacío cp fichero.txt fichero1.txt # copiar mv fichero.txt fichero0.txt # renombrar mv fichero0.txt /tmp # mover rm fichero1.txt # borrar fichero
2.1.3 R
- el programa se llama «R»
- cuando se ejecuta en un determinado directorio, quedan en éste…
- …un fichero oculto «.Rhistory» con las instrucciones ejecutadas
- …un fichero oculto «.RData» que contiene el espacio de trabajo (variables definidas)
- EJERCICIO
- realiza en el servidor la regresión de la respuesta «I3=290,V3=28, diam 1,20» del conjunto de datos sobre soldabilidad frente al «DIAMETRO PRIMARIA»
- guarda en un fichero de salida los coeficientes del modelo y el coeficiente de determinación
- solución
s <- read.delim2 ("soldabilidad.R") m <- lm (I3.290.V3.28........diam.1.20 ~ DIAMETRO.PRIMARIA, s) coef (m) summary (m) cat (coef (m), "\n", file = "salida-cat.txt") cat (summary (m) $ r.squared, file = "salida-cat.txt", append = TRUE)
el fichero anterior se llamaría desde Bash así:
R --vanilla < programa.R # salida por pantalla R --vanilla < programa.R > salida.txt # salida por fichero R --vanilla < programa.R | tee salida.txt # salida por ambos
2.2 estadígrafos descriptivos en C
2.2.1 compilación en C
2.2.1.1 editores
nano fichero.c # editor básico jed fichero.c # más completo, amigable emacs fichero.c # casi un sistema operativo
2.2.1.2 órdenes
gcc fichero.c # compilar ./a.out # ejecutar
gcc -o ej1.exe ejemplo1.c # compilar ./ej1.exe # ejecutar
2.2.2 sin bibliotecas
Usando la implementación de qsort de https://programmingpraxis.com/2016/10/28
#include <stdio.h> /* media */ double media (double *muestra, int n) { double suma = 0; for (int i = 0; i < n; i++) suma += muestra[i]; return suma / n; } /* mediana */ void swap (double* a, double* b) { double tmp = *a; *a = *b; *b = tmp; } int partition (double* array, int n) { double pivot = array[0]; for (int i = 1, j = n-1;; ++i, --j) { while (i < n && array[i] < pivot) ++i; while (j >= 0 && array[j] > pivot) --j; if (i >= j) { swap (array, array + j); return j; } swap(array + i, array + j); } } void qsort (double* array, int n) { if (n <= 1) return; int p = partition (array, n); qsort (array, p); qsort (array + p + 1, n - p - 1); } double mediana (double *muestra, int n) { qsort (muestra, n); return ((n % 2) ? muestra[(n-1)/2] : (muestra[n/2-1] + muestra[n/2]) / 2); } /* PRINCIPAL */ int main () { double datos[6] = {17.2, 18.1, 16.5, 18.3, 12.6, 17.8}; printf ("Media = %g\n", media (datos, 6)); printf ("Mediana = %g\n", mediana (datos, 6)); return 0; }
2.2.3 uso de GNU LibC para ordenar
Según https://www.gnu.org/software/libc/manual/html_node/Searching-and-Sorting.html
#include <stdio.h> #include <stdlib.h> /* media */ double media (double *muestra, int n) { double suma = 0; for (int i = 0; i < n; i++) suma += muestra[i]; return suma / n; } /* mediana */ int compare_doubles (const void *a, const void *b) { const double *da = (const double *) a; const double *db = (const double *) b; return (*da > *db) - (*da < *db); } double mediana (double *muestra, int n) { qsort (muestra, n, sizeof (double), compare_doubles); return ((n % 2) ? muestra[(n-1)/2] : (muestra[n/2-1] + muestra[n/2]) / 2); } int main () { double datos[6] = {17.2, 18.1, 16.5, 18.3, 12.6, 17.8}; printf ("Los datos al principio son %g, %g, %g, %g, %g\n", datos[0], datos[1], datos[2], datos[3], datos[4]); printf ("Media = %g\n", media (datos, 6)); printf ("Mediana = %g\n", mediana (datos, 6)); printf ("Los datos tras calcular la mediana son %g, %g, %g, %g, %g\n", datos[0], datos[1], datos[2], datos[3], datos[4]); return 0; }
Compilar meramente con gcc ejemplo.c
Si quiere evitarse la modificación de los datos originales, debe hacerse el cálculo sobre una copia:
#include <stdio.h> /* para printf */ #include <stdlib.h> /* para qsort */ #include <string.h> /* para memcpy */ /* media */ double media (double *muestra, int n) { double suma = 0; for (int i = 0; i < n; i++) suma += muestra[i]; return suma / n; } /* mediana */ int compare_doubles (const void *a, const void *b) { const double *da = (const double *) a; const double *db = (const double *) b; return (*da > *db) - (*da < *db); } double mediana (double *muestra, int n) { double copia[n]; memcpy (copia, muestra, n * sizeof(double)); qsort (copia, n, sizeof (double), compare_doubles); return ((n % 2) ? copia[(n-1)/2] : (copia[n/2-1] + copia[n/2]) / 2); } int main () { double datos[6] = {17.2, 18.1, 16.5, 18.3, 12.6, 17.8}; printf ("Los datos al principio son %g, %g, %g, %g, %g\n", datos[0], datos[1], datos[2], datos[3], datos[4]); printf ("Media = %g\n", media (datos, 6)); printf ("Mediana = %g\n", mediana (datos, 6)); printf ("Los datos tras calcular la mediana son %g, %g, %g, %g, %g\n", datos[0], datos[1], datos[2], datos[3], datos[4]); return 0; }
2.2.4 uso de GNU Scientific Library
2.2.4.1 compilar con GSL
Si la biblioteca GSL se ha instalado con el sistema de paquetería oficial del sistema operativo (por ejemplo, APT en Debian y Ubuntu):
gcc ejemplo.c -lgsl -lgslcblas -lm
Si la biblioteca GSL se ha instalado desde código fuente (por ejemplo, descargándola desde la página de GNU para tener la última versión publicada):
LD_LIBRARY_PATH=/usr/local/lib gcc ejemplo.c -lgsl -lgslcblas -lm
Otra opción en este caso es usar compilación estática…
gcc -static ejemplo.c -lgsl -lgslcblas -lm
…pero compárense los tamaños de los ejecutables:
gcc -o ejemplo-dinamico.out ejemplo.c gcc -o ejemplo-estatico.out -static ejemplo.c ls -lh ejemplo-*.out
stdlib
no añade mucho al tamaño; gsl
, un poco más.
2.2.4.2 media y mediana
Según https://www.gnu.org/software/gsl/doc/html/statistics.html#examples
#include <stdio.h> #include <gsl/gsl_sort.h> /* para la mediana */ #include <gsl/gsl_statistics.h> int main () { double datos[5] = {17.2, 18.1, 16.5, 18.3, 12.6}; double media, mediana; printf ("Los datos son %g, %g, %g, %g, %g\n", datos[0], datos[1], datos[2], datos[3], datos[4]); media = gsl_stats_mean (datos, 1, 5); gsl_sort (datos, 1, 5); printf ("Datos ordenados: %g, %g, %g, %g, %g\n", datos[0], datos[1], datos[2], datos[3], datos[4]); mediana = gsl_stats_median_from_sorted_data (datos, 1, 5); printf ("La media muestral es %g\n", media); printf ("La mediana es %g\n", mediana); return 0; }
En caso de no querer modificar el vector original por el
cálculo de la mediana, podría usarse memcpy
de stdlib
o bien usar vectores de GLS como en el siguiente listado:
#include <stdio.h> #include <gsl/gsl_vector.h> #include <gsl/gsl_sort_vector.h> #include <gsl/gsl_statistics.h> int main () { gsl_vector * datos = gsl_vector_alloc (5); gsl_vector_set (datos, 0, 17.2); gsl_vector_set (datos, 1, 18.1); gsl_vector_set (datos, 2, 16.5); gsl_vector_set (datos, 3, 18.3); gsl_vector_set (datos, 4, 12.6); double media, mediana; printf ("Los datos son %g, %g, %g, %g, %g\n", gsl_vector_get (datos, 0), gsl_vector_get (datos, 1), gsl_vector_get (datos, 2), gsl_vector_get (datos, 3), gsl_vector_get (datos, 4)); media = gsl_stats_mean (datos->data, datos->stride, datos->size); gsl_vector * copia = gsl_vector_alloc (5); gsl_vector_memcpy (copia, datos); gsl_sort_vector (copia); printf ("Los datos ordenados son %g, %g, %g, %g, %g\n", gsl_vector_get (copia, 0), gsl_vector_get (copia, 1), gsl_vector_get (copia, 2), gsl_vector_get (copia, 3), gsl_vector_get (copia, 4)); mediana = gsl_stats_median_from_sorted_data (copia->data, copia->stride, copia->size); printf ("La media muestral es %g\n", media); printf ("La mediana es %g\n", mediana); printf ("Los datos originales siguen siendo %g, %g, %g, %g, %g\n", gsl_vector_get (datos, 0), gsl_vector_get (datos, 1), gsl_vector_get (datos, 2), gsl_vector_get (datos, 3), gsl_vector_get (datos, 4)); return 0; }
2.2.5 generación de código fuente C mediante R
Por comodidad, puede generarse el programa C desde un lenguaje a alto nivel:
datos <- round (runif (6, 10, 20), 1) n <- length (datos) cat (' #include <stdio.h> #include <gsl/gsl_sort.h> /* para la mediana */ #include <gsl/gsl_statistics.h> int main () { double datos[', n, '] = {', paste (datos, collapse=","), '}; double media, mediana; printf ("Los datos son ', rep ('%g; ', n), '\\n",', paste0 ("datos[", 0:(n-1), "]", collapse=', '), '); media = gsl_stats_mean (datos, 1, ',n,'); gsl_sort (datos, 1, ',n,'); printf ("Datos ordenados: ', rep ('%g; ', n), '\\n",', paste0 ("datos[", 0:(n-1), "]", collapse=', '), '); mediana = gsl_stats_median_from_sorted_data (datos, 1, ',n,'); printf ("La media muestral es %g\\n", media); printf ("La mediana es %g\\n", mediana); return 0; } ', file = 'ejemplo-gsl-R.c', sep = "")
2.2.6 ejercicio
Usa la biblioteca GSL para realizar en C la regresión lineal de la respuesta «I3…» del conjunto de datos sobre soldabilidad frente al «DIAMETRO PRIMARIA».
Guarda en un fichero de salida los coeficientes del modelo y el coeficiente de determinación.
Partimos de este ejemplo…
/* inspirado en https://www.gnu.org/software/gsl/doc/html/lls.html#simple-linear-regression-example */ #include <stdio.h> #include <gsl/gsl_fit.h> int main (void) { int i, n = 4; double x[4] = { 1970, 1980, 1990, 2000 }; double y[4] = { 12, 11, 14, 13 }; double c0, c1, cov00, cov01, cov11, chisq; gsl_fit_linear (x, 1, y, 1, n, &c0, &c1, &cov00, &cov01, &cov11, &chisq); printf ("# mejor ajuste: Y = %g + %g X\n", c0, c1); printf ("# matriz de covarianzas:\n"); printf ("# [ %g, %g\n# %g, %g]\n", cov00, cov01, cov01, cov11); printf ("# ji2 = %g\n", chisq); return 0; }
…y pergeñamos este programa en R:
s <- read.delim2 ('soldabilidad.csv') x <- s$DIAMETRO.PRIMARIA y <- s$I3.290.V3.28........diam.1.20 filtro <- !is.na(x) & !is.na(y) x <- x[filtro] y <- y[filtro] n <- length (x) stopifnot (n == length(y)) cat (' #include <stdio.h> #include <gsl/gsl_statistics_double.h> #include <gsl/gsl_fit.h> int main (void) { int n = ',n,'; double x[',n,'] = { ',paste(x,collapse=','),' }; double y[',n,'] = { ',paste(y,collapse=','),' }; double c0, c1, cov00, cov01, cov11, chisq, sct; sct = gsl_stats_tss (y, 1, n); gsl_fit_linear (x, 1, y, 1, n, &c0, &c1, &cov00, &cov01, &cov11, &chisq); printf ("# mejor ajuste: Y = %g + %g X\\n", c0, c1); printf ("# matriz de covarianzas:\\n"); printf ("# [ %7.3f %7.3f ]\\n# [ %7.3f %7.3f ]\\n", cov00, cov01, cov01, cov11); printf ("# ji2 = %g\\n", chisq); printf ("# SCT = %g\\n", sct); printf ("# R2 = 1 - ji2:SCT = %g\\n", 1 - chisq / sct); FILE * salida = fopen ("salida.sex", "w"); fprintf (salida, "((coef (%g %g)) (r2 %g))\\n", c0, c1, 1-chisq/sct); fclose (salida); return 0; }', file = "regresion.c")
2.3 cálculo de estadígrafos en continuo
Se llama cálculo de estadígrafos en continuo, al vuelo, en línea, en flujo, en corriente… o bien estadígrafos móviles, rodantes, corrientes…
Se emplean para resumir datos que no caben en memoria todos a la vez. Para ello, se establece un acumulador cuyos parámetros se van actualizando según se incluyen nuevos datos.
Los cálculos de medias y varianzas son exactos. Los de los cuantiles son aproximados, aunque su precisión mejora con el aumento del tamaño muestral integrado por el acumulador.
Véase la sección Running Statistics de la G.S.L.
EJERCICIOS
- Inferir la distribución de valores de los octetos generados por «/dev/urandom»,
utilizando el acumulador «rstat» en vez de un vector para almacenar los datos.
Por ejemplo, calcular valores de media, varianza, asimetría, curtosis y comparar con los teóricos.
#include <stdio.h> #include <gsl/gsl_rstat.h> #include <fcntl.h> /* para open */ #include <unistd.h> /* para read */ #include <time.h> /* para nanosleep */ int main(void) { size_t i, n = 10000; /* nu'mero de valores muestreados */ struct timespec espera; espera.tv_sec = 0; /* segundos entre muestreos */ espera.tv_nsec = 1000000; /* nanosegundos entre muestreos */ char nuevodato; double media, varianza, dt, asimetria, curtosis; gsl_rstat_workspace *acumulador = gsl_rstat_alloc(); int manantial = open ("/dev/urandom", O_RDONLY); for (i = 0; i < n; ++i) { read (manantial, &nuevodato, sizeof(nuevodato)); gsl_rstat_add((double) nuevodato, acumulador); media = gsl_rstat_mean(acumulador); varianza = gsl_rstat_variance(acumulador); dt = gsl_rstat_sd(acumulador); asimetria = gsl_rstat_skew(acumulador); curtosis = gsl_rstat_kurtosis(acumulador); printf ("%lu: %d => %g, %g, %g, %g, %g\n", i, nuevodato, media, varianza, dt, asimetria, curtosis); nanosleep (&espera, NULL); } gsl_rstat_free(acumulador); return 0; }
- Inferir la distribución de valores del fichero de resultados sobre matemáticas en PISA: «/home/iot/dat/pvmath.dat»
#include <stdio.h> #include <locale.h> #include <gsl/gsl_rstat.h> int main(void) { ssize_t i = 0; char * registro; size_t anchura = 0; double nuevodato; double media, varianza, dt, asimetria, curtosis; gsl_rstat_workspace * acumulador = gsl_rstat_alloc(); setlocale (LC_ALL, "es_ES.utf8"); FILE * manantial = fopen ("/home/iot/dat/pvmath.dat", "r"); while (getline (®istro, &anchura, manantial) != -1) { sscanf (registro, "%lg\n", &nuevodato); gsl_rstat_add((double) nuevodato, acumulador); media = gsl_rstat_mean(acumulador); varianza = gsl_rstat_variance(acumulador); dt = gsl_rstat_sd(acumulador); asimetria = gsl_rstat_skew(acumulador); curtosis = gsl_rstat_kurtosis(acumulador); printf ("%lu: %g => %g, %g, %g, %g, %g\n", ++i, nuevodato, media, varianza, dt, asimetria, curtosis); } gsl_rstat_free(acumulador); return 0; }
2.4 ventanas y núcleos
- Señal muestreada: Secuencia de valores que representan los cambios de cierto fenómeno a través de una dimensión (tiempo o espacio).
- Filtro digital: Algoritmo que elimina algún aspecto de la señal (frecuencias, ruidos…)
- Objetivo: Estimar la forma y tendencia de una señal mediante el cálculo de estadígrafos locales (ponderados a través función núcleo), basados en un entorno (ventana) alrededor de cada observación del flujo de datos.
- El entorno de una observación \(x_i\) incluye \(H\) observaciones previas y \(J\) observaciones posteriores.
El entorno contiene entonces \(K=H+1+J\) observaciones: \[\mbox{ventana de $x_i$} = \left\{ x_{i-H},\dots,x_i,\dots,x_{i+J} \right\} \]
- Manejo de los extremos: Al principio y al final de la secuencia no hay \(K\) observaciones para rellenar el entorno. Caben diversas formas de soslayarlo.
2.4.1 señales de ejemplo
- senoidal más ruido gausiano
x <- seq (0, 10, 0.01); y <- sin (x) + rnorm (x, 0, 0.1)
- parábola contaminada, sacada de «example(runmed)»
y <- (-20:20)^2 y [c(1,10,21,41)] <- c(150, 30, 400, 450)
- onda rectangular
x <- seq (0, 10, 0.01); y <- floor(x) %% 2
- señales eléctricas
@carleos2.epv.uniovi.es:/home/iot/dat
EJERCICIO
- representar gráficamente todas las señales
2.4.2 media móvil
- Se trata de calcular la media aritmética de los valores próximos a cada observación: \[\hat{\mu}_i = \frac{1}{K} \sum_{m=i-H}^{i+J} x_m \]
- EJERCICIO
- implementar una media móvil en R usando
mean
filtro <- function (x, h, j=h) c (rep (NA, h), sapply ((h+1):(length(x)-j), function (i) mean (x[(i-h):(i+j)])), rep (NA, j)) filtro (señal, 3) # filtra con ventana de anchura k = 2×3+1 = 7
- aplicar el filtro a las señales de ejemplo buscando una \(K\) adecuada en cada caso
- implementar una media móvil en R usando
2.4.3 alisado gausiano
- Se trata de calcular la media aritmética ponderada de los valores próximos a cada observación: \[\hat{\mu}_i = \frac{1}{\sum_{m=i-H}^{i+H} G(m)} \sum_{m=i-H}^{i+H} x_m\cdot G(m) \]
- Sus ponderaciones se basan en la campana de Gaus: \[ G(m) = e^{-\frac{1}{2} \left( \alpha \frac{m}{H} \right)^2} = e^{-m^2/2\sigma^2} \] para \(-H = -(K-1)/2 \le m \le (K-1)/2 =H\).
- \(\alpha\) representa el número de desviaciones típicas (\(\sigma\)) cubiertas por la ventana: \[\sigma = \frac{H}{\,\alpha} \]
- Se usa para reducir el ruido de una señal.
- EJERCICIO
- implementar un filtro gausiano en R
(puedes usar
weighted.mean
ydnorm
)filtro <- function (x, k, alfa) { h <- (k-1)/2 c (rep (NA, h), sapply ((h+1):(length(x)-h), function (i) weighted.mean (x[(i-h):(i+h)], dnorm ((-h):(+h), sd = (k-1)/2/alfa))), rep (NA, h)) } filtro (señal, 3, 1) # filtra con ventana de anchura k = 3 y alfa = 1
- usar el filtro sobre las señales de ejemplo (en especial la rectangular) y estudiar el efecto de \(K\) y \(\alpha\)
- implementar un filtro gausiano en R
(puedes usar
2.4.4 mediana móvil
- Calcular la mediana del entorno de cada observación. \[\hat{\mu}_i = \mbox{Mediana}\,\left\{ x_m \mid {i-H}\leq m\leq{i+J} \right\} \]
- Propiedades:
- Robusta ante atípicos locales (la media es sensible a ellos).
- Tiende a preservar los saltos súbitos de la señal (la media los suaviza).
- EJERCICIO
- implementar un filtro de mediana en R usando
median
- usarlo en las señales de ejemplo
- parábola contaminada
- señal rectangular
comparar su efecto con el de los filtros de medias
- implementar un filtro de mediana en R usando
2.5 filtrado en R
R incluye implementaciones optimizadas en lenguaje C de filtros de medias y medianas.
2.5.1 filter
- realiza medias móviles (convolución) por omisión
- toma (al menos) dos argumentos
- vector de datos
x
- pesos o ponderaciones
p
mu <- filter (x, p)
\[\hat{\mu}_i = \frac{1}{K} \sum_{m=i-H}^{i+J} x_m\cdot p_m \] donde \(K\) =
length(p)
; \(x_m\) es cada elemento dex
; \(p_m\) es cada elemento dep
; \(H = J = \frac{K-1}2\) si \(K\) es impar y el filtro es simétrico
- vector de datos
- en los valores extremos considera que los datos externos son ausentes (NA) por omisión (hay opción «circular=TRUE»)
- la longitud de la ventana (\(K\)), en el caso de ventana simétrica (opción «sides=2», por omisión) debería ser impar; en caso de ser par, considera \(J=H+1\) (o sea, una observación más por la derecha que por la izquierda)
- uso como convolución por omisión
- uso para media móvil básica (de ponderaciones uniformes)
- en ese caso, \(p_m = \frac1m\) para todo \(m\);
plot (AirPassengers) k=12; plot (filter (AirPassengers, rep(1,k)/k))
- en ese caso, \(p_m = \frac1m\) para todo \(m\);
AVISO
filter
es usada por «decompose», aunque en caso de longitud par de ventana, «decompose» usa pesos completamente simétricos \( \frac12;1;1;\dots;1;1;\frac12 \);decompose(AirPassengers)
EJERCICIO
- usar
filter
para implementar un alisado gausiano - comparar velocidad de
filter
con la de la implementación personal en R aplicándolas a una secuencia muy larga
2.6 filtrado en C
- Es necesario reservar un espacio para efectuar los cálculos, por ejemplo mediante
gsl_movstat_workspace * gsl_movstat_alloc(const size_t K)
Dicho espacio se libera con
void * gsl_movstat_free(gsl_movstat_workspace * w)
- Extremos. Hay varias opciones sobre cómo aplicar el filtro en los extremos:
- rellenar los huecos con ceros (
GSL_MOVSTAT_END_PADZERO
) - repetir el primer (resp. último) valor en los huecos (
GSL_MOVSTAT_END_PADVALUE
) - dejar esos entornos con menos observaciones (
GSL_MOVSTAT_END_TRUNCATE
)
- rellenar los huecos con ceros (
- Véanse las secciones Moving Window Statistics y Digital Filtering de la G.S.L.
2.6.1 media móvil
int gsl_movstat_mean(const gsl_movstat_end_t endtype, const gsl_vector * x, gsl_vector * y, gsl_movstat_workspace * w)¶
x
es el vector de datosy
es el resultado
En R se calcularía mediante filter aplicando pesos uniformes.
Ejemplo sobre una señal senoidal ruidosa:
#include <stdio.h> #include <stdlib.h> #include <gsl/gsl_math.h> #include <gsl/gsl_movstat.h> #include <gsl/gsl_rng.h> #include <gsl/gsl_randist.h> #include <gsl/gsl_vector.h> int main(void) { const size_t N = 500; /* longitud de la secuencia de la señal */ const size_t K = 11; /* anchura de ventana (H = J = 5) */ gsl_movstat_workspace * w = gsl_movstat_alloc(K); gsl_vector *x = gsl_vector_alloc(N); gsl_vector *xmedia = gsl_vector_alloc(N); gsl_rng *r = gsl_rng_alloc(gsl_rng_default); size_t i; for (i = 0; i < N; ++i) { double xi = cos(2.0 * M_PI * i / (double) N); double ei = gsl_ran_gaussian(r, 0.1); gsl_vector_set(x, i, xi + ei); } /* calcular media móvil */ gsl_movstat_mean(GSL_MOVSTAT_END_PADVALUE, x, xmedia, w); /* resultado */ for (i = 0; i < N; ++i) { printf("%zu %f %f\n", i, gsl_vector_get(x, i), gsl_vector_get(xmedia, i); } gsl_vector_free(x); gsl_vector_free(xmedia); gsl_rng_free(r); gsl_movstat_free(w); return 0; }
EJERCICIO
- Aplicar una media móvil a los datos de «/home/iot/dat/señales-eléctricas.csv».
Buscar la K apropiada en cada caso.
2.6.2 alisado gausiano
Hay que preparar un espacio de trabajo mediante
gsl_filter_gaussian_workspace * gsl_filter_gaussian_alloc(const size_t K)
que se puede liberar con
void gsl_filter_gaussian_free(gsl_filter_gaussian_workspace * w)
La función que efectúa el alisado es:
int gsl_filter_gaussian(const gsl_filter_end_t endtype, const double alpha, const size_t order, const gsl_vector * x, gsl_vector * y, gsl_filter_gaussian_workspace * w)¶
x
es la entraday
es la salidaalpha
es \(\alpha\), el parámetro del núcleoendtype
indica qué hacer en los extremos (principio y fin) de la señalorder
ha de ser 0 para alisado (1 para primera derivada, etc.)
2.6.3 mediana móvil
En C tenemos dos versiones. La primera tiene interfaz similar a la media móvil:
int gsl_movstat_median(const gsl_movstat_end_t endtype, const gsl_vector * x, gsl_vector * y, gsl_movstat_workspace * w)
La segunda versión tiene la interfaz de los métodos de alisado:
gsl_filter_median_workspace * gsl_filter_median_alloc(const size_t K) int gsl_filter_median(const gsl_filter_end_t endtype, const gsl_vector * x, gsl_vector * y, gsl_filter_median_workspace * w) void gsl_filter_median_free(gsl_filter_median_workspace * w)
En R se calcularía mediante runmed.
2.6.4 filtro de mediana recursivo
En ocasiones, para conseguir un alisado adecuado, se aplica una mediana móvil «en cascada», es decir, varias veces a la misma secuencia.
Un filtro de mediana recursivo converge a una secuencia radical (es decir, que no cambia si es filtrada de nuevo) en una sola pasada.
gsl_filter_rmedian_workspace * gsl_filter_rmedian_alloc(const size_t K) int gsl_filter_rmedian(const gsl_filter_end_t endtype, const gsl_vector * x, gsl_vector * y, gsl_filter_rmedian_workspace * w) void gsl_filter_rmedian_free(gsl_filter_rmedian_workspace * w)
2.6.5 filtro detector de impulsos
Es una versión menos «agresiva» de la mediana móvil: \[yi = \left\{
\begin{array}{cc} x_i, & |x_i - m_i| \le t S_i \\ m_i, & |x_i - m_i| > t S_i \end{array}\right. \] donde
- \(m_i\) es el valor mediano en el entorno de \(x_i\)
- \(S_i\) es una estimación robusta de la dispersión en el entorno
- \(t\) es el parámetro del filtro
\(S_i\) puede ser por ejemplo la desviación absoluta mediana (filtro de Hampel) o el recorrido intercuartílico.
3 descriptiva
3.1 univariante
3.1.1 atributo (variable cualitativa)
3.1.1.1 clasificación
- nominales: nacionalidad, novela favorita…
- ordinales: calificación (malo, regular, bueno), nivel de estudios, rango…
- circulares: días de la semana, meses del año…
3.1.1.2 resúmenes
- distribución de frecuencias (apartado 2.4 del capítulo 1 de Estadística descriptiva y probabilidad)
table (x) # absolutas prop.table (table (x)) # relativas
- diagrama de sectores (para atributos nominales o circulares)
pie (table (x))
- diagrama de barras
barplot (table (x))
3.1.2 variable (cuantitativa)
3.1.2.1 clasificación
- discreta: número de hijos, número de averías…
- continua: diámetro del ánima, peso del proyectil…
3.1.2.2 resúmenes
- centralización
mean (x) # media median (x) # mediana mean (x, trim=0.1) # media truncada
- dispersión
sd (x) # desviación típica IQR (x) # recorrido intercuartílico
- posición
quantile (x, 0.95) # percentil 95
- histograma
hist (x) hist (x, col=2, breaks=100) stem (x) # gráfico de tallo: a menudo más informativo
3.2 bivariante
3.2.1 atributo Y frente a atributo X
- tabla de frecuencias condicionadas
prop.table (table (x, y), 1) # «1» = «por filas»
- mosaico (poco usado)
mosaicplot (y ~ x)
3.2.2 variable X frente a atributo A
- descriptivos condicionados
by (x, a, summary) aggregate (x, list(a), summary)
- diagrama de cajas
boxplot (x ~ a)
3.2.3 variable Y frente a variable X
- diagrama de dispersión (nube de puntos)
plot (y ~ x)
- correlación lineal
cor (x, y) cor (x, y, use="complete", method="pearson") cor (x, y, use="pairwise", method="spearman")
- regresión simple
lm (y ~ x)
3.3 multivariante
3.3.1 variables
- reducción dimensional mediante componentes principales
biplot (princomp (~ ., datos, cor=TRUE)) plot (princomp (~ ., datos, cor=TRUE)) # importancia de los ejes
3.3.2 atributos
- análisis de correspondencias de una tabla de doble entrada
library (MASS) biplot (corresp (x))
4 probabilidad
4.1 teoría de conjuntos
- unión
- intersección
- complemento
4.2 definición de probabilidad
4.2.1 axiomas
- \(\forall\,A\subset\Omega,\quad\Pr\,A \geq 0\)
- \(\Pr\,\Omega = 1\)
- \( \forall\,A,B\subset\Omega,\quad A\cap B=0 \Rightarrow \Pr\,A\cup B = \Pr\,A + \Pr\,B\)
4.2.2 probabilidad condicionada
- definición \[ \Pr\,(A\mid B) = \frac {\Pr\,A\cap B} {\Pr\,B} \]
- probabilidad total
- \(\forall\,i,j\, \quad A_i\cap A_j = \emptyset\)
- \(A_1\cup\dots\cup A_n = \Omega\)
\[ \Pr\,B = \sum_{i=1}^n \Pr\,(B\mid A_i)\cdot\Pr\,A_i \]
- fórmula de Bayes \[\Pr\,(A\mid B) = \frac {\Pr\,(B\mid A)\cdot\Pr\,A} {\Pr\,B} \]
4.2.3 independencia
\[ \text{\(A\) y \(B\) independientes} \Longleftrightarrow \Pr\,A\cap B=\Pr\,A\cdot\Pr\,B \]
4.3 variables aleatorias
4.3.1 generalidades
- tipos
- discretas
- función de probabilidad
- función de cuantía
- función de masa
- continuas
- función de densidad
- discretas
- función de distribución
- momentos
- esperanza = media
- varianza
4.3.2 familias notables de distribuciones univariantes
- binomial B(n,p)
- puasón P(l)
- exponencial Exp(l)
- gausiana N(m,s)
- de Estiúdent t(n)
5 inferencia
Libro Inferencia estadística.
5.1 conceptos
- población
- conjunto infinito de posibles individuos, cuyo comportamiento es el interés del estudio;
- matemáticamente: variable aleatoria (p.ej. \(X\hookrightarrow\mathcal N\,[\mu;\sigma]\))
- muestra
- conjunto finito de individuos observados
- supondremos una muestra aleatoria simple: individuos elegidos independientemente, con la misma distribución
- matemáticamente: variables aleatorias independientes \(X_1\), \(X_2\), …, \(X_n\) con la misma distribución que la población (\(\forall\,i,\quad X_i\hookrightarrow X\))
- tamaño muestral
- número de individuos en la muestra (\(n\))
- realización muestral
- valores realmente observados (números constantes)
- lo indicaremos mediante minúsculas: \(x_1\), \(x_2\), …, \(x_n\)
- objetivo
- inferir propiedades de la población a partir de una realización muestral
5.2 estimación
5.2.1 puntual
- estimación de la media poblacional \(\mu\) mediante la media muestral \[ \bar X = \frac1n\sum_{i=1}^n\,X_i \]
- estimación de la varianza poblacional \(\sigma^2\) mediante la varianza muestral \(S^2\) o la cuasivarianza \(\hat S^2\) \[ S^2 = \frac1n\sum_{i=1}^n\,(X_i-\bar X)^2 \qquad \hat S^2 = \frac1{n-1}\sum_{i=1}^n\,(X_i-\bar X)^2 \]
- estimación de la proporción poblacional \(p\) mediante la proporción muestral \(\hat p=\bar X\)
5.2.2 por intervalo
- para la media \(\mu\) de una población gausiana \(\mathcal N(\mu;\sigma)\) el pivote sería \[ \frac {\hat X - \mu} {\sigma : \sqrt n} \hookrightarrow \mathcal N(0;1) \] si \(\sigma\) fuera conocida, pero como nunca lo es entonces: \[ \frac {\hat X - \mu} {\hat S : \sqrt n} \hookrightarrow \mathcal t_{n-1} \]
- para la proporción \(p\) de una población binomial \(\mathcal B(1;p)\) el pivote visto
durante el grado es
\[ \frac {\hat p - p} {\sqrt {\hat p\cdot(1-\hat p):n}} \hookrightarrow \mathcal N(0;1)\]
si \(n\) es suficientemente grande, pero la función
prop.test
de R usa una aproximación cuadrática (véase apartado 6.1 del capítulo 3 de Inferencia estadística) que evita por ejemplo que resulten intervalos de confianza fuera del intervalo [0;1]; en cualquier caso, la funciónbinom.test
proporciona una versión exacta;
5.3 docimasia de hipótesis
5.3.1 generalidades
5.3.1.1 hipótesis
- afirmación sobre una distribución de probabilidad
- tipos
- paramétrica
- la media es 107
- las varianzas son iguales en ambos grupos
- no paramétrica
- la distribución es gausiana
- la mediana de las diferencias es negativa
- paramétrica
5.3.1.2 contraste de hipótesis
- es un procedimiento para elegir entre dos hipótesis contrapuestas
- H0
- hipótesis nula
- siempre contiene la «igualdad»
- la media es igual a 100
- la proporción de defectos es menor o igual al 1%
- las varianzas son iguales
- la distribución es gausiana (densidad = campana de Gaus)
- H1
- hipótesis alternativa
- no suele contener la «igualdad» («H1 compuesta»)
- la media es distinta de 100
- la proporción de defectos es mayor que el 1%
- las varianzas son distintas
- la distribución no es gausiana (densidad ≠ campana de Gaus)
hay excepciones («H1 simple»)
- H0: proporción = 10%
- H1: proporción = 15%
- tipos según lateralidad:
- H1: media ≠ 100 → contraste bilateral
- H1: media < 100 → contraste unilateral izquierdo
- H1: media > 100 → contraste unilateral derecho
- son equivalentes las siguientes formas de expresar contrastes unilaterales: \[ \left.\begin{array}{l} H_0:\quad \mu = 100 \\ H_1:\quad \mu < 100 \end{array}\right\} \equiv \left\{\begin{array}{l} H_0:\quad \mu \geq 100 \\ H_1:\quad \mu < 100 \end{array}\right. \] \[ \left.\begin{array}{l} H_0:\quad \mu = 100 \\ H_1:\quad \mu > 100 \end{array}\right\} \equiv \left\{\begin{array}{l} H_0:\quad \mu \leq 100 \\ H_1:\quad \mu > 100 \end{array}\right. \]
5.3.1.3 filosofía (frecuentista o clásica) de resolución
- errores
realidad \ decisión elijo H0 elijo H1 H0 es cierta 👍 error 1 H1 es cierta error 2 👍 - presunción de inocencia
- paradigma jurídico
- H0: inocente
- H1: culpable
- paradigma de control de calidad
- H0: proceso bajo control
- H1: proceso fuera de control
- nemotecnia: en caso de duda, hipótesis nula
- paradigma jurídico
- umbral de elección = nivel de significación = α
- es la probabilidad del error de tipo 1 (probabilidad de condenar a un inocente)
- el más habitual: 5%
- depende mucho del campo de trabajo (control de calidad 3σ ⇒ α = 0,3%)
5.3.1.4 resolución mediante ordenador
- cálculo del nivel crítico o P-valor
- brevemente: es la probabilidad bajo H0 de obtener una muestra más rara que la mía;
- con algo más de rigor: es la probabilidad, suponiendo que H0 es cierta, de obtener una muestra (del mismo tamaño que la que ya tengo) al menos tan rara como la mía;
- por tanto, 0 ≤ P-valor ≤ 1
- P-valor cercano a 0 cuando mi muestra sea muy rara bajo H0, luego no me creo H0;
- P-valor grande cuando mi muestra no es rara bajo H0, luego puedo creerme H0;
- comparar P-valor y nivel de significación
- P-valor ≥ α ⇒ elijo H0
- P-valor < α ⇒ elijo H1
- nemotecnia
- P-valor alto, hipótesis alta (H0)
- P-valor bajo, hipótesis de abajo (H1)
5.3.1.5 potencia
- (bajo H0) tamaño de un contraste
- es la proporción de veces que se elige H1 siendo cierta H0;
- estimable fácilmente mediante simulación:
alfa <- 0.05; n <- 25; mean (replicate (1e5, shapiro.test (rnorm (n)) $ p.value < alfa))
- debería parecerse a α
- bajo H1
- potencia es la probabilidad de elegir H1 siendo cierta H1, es decir, 1 - Pr (error 2);
- suele calcularse en función de un valor concreto dentro de H1
## p = proporción de defectuosos ## H0: p = 10% ## H1: p > 10% ## tamaño del contraste considerando muestras de tamaño 100: mean (replicate (1e5, binom.test (rbinom(1,100,0.1), 100, 0.1, alternative="greater") $ p.value < 0.05)) ## potencia del contraste suponiendo que en realidad p = 20% mean (replicate (1e5, binom.test (rbinom(1,100,0.2), 100, 0.1, alternative="greater") $ p.value < 0.05))
- puede calcularse la función de potencia, en función de los valores que toman los parámetros
bajo H1:
potencia1 <- function (p) mean (replicate (1e5, binom.test (rbinom(1,100,p), 100, 0.1, alternative="greater") $ p.value < 0.05)) potencia <- Vectorize (potencia1) plot (Pd <- seq (0.05, 0.95, 0.05), potencia (Pd), type="l")
- en poblaciones gausianas, un contraste de Wilcoxon es casi tan potente como
un contraste t:
> mean (replicate (1e5, t.test (rnorm(25), mu=0) $ p.value < 0.05)) [1] 0.05036 > mean (replicate (1e5, wilcox.test (rnorm(25), mu=0) $ p.value < 0.05)) [1] 0.0496 > mean (replicate (1e5, t.test (rnorm(25), mu=0.5) $ p.value < 0.05)) [1] 0.66888 > mean (replicate (1e5, wilcox.test (rnorm(25), mu=0.5) $ p.value < 0.05)) [1] 0.64707
- en poblaciones no gausianas y con tamaño de muestra pequeño,
el contraste t es conservador: su tamaño es menor que el nivel de significación;
> mean (replicate (100000, t.test (rexp(15), rexp(15)) $ p.value < 0.05)) ; gc() [1] 0.04267 > mean (replicate (100000, wilcox.test (rexp(15), rexp(15)) $ p.value < 0.05)) [1] 0.0455
el de Wilcoxon se acerca algo más al tamaño óptimo (5%)
5.3.2 situaciones
5.3.2.1 preliminares: calidad de la muestra y estructura de la población
- constraste de independencia
- rachas
- secuencia de valores iguales
- calculables en R mediante «rle»
- para variables continuas, tomar la mediana como referencia: «rle (m > median(m))»
- número de rachas
- implementación sencilla
numrachas <- function (m, FUN = function (m) length (rle (m > median(m)) $ lengths), B = 9999) { Pder <- 1/(B+1) + mean (replicate (B, FUN (sample (m))) >= FUN (m)) Pizq <- 1/(B+1) + mean (replicate (B, FUN (sample (m))) <= FUN (m)) 2 * min (Pder, Pizq) } ## ejemplo > numrachas (mtcars$mpg, B=99999) [1] 0.04646046
- «runs.test» en «snpar» o «tseries»
library (snpar) > runs.test(mtcars$mpg) Approximate runs rest data: mtcars$mpg Runs = 11, p-value = 0.03215 alternative hypothesis: two.sided > ?runs.test > runs.test(mtcars$mpg,exact=TRUE) Exact runs test data: mtcars$mpg Runs = 11, p-value = 0.04741 alternative hypothesis: two.sided
- implementación sencilla
- racha más larga
rachamaslarga <- function (...) numrachas (FUN = function (m) max (rle (m > median(m)) $ lengths), ...) ## ejemplo (es menos potente que el número de rachas) > rachamaslarga(mtcars$mpg,B=99999) [1] 0.09080091
- rachas
- contraste de gausianidad
- «shapiro.test»
5.3.2.2 poblaciones continuas
- una muestra
- contraste de media
- «t.test»
- contraste de mediana (prueba de signos)
- «binom.test» ó «prop.test»
binom.test (sum (M > mediana0), sum(M == mediana0), .5, alternative=...) prop.test (sum (M > mediana0), sum(M == mediana0), .5, alternative=...)
- BSDA::SIGN.test (muestra, md=mediana0, alternative=…)
- «binom.test» ó «prop.test»
- contraste de media
- dos muestras
- muestras independientes
- «t.test» (con gausianidad o muestras grandes)
- «wilcox.test» (algo menos potente, pero válido siempre)
- permutas:
- implementación sencilla
permutas <- function (grupo1, grupo2, FUN = function (m1, m2) abs (mean(m1,na.rm=TRUE)-mean(m2,na.rm=TRUE)), B = 9999) 1/(B+1) + mean (replicate (B, {todos <- sample (c (grupo1, grupo2)) g1 <- todos [1 : length(grupo1)] g2 <- todos [(length(grupo1) + 1) : length(todos)] FUN (g1, g2)}) >= FUN (grupo1, grupo2)) ## ejemplo > permutas (mtcars$mpg[mtcars$am==0], mtcars$mpg[mtcars$am==1], B=999999) [1] 0.0002720003
- paquete «perm»
> permTS(mpg~am,mtcars,method="exact.mc",control=permControl(nmc=999999,tsmethod="abs"))$p.value [1] 0.000268 > permTS(mpg~am,mtcars,method="exact.mc",control=permControl(nmc=999999))$p.value [1] 0.000392
- tsmethod = two-side method = método para calcular P-valor bilateral
- por omisión, P-valor = 2.mín{Pizq,Pder}
- método "abs" es el de la implementación sencilla de arriba
- para más detalles, consultar «?permControl» o aquí
- paquete coin:
> library (coin) > independence_test(mpg~am,mtcars) Asymptotic General Independence Test data: mpg by am Z = 3.3397, p-value = 0.0008386 alternative hypothesis: two.sided
- es el paquete que recomiendan y que sigue en desarrollo
- implementación compleja, en C
- implementación sencilla
- muestras pareadas
- muestras pareadas, pero observaciones independientes entre sí
- equivalen a comparar una muestra (de las diferencias) respecto al cero
- «t.test (…, paired=TRUE)»
- «wilcox.test (…, paired=TRUE)»
- muestras independientes
- varias muestras
- independientes
- análisis de varianza unifactorial: «aov (respuesta ~ grupo, …)»
library (car) # para Chile t.test (statusquo ~ sex, Chile) ## equivale a t.test si el factor tiene sólo dos niveles: summary (aov (statusquo ~ sex, Chile)) ## compara medias entre más de dos grupos: summary (aov (statusquo ~ vote, Chile))
- la versión no paramétrica es el «kruskal.test»:
kruskal.test (statusquo ~ vote, Chile)
- análisis de varianza unifactorial: «aov (respuesta ~ grupo, …)»
- relacionadas
- series temporales
- independientes
5.3.2.3 proporciones
- una muestra
- exacto: «binom.test»
> binom.test (4, 100, 0.01) Exact binomial test data: 4 and 100 number of successes = 4, number of trials = 100, p-value = 0.01837 alternative hypothesis: true probability of success is not equal to 0.01 95 percent confidence interval: 0.01100449 0.09925716 sample estimates: probability of success 0.04
- aproximado:
- «prop.test»
> prop.test (4, 100, 0.01) 1-sample proportions test with continuity correction data: 4 out of 100, null probability 0.01 X-squared = 6.3131, df = 1, p-value = 0.01198 alternative hypothesis: true p is not equal to 0.01 95 percent confidence interval: 0.01289087 0.10511152 sample estimates: p 0.04 Warning message: In prop.test(4, 100, 0.01) : Chi-squared approximation may be incorrect > prop.test (4, 100, 0.01, correct=FALSE) 1-sample proportions test without continuity correction data: 4 out of 100, null probability 0.01 X-squared = 9.0909, df = 1, p-value = 0.002569 alternative hypothesis: true p is not equal to 0.01 95 percent confidence interval: 0.01566330 0.09837071 sample estimates: p 0.04 Warning message: In prop.test(4, 100, 0.01, correct = FALSE) : Chi-squared approximation may be incorrect
- «chisq.test»
> chisq.test (c(4,96), p=c(0.01,0.99)) Chi-squared test for given probabilities data: c(4, 96) X-squared = 9.0909, df = 1, p-value = 0.002569 Warning message: In chisq.test(c(4, 96), p = c(0.01, 0.99)) : Chi-squared approximation may be incorrect
- «prop.test»
- exacto: «binom.test»
- dos muestras
- prop.test chisq.test
> prop.test (c(10,20), c(100,100)) 2-sample test for equality of proportions with continuity correction data: c(10, 20) out of c(100, 100) X-squared = 3.1765, df = 1, p-value = 0.07471 alternative hypothesis: two.sided 95 percent confidence interval: -0.207998199 0.007998199 sample estimates: prop 1 prop 2 0.1 0.2 > chisq.test (matrix (c(10,20,90,80), 2)) Pearson's Chi-squared test with Yates' continuity correction data: matrix(c(10, 20, 90, 80), 2) X-squared = 3.1765, df = 1, p-value = 0.07471
- prop.test chisq.test
- varias muestras
- chisq.test
> matrix (c(10,20,10,5,10,90,80,85,90,90), ncol=2) [,1] [,2] [1,] 10 90 [2,] 20 80 [3,] 10 85 [4,] 5 90 [5,] 10 90 > chisq.test (matrix (c(10,20,10,5,10,90,80,85,90,90), ncol=2)) Pearson's Chi-squared test data: matrix(c(10, 20, 10, 5, 10, 90, 80, 85, 90, 90), ncol = 2) X-squared = 11.464, df = 4, p-value = 0.02182 > chisq.test (matrix (c(10,20,10,5,10,90,80,85,90,90), ncol=2), simulate.p.value=TRUE, B=999999) Pearson's Chi-squared test with simulated p-value (based on 999999 replicates) data: matrix(c(10, 20, 10, 5, 10, 90, 80, 85, 90, 90), ncol = 2) X-squared = 11.464, df = NA, p-value = 0.02119
- chisq.test
6 modelos lineales
6.1 regresión simple
- predecir Y a partir de X: \(Y = \beta_0 + \beta_1\,X + \epsilon\)
- los \(\beta\) se estiman a partir de los datos \(x_i,y_i\), \(i=1,...,n\) minimizando los residuos \(e_i\): \[\sum_{i=1}^n e_i^2 = \sum \left(y_i - \beta_0-\beta_1\,x_i \right)^2 \]
- la calidad predictiva suele expresarse mediante el coeficiente de determinación \[ R^2 = \frac {\mbox{variación de Y explicada por el modelo}} {\mbox{variación total de Y}} \]
- para construir un modelo, elegir la variable más relacionada con la respuesta
> sort (cor (mtcars) [,1] ^ 2) qsec gear carb am vs drat hp disp 0.1752963 0.2306734 0.3035184 0.3597989 0.4409477 0.4639952 0.6024373 0.7183433 cyl wt mpg 0.7261800 0.7528328 1.0000000 > summary (lm (mpg ~ wt, mtcars)) Call: lm(formula = mpg ~ wt, data = mtcars) Residuals: Min 1Q Median 3Q Max -4.5432 -2.3647 -0.1252 1.4096 6.8727 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 37.2851 1.8776 19.858 < 2e-16 *** wt -5.3445 0.5591 -9.559 1.29e-10 *** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 3.046 on 30 degrees of freedom Multiple R-squared: 0.7528,Adjusted R-squared: 0.7446 F-statistic: 91.38 on 1 and 30 DF, p-value: 1.294e-10
- predecir con intervalo de confianza:
> predict (modelo, data.frame (wt = 5), interval="confidence", level=0.99) fit lwr upr 1 10.56277 7.447369 13.67817 > predict (modelo, data.frame (wt = 5), interval="confidence", level=0.95) fit lwr upr 1 10.56277 8.24913 12.87641 > abscisas <- data.frame (wt = seq (min(mtcars$wt), max(mtcars$wt), length.out=100)) > p <- predict (modelo, abscisas, interval="prediction") > head (p) fit lwr upr 1 29.19894 22.58903 35.80885 2 28.98781 22.39104 35.58458 3 28.77667 22.19276 35.36059 4 28.56554 21.99420 35.13688 5 28.35441 21.79535 34.91346 6 28.14327 21.59621 34.69033 > plot (mpg ~ wt, mtcars) > abline (modelo <- lm (mpg ~ wt, mtcars), col = 2) > lines (abscisas$wt, p[,"lwr"], col=3) > lines (abscisas$wt, p[,"upr"], col=3)
- diagnosis
- ¿se ajusta la nube de puntos a la recta?: diagrama de dispersión
plot (X, Y)
- residuos
plot (lm (Y ~ X))
- deben no presentar estructura
- el gráfico QQ (cuantil - cuantil) muestra su gausianidad
- ¿se ajusta la nube de puntos a la recta?: diagrama de dispersión
6.2 regresión no lineal
- lenguaje de modelos de R: capítulo 11 de Una introducción a R
- trasformación a regresión lineal
plot (1/mpg ~ wt, mtcars) lm (1/mpg ~ wt, mtcars) -> modelo summary (modelo) abline (modelo, col = 2) abscisas <- data.frame (wt = seq (min(mtcars$wt), max(mtcars$wt), length.out=100)) p <- predict (modelo, abscisas, interval="prediction") lines (abscisas$wt, p[,"lwr"], col=3) lines (abscisas$wt, p[,"upr"], col=3)
probar también
mpg ~ log(wt)
- para expresiones más complejas puede usarse «nls»
> x <- -(1:100)/10 > y <- 100 + 10 * exp(x / 2) + rnorm(x)/10 > nlmod <- nls(y ~ Const + A * exp(B * x)) Warning message: In nls(y ~ Const + A * exp(B * x)) : No starting values specified for some parameters. Initializing ‘Const’, ‘A’, ‘B’ to '1.'. Consider specifying 'start' or using a selfStart model > nlmod Nonlinear regression model model: y ~ Const + A * exp(B * x) data: parent.frame() Const A B 99.9807 10.0175 0.4964 residual sum-of-squares: 0.8255 Number of iterations to convergence: 10 Achieved convergence tolerance: 2.925e-07
6.3 regresión múltiple
- lenguaje de modelos de R: capítulo 11 de Una introducción a R
- una variable y trasformaciones suyas
> modelo2 <- lm (mpg ~ wt + I(wt^2), mtcars) > summary (modelo2) Call: lm(formula = mpg ~ wt + I(wt^2), data = mtcars) Residuals: Min 1Q Median 3Q Max -3.483 -1.998 -0.773 1.462 6.238 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 49.9308 4.2113 11.856 1.21e-12 *** wt -13.3803 2.5140 -5.322 1.04e-05 *** I(wt^2) 1.1711 0.3594 3.258 0.00286 ** --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 2.651 on 29 degrees of freedom Multiple R-squared: 0.8191,Adjusted R-squared: 0.8066 F-statistic: 65.64 on 2 and 29 DF, p-value: 1.715e-11 > abscisas <- data.frame (wt = seq (min(mtcars$wt), max(mtcars$wt), length.out=100)) > p <- predict (modelo2, abscisas, interval="prediction") > plot (mpg ~ wt, mtcars) > lines (abscisas$wt, p[,"fit"], col=2) > lines (abscisas$wt, p[,"lwr"], col=3) > lines (abscisas$wt, p[,"upr"], col=3)
- varias variables
> summary (lm (mpg ~ ., mtcars)) # «.» significa «el resto de columnas» Call: lm(formula = mpg ~ ., data = mtcars) Residuals: Min 1Q Median 3Q Max -3.4506 -1.6044 -0.1196 1.2193 4.6271 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 12.30337 18.71788 0.657 0.5181 cyl -0.11144 1.04502 -0.107 0.9161 disp 0.01334 0.01786 0.747 0.4635 hp -0.02148 0.02177 -0.987 0.3350 drat 0.78711 1.63537 0.481 0.6353 wt -3.71530 1.89441 -1.961 0.0633 . qsec 0.82104 0.73084 1.123 0.2739 vs 0.31776 2.10451 0.151 0.8814 am 2.52023 2.05665 1.225 0.2340 gear 0.65541 1.49326 0.439 0.6652 carb -0.19942 0.82875 -0.241 0.8122 --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 2.65 on 21 degrees of freedom Multiple R-squared: 0.869,Adjusted R-squared: 0.8066 F-statistic: 13.93 on 10 and 21 DF, p-value: 3.793e-07 > step (lm (mpg ~ ., mtcars)) -> mejor.modelo > summary (mejor.modelo) Call: lm(formula = mpg ~ wt + qsec + am, data = mtcars) Residuals: Min 1Q Median 3Q Max -3.4811 -1.5555 -0.7257 1.4110 4.6610 Coefficients: Estimate Std. Error t value Pr(>|t|) (Intercept) 9.6178 6.9596 1.382 0.177915 wt -3.9165 0.7112 -5.507 6.95e-06 *** qsec 1.2259 0.2887 4.247 0.000216 *** am 2.9358 1.4109 2.081 0.046716 * --- Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1 Residual standard error: 2.459 on 28 degrees of freedom Multiple R-squared: 0.8497,Adjusted R-squared: 0.8336 F-statistic: 52.75 on 3 and 28 DF, p-value: 1.21e-11
- EJERCICIO
- Aplicar «step» al modelo «lm (mpg ~ wt + I(wt2), mtcars)» para obtener un modelo nuevo.
- Comparar gráficamente predicciones e intervalos de ambos modelos.
6.4 análisis de varianza de efectos fijos
6.4.1 unifactorial
Libro (libre) de inferencia de la Universidad de Cádiz
- análisis de varianza unifactorial: «aov (respuesta ~ grupo, …)»
library (car) # para Chile summary (aov (statusquo ~ vote, Chile))
- modelo
- variable respuesta \(X\)
- factor \(A\) con \(I\) niveles indexados por \(i=1,...,I\)
- \(X_i = \mu_i+\epsilon_i = \mu + a_i + \epsilon_i\)
- \(\epsilon_i \hookrightarrow N(0;\sigma)\)
Nivel | Observaciones | Total | Media muestral | Media poblacional |
---|---|---|---|---|
1 | \(\begin{array}{cccc}x_{11} & x_{12} & \ldots & x_{1n_{1}} \\\end{array}\) | \(x_{1\cdot}\) | \(\bar{x}_1\) | \(\mu_{1}\) |
2 | \(\begin{array}{cccc}x_{21}&x_{22}&\ldots &x_{2n_{2}}\\\end{array}\) | \(x_{2\cdot}\) | \(\bar{x}_2\) | \(\mu_{2}\) |
\(\vdots\) | \(\begin{array}{llcr}\vdots &\vdots & &\vdots \\\end{array}\) | \(\vdots\) | \(\vdots\) | \(\vdots\) |
I | \(\begin{array}{cccc}x_{I1}&x_{I2}&\ldots &x_{In_{I}}\\\end{array}\) | \(x_{I\cdot}\) | \(\bar{x}_I\) | \(\mu_{I}\) |
Valores globales | \(x_{\cdot\cdot}\) | \(\bar{x}_{..}\) | \(\mu\) |
- contraste
- \( H_0: \quad \mu_1=\mu_2=...=\mu_I \quad\equiv\quad \forall\,i,\,\mu_i=\mu\quad\equiv\quad \forall\,i,\,a_i=0 \)
- \( H_1: \quad \exists\,i,j,\, \mu_i\not=\mu_j\quad \equiv\quad \exists\,i,\, a_i\not=0\)
- descomposición de la variabilidad \[x_{ij}=\mu+a_{i}+\varepsilon_{ij}\] \[x_{ij}=\bar{x}_{\cdot\cdot}+(\bar{x}_{i\cdot}-\bar{x}_{\cdot\cdot})+(x_{ij}-\bar{x}_{i\cdot})\] \[(x_{ij}-\bar{x}_{\cdot\cdot})=(\bar{x}_{i\cdot}-\bar{x}_{\cdot\cdot})+(x_{ij}-\bar{x}_{i\cdot})\] \[\sum_{i=1}^k\sum_{j=1}^{n_{i}}(x_{ij}-\bar{x}_{\cdot\cdot})^2= \sum_{i=1}^k\sum_{j=1}^{n_{i}}[(\bar{x}_{i\cdot}-\bar{x}_{\cdot\cdot}) +(x_{ij}-\bar{x}_{i\cdot})]^2\] \[\underbrace{\sum_{i=1}^k\sum_{j=1}^{n_{i}}(x_{ij}-\bar{x}_{\cdot\cdot})^2}_{SC{T}}= \underbrace{\sum_{i=1}^k n_{i}(\bar{x}_{i\cdot}-\bar{x}_{\cdot\cdot})^2}_{SC{A}}+ \underbrace{\sum_{i=1}^k\sum_{j=1}^{n_{i}}(x_{ij}-\bar{x}_{i\cdot})^2}_{SC{E}} \]
- en R
summary (aov (Speed ~ Expt, morley)) # ¡ojo a los grados de libertad! summary (aov (Speed ~ factor(Expt), morley)) summary (lm (Speed ~ factor(Expt), morley)) # equivalente
6.4.2 bifactorial
- modelo
- variable respuesta \(X\)
- factor \(A\) con \(I\) niveles indexados por \(i=1,...,I\)
- factor \(B\) con \(J\) niveles indexados por \(j=1,...,J\)
- \(X_i = \mu + a_i + b_j+\epsilon_{ij}\)
- \(X_i = \mu + a_i + b_j+ (ab)_{ij} + \epsilon_{ij}\) (con interacción)
- \(\epsilon_{ij} \hookrightarrow N(0;\sigma)\)
- lenguaje de modelos de R: capítulo 11 de Una introducción a R
summary (sin <- aov (yield ~ N+P, npk)) # sin interacción summary (con <- aov (yield ~ N*P, npk)) # con interacción summary (aov (yield ~ N+P+N:P, npk)) # ídem anova (sin, con) # contraste para comparar
6.4.3 multifactorial
- puede haber interacciones entre tres o más factores
summary (aov (statusquo ~ region + sex + education, Chile)) summary (lm (statusquo ~ region + sex + education, Chile)) summary (aov (yield ~ N*P*K*block, npk)) # sin grados de libertad suficientes summary (aov (yield ~ N*P*K+block, npk)) # el bloque se supone sin interacción summary (aov (yield ~ N+K+block, npk)) summary (lm (yield ~ N+K+block, npk)) # ver diferencias entre bloques