Contenidos de «Complementos de Estadística»

Índice

1 R y Python

1.1 Instalación

1.1.1 R

1.1.1.1 ReactOS y Windows
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

1.2.3 Guardar datos

(Lo mismo en R, Python.)

  • 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.
  • 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 fichero mtcars.rda y a un fichero mtcars.csv.

1.2.4 Descriptivos

(Lo mismo en R, Python)

  • 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.

1.2.5 Modificar datos

(Lo mismo en R, Python.)

  • 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 llamado Chile.f que contenga los registros tales que sex sea F y tales que age sea menor que 50.
    • Hacer un diagrama de barras de la variable education con el orden correcto.

1.2.6 Distribuciones de probabilidad

(Lo mismo en R, Python.)

  • 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 valores (probabilidad 30%) y no (probabilidad 70%).

1.2.7 Contrastes de hipótesis sobre medias, proporciones…

(Lo mismo en R, Python.)

  • 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?

1.2.8 Contrastes de hipótesis sobre independencia

(Lo mismo en R, Python.)

  • Contraste \(\chi^2\) (ji cuadrado)
    • Estadísticos: Tablas de contingencia: Tabla de doble entrada
  • Contraste de correlación lineal de Pearson
    • Estadísticos: Resúmenes: Test de correlación
  • Ejercicio:
    • ¿Qué relaciones hay en las parejas de variables de mtcars?

1.2.9 Regresión lineal

(Lo mismo en R, Python.)

  • 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.

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
  1. especiales
    1. R
      • NULL
      • NA not available
      • NaN not a number
    2. Python
      • None
      • import numpy as np; np.nan
  2. lógicos (booleanos)
    1. R
      • TRUE y FALSE
      • 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
        
    2. Python
      • True y False
      • 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
  3. numéricos
    1. R
      • enteros: 58 o bien 58L
      • coma deslizante: 102.23
      • notación exponencial: 1e-6
      • complejos: 5+3i (comparar sqrt(-1) y sqrt(-1+0i))
    2. Python
      • enteros: 58 o bien 58L
      • coma deslizante: 102.23
      • notación exponencial: 1e-6
      • complejos: 5+3j (comparar math.sqrt(-1) y cmath.sqrt(-1))
  4. caracteres
    1. 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
        
    2. 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»
1.3.2.2 compuestos
  1. vectores
    1. 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 usar which)
        • 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)
          
      • 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
        
    2. 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 (el nan produce False)
        • 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)
      
  2. matrices
    1. 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
    2. 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)
  3. listas
    1. 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]
        
    2. 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 de pandas:

      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"]
        
  4. dataframes
    1. 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
    2. 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

  5. factores o categóricas
    1. R
      • implementan variables cualitativas:
        sexo <- c("M","M","H","H","H","M")
        sexo.f <- factor (sexo)
        levels (sexo.f)
        
      • factor genera un factor
        s = 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 sobrantes
        f1 = 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"))
        
    2. 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

  6. fechas y horas
    1. 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 o C) 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 de strptime.

    2. 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.

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 (con s 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 (con l de lista) devuelve una lista
      lapply (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 dataframe
    m <- 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
  1. 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)
      
  2. 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)
      
  3. 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)
          
1.4.1.2 Python
  1. De ejemplo (incluidon en python-sklearn)
    from sklearn import datasets
    iris = datasets.load_iris()
    
  2. 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")
    
  3. En formatos ajenos

    (Lo mismo en R.)

    • Importar Pandas
      import pandas as pd
      
    • Para datos de texto (CSV) hay read_csv() (comas) y read_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)
          
    • 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
      

1.4.2 Guardar datos

1.4.2.1 R

(Lo mismo en Rcmdr, Python.)

  • 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

(Lo mismo en R, Rcmdr.)

  • 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

(Lo mismo en Rcmdr, Python.)

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

(Lo mismo en R, Rcmdr.)

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

(Lo mismo en Python, Rcmdr.)

  • 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

(Lo mismo en R, Rcmdr.)

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

(Lo mismo en Python, Rcmdr.)

  • letra inicial
    • r para generar aleatorios
    • p 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 uniforme
    • norm gausiana
    • exp exponencial
    • binom binomial
    • pois puasón
    • t 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

(Lo mismo en R, Rcmdr.)

  • métodos
    • rvs para generar aleatorios
    • cdf 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, mediana
    • ppf función cuantil (percent point function)
  • distribuciones
    • uniform uniforme
    • norm gausiana
    • expon exponencial
    • binom binomial
    • pois puasón
    • t 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

(Lo mismo en Python, Rcmdr.)

?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
      
1.4.6.2 Python

(Lo mismo en R, Rcmdr.)

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

(Lo mismo en Python, Rcmdr.)

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

(Lo mismo en R, Rcmdr.)

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

(Lo mismo en Python, Rcmdr.)

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

(Lo mismo en R, Rcmdr.)

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.
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
  1. PuTTY
  2. trasferir ficheros
  3. abrir ventanas gráficas remotas localmente
    • Xming
      • instalar y ejecutar Xming (enlace directo)
      • en PuTTY, activar Connection: SSH: X11: Enable X11 forwarding
    • Cygwin
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

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ón

    http://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 (&registro, &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

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 y dnorm)
      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\)

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

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 de x; \(p_m\) es cada elemento de p; \(H = J = \frac{K-1}2\) si \(K\) es impar y el filtro es simétrico

  • 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))
      

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.5.2 runmed

  • implementación en C para R una mediana móvil

EJERCICIO

  • comparar con tu implementación en R

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)
  • 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 datos
  • y 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 entrada
  • y es la salida
  • alpha es \(\alpha\), el parámetro del núcleo
  • endtype indica qué hacer en los extremos (principio y fin) de la señal
  • order 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

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
  • 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

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ón binom.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
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
  • 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
        
    • 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
      
  • contraste de gausianidad
    • «shapiro.test»
5.3.2.2 poblaciones continuas
  1. 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=…)
  2. dos muestras
    1. 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
    2. 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)»
  3. varias muestras
    1. 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)
        
    2. relacionadas
      • series temporales
5.3.2.3 proporciones
  1. 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
        
  2. 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
      
  3. 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
      

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)
    

regre1.png

  • 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

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
    

Autor: Carleos Artime

Created: 2019-02-20 mié 14:57

Emacs 25.1.1 (Org mode 8.2.10)

Validate