La estadística descriptiva tiene más que ver con describir una muestra de manera cualitativa (gráfica) o cuantitativa (numérica) que con inferir propiedades acerca de la población de la cual proviene esa muestra (estadística inferencial).

La estadística descriptiva está fuertemente ligada al análisis exploratorio de datos (EDA for Exploratory Data Analysis) y al análisis inicial de datos (IDA por Initial Data Analysis). El primero focaliza en explorar los datos en busca de nuevas hipótesis, las cuales pueden terminar en nuevos muestreos y experimentos, mientras el segundo se focaliza en asegurar la calidad de los datos, chequear las asunciones y realizar las transformaciones necesarias para testear la hipótesis que teníamos en mente a la hora de recolectar los datos.

El análisis inicial de datos no es necesario solamente para el testeo de hipótesis de la estadística inferencial, sino también como un paso previo para el aprendizaje automático (ML por Machine Learning) y forma parte importante de las primeras fases de la minería de datos (Data mining).

Muestra estadística

Se denomina muestra a un subconjunto de datos tomados o seleccionados de una población estadística mediante un proceso de muestreo determinado. Cada una de las unidades muestrales suele llamarse observación, y es posible medir variables aleatorias para cada una de ellas.

Las muestras pueden ser:

  • Completas: Incluye a todos los casos, individuos u objetos de la población que cumplen con un criterio (de selección) determinado. Generalmente es difícil o imposible disponer de muestras completas.
  • Representativas (representative or unbiased): Un conjunto de unidades muestrales seleccionados de una muestra completa usando un proceso de selección/muestreo que no depende de las propiedades de estas unidades. Una manera de obtener muestras no sesgadas es seleccionando una muestra aleatoria (random/probability sample).

Técnicas de muestreo

Muestreo aleatorio simple

En el muestreo aleatorio simple se selecciona un número k de unidades muestrales de manera aleatoria, teniendo cada elemento de la población la misma probabilidad de ser seleccionado. El muestreo puede ser con o sin reposición (with or without replacement). Si el muestreo se efectúa con reposición, cada elemento de la población puede ser seleccionado más de una vez. En el muestreo aleatorio sin reposición, donde los elementos no son devueltos a la población y no pueden ser elegidos más de una vez, la probabilidad de sacar un determinado elemento cambia con la extracción del anterior (no son independientes). Sin embargo el muestreo aleatorio simple sin reposición satisface intercambiabilidad, es que cualquier orden de los elementos extraídos es igualmente probable. Si el tamaño de la población es mucho más grande que el tamaño de la muestra, el muestreo aleatorio simple sin reposición se aproxima a un muestreo simple con reposición, dada la baja probabilidad de elegir un mismo elemento dos veces.

La manera más sencilla de hacer un muestreo aleatorio simple con o sin reposición en Julia, es usando la función sample de StatsBase. Ésta es similar a la función sample de R. Ambas toman una lista de valores, el tamaño de la muestra a tomar (size) y se les debe indicar si queremos que sea con o sin reemplazo o reposición (replace). Una diferencia entre ambas funciones es que mientras R por defecto hace el muestreo sin reemplazo, Julia lo hace con reemplazo si no le indicamos lo contrario.


In [1]:
individuos = 1:10


Out[1]:
1:10

In [2]:
using StatsBase

sample(individuos, 5, replace=true)


Out[2]:
5-element Array{Int64,1}:
  4
  7
  9
  6
 10

In [3]:
using RCall

R"sample($individuos, size=5, replace=TRUE)"


Out[3]:
RCall.RObject{RCall.IntSxp}
[1] 5 5 2 6 8
Muestreo sistemático

El muestreo sistemático consiste en ordenar los elementos de una población según alguna variable de interés, para luego tomar n unidades muestrales equiespaciadas. El primer elemento debe ser seleccionado al azar, quedando los otros determinados en relación a este. Una ventaja de este tipo de muestreo es que permite muestrear una variable de intereses en todo su rango. Pero debe tenerse cuidado si la variable muestra alguna característica periódica, dado que puede generarse una muestra sesgada de la población. Además debe tenerse en cuenta que no se verá la variación entre dos elementos contiguos en la lista, dado que nunca son seleccionados a la vez.

Por ejemplo, si queremos hacer un muestreo sistemático de las plantas del conjunto de datos iris según largo de sus pétalos:


In [5]:
using RDatasets
iris = dataset("datasets","iris")
head(iris)


Out[5]:
SepalLengthSepalWidthPetalLengthPetalWidthSpecies
15.13.51.40.2setosa
24.93.01.40.2setosa
34.73.21.30.2setosa
44.63.11.50.2setosa
55.03.61.40.2setosa
65.43.91.70.4setosa

In [6]:
sort!(iris, cols=:PetalLength) # Ordena la variable de interés
head(iris)


Out[6]:
SepalLengthSepalWidthPetalLengthPetalWidthSpecies
14.63.61.00.2setosa
24.33.01.10.1setosa
35.84.01.20.2setosa
45.03.21.20.2setosa
54.73.21.30.2setosa
65.43.91.30.4setosa

In [7]:
N = nrow(iris) # Número de elementos en mi población


Out[7]:
150

In [8]:
n = 7 # Número de muestras


Out[8]:
7

In [9]:
@assert n != 0 "El tamaño de la muestra no puede ser 0"

@assert n <= N "La muestra no puede ser superior en tamaño a la población"

k = div(N,n) # Intervalo de muestreo (sampling interval or skip)


Out[9]:
21

In [10]:
primero = sample(1:k) # Elijo al azar (con igual probabilidad) un elemento de 1 a k para comenzar


Out[10]:
8

In [15]:
# Selecciono los elementos restante a k pasos del primero
índices = Int[ primero + ((muestra-1) * k) for muestra in 1:n ]


Out[15]:
7-element Array{Int64,1}:
   8
  29
  50
  71
  92
 113
 134

In [16]:
iris[índices,:]


Out[16]:
SepalLengthSepalWidthPetalLengthPetalWidthSpecies
14.43.01.30.2setosa
25.74.41.50.4setosa
35.13.81.90.4setosa
45.62.74.21.3versicolor
56.33.34.71.6versicolor
66.32.85.11.5virginica
76.73.35.72.5virginica
Muestreo estratificado

En el muestreo estratificado, se estratifica la población antes de tomar las muestras. En este proceso se divide a los miembros de la población en estratos, grupos o subpoblaciones homogéneas. Estos estratos deben ser mutuamente excluyentes, dado que un miembro de la población no podrá pertenecer a más de una subpoblación. Todos los miembros de la población deben pertenecer a un estrato determinado, no pueden quedar miembros sin clasificar (estratificación exhaustiva). Una vez que se estratifico la población, se realizar un muestreo aleatorio simple o sistemático dentro de cada estrato.

Existen tres posibles estrategias:

  • Asignación proporcional: El número de unidades muestrales de cada estrato es proporcional al número de individuos del estrato dentro de la población. Es decir, se respeta las proporciones de los estratos en la población.
  • Asignación óptima: El número de muestras seleccionadas para cada estrato es proporcional a la desviación estándar de la variable de interés en cada estrato. Ésto requiere un conocimiento previo de la población.
  • Asignación uniforme: Se selecciona un igual número de elementos para cada estrato. Ésto permite, cuando el tamaño de los estratos varía en la población, equiparar el poder de los test utilizados en cada estratos a la hora de compararlos. El conjunto de datos iris fue generado en un muestreo estratificado uniforme (50 flores de cada especie), en el que cada especie conforma un estrato.
Media
$$ \mu_{s} = \frac{1}{N} \sum_{h=1}^{L} N_{h} \mu_{h} $$

Por ejemplo, si consideramos que todas las filas del conjunto de datos iris es nuestra población:


In [17]:
μₛ = mean(iris[:PetalLength])


Out[17]:
3.7580000000000005

In [20]:
estratos = by(iris, :Species) do df 
    DataFrame(
        μₕ = mean(df[:PetalLength]),
        Nₕ = nrow(df)
    )
end


Out[20]:
SpeciesμₕNₕ
1setosa1.46250
2versicolor4.2650
3virginica5.55250

In [21]:
N = nrow(iris)


Out[21]:
150

In [22]:
(1/N) * sum(estratos[:μₕ] .* estratos[:Nₕ])


Out[22]:
3.7580000000000005

Estadísticos de resumen

Los estadísticos de resumen (Summary statistics) describen de manera cuantitativa la distribución de una muestra. Normalmente se obtiene un conjunto de estadísticos que describen cada variable aleatoria/dimensión de los datos de manera independiente (si excluimos medidas de dependencia como las correlaciones).

Existen estadísticos de:

  • tendencia central (location or central tendency)
  • dispersión (spread or dispersion)
  • forma (shape):
    • asimetría (Skewness)
    • apuntamiento (Kurtosis)

Estos estadísticos pueden ser robustos o no, llamándose robustos a los estadísticos menos afectados por valores atípicos (outliers). Estos estadísticos describen la muestra de una manera más robusta cuando su distribución se aleja de una distribución normal (por ejemplo, si la distribución es asimétrica).

Estadísticos de tendencia central

Existen diversos estadísticos de tendencia central, siendo la media el más popular de ellos a pesar de no ser un estadístico robusto. La medidas de ubicación robusta más popular es la mediana. La moda es el único estadístico de tendencia central para datos nominales, pero es difícil de estimar correctamente para variables continuos.


In [23]:
for (nombre, valores) in eachcol(iris)
    println(nombre)
    
    if eltype(valores) <: Real
        println("  Media   : ", mean(valores))
        println("  Mediana : ", median(valores))
        println("  Moda    : ", mode(valores))
    else
        println("  Moda    : ", mode(valores))
    end 
    
end


SepalLength
  Media   : 5.843333333333334
  Mediana : 5.8
  Moda    : 5.0
SepalWidth
  Media   : 3.0573333333333332
  Mediana : 3.0
  Moda    : 3.0
PetalLength
  Media   : 3.7580000000000005
  Mediana : 4.35
  Moda    : 1.4
PetalWidth
  Media   : 1.1993333333333331
  Mediana : 1.3
  Moda    : 0.2
Species
  Moda    : setosa

Estadísticos de dispersión

De los estadísticos de dispersión, la desviación estándar es el más popular acompañando a la media. No debe confundirse con el error estadístico o estándar, que en realidad habla de la dispersión de las medias muestrales, y no de la variable de interés. La desviación estándar no es un estimador robusto. Alternativas más robustas son el rango entre cuartiles y la Median Absolute Deviation (MAD).


In [24]:
for (nombre, valores) in eachcol(iris)
    if eltype(valores) <: Real
        
        println(nombre)
        
        println("  Varianza                  : ", var(valores))
        println("  Desviación estándar       : ", std(valores))
        println("  Rango intercuartílico     : ", iqr(valores))
        println("  Median Absolute Deviation : ", mad(valores))
        
    end
end


SepalLength
  Varianza                  : 0.6856935123042507
  Desviación estándar       : 0.828066127977863
  Rango intercuartílico     : 1.3000000000000007
  Median Absolute Deviation : 1.0378215529539214
SepalWidth
  Varianza                  : 0.18997941834451898
  Desviación estándar       : 0.4358662849366982
  Rango intercuartílico     : 0.5
  Median Absolute Deviation : 0.4447806655516803
PetalLength
  Varianza                  : 3.116277852348993
  Desviación estándar       : 1.7652982332594662
  Rango intercuartílico     : 3.4999999999999996
  Median Absolute Deviation : 1.8532527731320023
PetalWidth
  Varianza                  : 0.5810062639821029
  Desviación estándar       : 0.7622376689603465
  Rango intercuartílico     : 1.5
  Median Absolute Deviation : 1.0378215529539212

Estadísticos de forma

Las dos medidas de forma de la distribución principales son el Skewness o asimetría y la curtosis (Kurtosis) que habla de la concentración de datos cerca de la media y de la probabilidad de observar outliers.

La kurtosis de la distribución normal es 3, sin embargo suele usarse la $kurtosis - 3$ o excess kurtosis para comparar contra la distribución normal. Distribuciones para las cuales es menos probable observar outliers que en la distribución normal, dan valores de kurtosis negativa. Mientras que valores positivos de kurtosis se observan para distribuciones de probabilidad para los cuales se obtienen outliers o valores extremos con más frecuencia (es decir, poseen colas más pesadas).


In [47]:
using Distributions
using Plots

plt = plot()

for distribución in [ Uniform(-2,2), Normal(), Laplace() ]

    long_name = string(distribución)
    short_name = match(r"\.(\w+)\{",long_name)[1] # Obtiene Normal de Distributions.Normal{Float...
    
    println(long_name)
    println(" Kurtosis: ", kurtosis(distribución))
    
    plot!(plt, -3:0.01:3, x -> pdf(distribución, x), label=short_name)
end

plt


Distributions.Uniform{Float64}(a=-2.0, b=2.0)
 Kurtosis: -1.2
Distributions.Normal{Float64}(μ=0.0, σ=1.0)
 Kurtosis: 0.0
Distributions.Laplace{Float64}(μ=0.0, θ=1.0)
 Kurtosis: 3.0
Out[47]:

In [25]:
for (nombre, valores) in eachcol(iris)
    if eltype(valores) <: Real
        
        println(nombre)
        
        println("  Skewness : ", skewness(valores))
        println("  Kurtosis : ", kurtosis(valores))
        
    end
end


SepalLength
  Skewness : 0.31175305850229645
  Kurtosis : -0.573567948924977
SepalWidth
  Skewness : 0.31576710633893856
  Kurtosis : 0.18097631752246546
PetalLength
  Skewness : -0.27212766645672154
  Kurtosis : -1.3955358863990097
PetalWidth
  Skewness : -0.10193420656559918
  Kurtosis : -1.3360674052315484

Descripción gráfica


In [53]:
using StatPlots
pyplot(size=(600,300))


Out[53]:
Plots.PyPlotBackend()

In [54]:
columnas = [:SepalLength, :SepalWidth, :PetalLength, :PetalWidth]


Out[54]:
4-element Array{Symbol,1}:
 :SepalLength
 :SepalWidth 
 :PetalLength
 :PetalWidth 

Los Histogramas permiten tener una visión de cómo sería la forma de una distribución de densidad para una variable aleatoria continua. Se construyen dividiendo la variable en grupos (bins) y contando el número de observaciones dentro de cada uno (representada por la altura de la barra). El siguiente paso de complejidad que podríamos dar para tener una mejor estimación de la función de densidad de probabilidad, es utilizar Averaged Shifted Histograms (ASH) o el estimador por núcleo (KDE por Kernel Density Estimator). En Julia, si la biblioteca KernelDensity está instalada, Plots la utilizará en su función density. R también posee una función density que puede observarse usado plot(density(....
KDE tiene dos parámetros importantes, uno es la función kernel a utilizar que deber ser una distribución de probabilidad, por defecto se utiliza la distribución Normal. El otro parámetro es el ancho de banda a utilizar.


In [55]:
plot(
histogram(iris, columnas, alpha=0.5, bins=0:0.2:8, legend=true),
density(iris, columnas, alpha=0.5, legend=true, fill=0)
)


Out[55]:

Los Diagramas de Dispersión (scatter plots) utilizan las coordenadas cartesianas para mostrar cómo se distribuyen dos variables en un espacio bi dimensional. Es posible representar más dimensiones utilizado diferentes formas, tamaños y/o colores.


In [61]:
plot(
scatter(iris, :SepalLength, :SepalWidth, group=:Species),
scatter(iris, :PetalLength, :PetalWidth, group=:Species, legend=false)
)


Out[61]:

Otra manera de observar la distribución conjunta de dos variables continuas es haciendo uso de los histogramas bivariados o bidimensionales (2D o bivariate histograms). Los grupos (bins) se establecen para las dos variables, definiendo rectángulos en un espacio bidimensional. Normalmente se utiliza un código de color para indicar la cantidad de valores en cada grupo.


In [64]:
histogram2d(iris, :PetalLength, :PetalWidth, size=(400,300), bins=10)


Out[64]:

Esta representación se asemeja a la de un Mapa de calor (heatmap), pero estos últimos generalmente poseen variable discretas o categóricas en sus ejes (en lugar de la discretización de una variable continua, aunque ésto también es posible). Los heat maps son útiles para mostrar los valores de una matriz, y representan a una variable continua utilizando un gradiente de colores.


In [66]:
medias = by(iris, :Species) do df
    DataFrame( 
        SepalLength = mean(df[:SepalLength]),
        SepalWidth  = mean(df[:SepalWidth]),
        PetalLength = mean(df[:PetalLength]),
        PetalWidth  = mean(df[:PetalWidth])
    )
end


Out[66]:
SpeciesSepalLengthSepalWidthPetalLengthPetalWidth
1setosa5.0063.42799999999999951.4620.24600000000000002
2versicolor5.9362.774.261.3259999999999998
3virginica6.5879999999999992.97399999999999985.5522.026

In [81]:
heatmap(string.(columnas), string.(medias[:Species]), convert(Matrix{Float64}, medias[:,columnas]), 
        ratio=:equal, yflip=true)


Out[81]:

Muchas veces es útil pasar un DataFrame de un formato wide a uno long. En esta conversión se genera una nueva variable categórica con el nombre de las columnas como niveles y se acumula sus valores en una nueva variable. En Julia es posible usar melt y stack para cambiar la forma del DataFrame de wide to long o unstack para ir en el otro sentido. Esta operación es particularmente útil en R cuando se trabaja con ggplot2, y requiere de la biblioteca reshape2.


In [82]:
long = melt(iris, :Species)

head(long)


Out[82]:
variablevalueSpecies
1SepalLength4.6setosa
2SepalLength4.3setosa
3SepalLength5.8setosa
4SepalLength5.0setosa
5SepalLength4.7setosa
6SepalLength5.4setosa

Los Diagramas de Cajas (boxplots) son otra forma de visualizar datos acerca de una distribución. Son interesantes porque permiten observar estadísticos robustos de tendencia central (mediana) y de dispersión (rango entre cuartiles).


In [94]:
boxplot(string.(long[:variable]), long[:value], notch=true, legend=false)


Out[94]:

The notches (if requested) extend to +/- 1.58 IQR/sqrt(n). This seems to be based on the same calculations as the formula with 1.57 in Chambers et al (1983, p. 62), given in McGill et al (1978, p. 16). They are based on asymptotic normality of the median and roughly equal sample sizes for the two medians being compared, and are said to be rather insensitive to the underlying distributions of the samples. The idea appears to be to give roughly a 95% confidence interval for the difference in two medians. R boxplot's help


In [85]:
# install.packages("ggplot2") # Para installar ggplot2 en R

In [95]:
R"""
library(ggplot2)
ggplot($long, aes(x=as.character(variable), y=value)) + geom_boxplot()
"""


Out[95]:
RCall.RObject{RCall.VecSxp}

Gadfly es una biblioteca similar a ggplot2 pero para Julia.


In [97]:
using Gadfly

In [98]:
Gadfly.plot(long, x=:variable, y=:value, Geom.boxplot)


Out[98]:
variable SepalLength SepalWidth PetalLength PetalWidth -10 -8 -6 -4 -2 0 2 4 6 8 10 12 14 16 18 -8.0 -7.5 -7.0 -6.5 -6.0 -5.5 -5.0 -4.5 -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 9.5 10.0 10.5 11.0 11.5 12.0 12.5 13.0 13.5 14.0 14.5 15.0 15.5 16.0 -10 0 10 20 -8.0 -7.5 -7.0 -6.5 -6.0 -5.5 -5.0 -4.5 -4.0 -3.5 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 9.5 10.0 10.5 11.0 11.5 12.0 12.5 13.0 13.5 14.0 14.5 15.0 15.5 16.0 value

Mientras los density plots permiten observar una PDF inferida a partir de los datos, la función ecdf de la biblioteca StatsBase de Julia, permite observar la función de densidad de probabilidad acumulada empírica de una muestra (Empirical Cumulative Distribution Function ECDF), una aproximación a la CDF.


In [99]:
using StatsBase

In [100]:
ECDF = ecdf(iris[:SepalLength]) # retorna una función


Out[100]:
(::ef) (generic function with 2 methods)

In [101]:
plot(ECDF, extrema(iris[:SepalLength])..., label="ECDF")


Out[101]:

Ajuste de distribuciones estadísticas

Es posible, para los datos de una muestra, ajustar una distribución de densidad de probabilidad (distribution fitting). Muchos de los estadísticos determinados durante la exploración de datos pueden son los estimadores de máxima verosimilitud o maximum-likelihood estimator (MLE) de algunas distribuciones. Por ejemplo, la media es el estimador de máxima verosimilitud de la media poblacional $\mu$ de una distribución normal. Tanto los estadísticos cuantitativos, como el análisis gráfico realizado en la etapa de exploración (histogramas, density plots, boxplots y ecdf) pueden ayudar a decidir cuál familia de funciones de densidad de probabilidad debemos ajustar. La biblioteca Distributions de Julia posee un método fit que permite estimar los parámetros de una distribución a partir de los datos, en general usando máxima verosimilitud.


In [102]:
using Distributions

variable = iris[:SepalWidth]

mean(variable)


Out[102]:
3.0573333333333332

In [103]:
std(variable) # std usa n-1


Out[103]:
0.4358662849366982

In [104]:
ajuste = fit(Normal, variable) # std usa n


Out[104]:
Distributions.Normal{Float64}(μ=3.0573333333333337, σ=0.4344109677354944)

In [106]:
PDF = histogram(variable, normed=true)
plot!(PDF, x -> pdf(ajuste,x), extrema(variable)...)

CDF = plot(ecdf(variable), extrema(variable)...)
plot!(CDF, x -> cdf(ajuste,x), extrema(variable)...)

plot(PDF, CDF, legend=false)


Out[106]:

Tests de normalidad

Como parte del análisis inicial de datos, muchas veces debemos comprobar si los valores de una variable en nuestra muestra se distribuyen de manera normal. Existen diversas manera de testear normalidad, las más populares son:

Gráfico de probabilidad normal

Los gráficos QQ (qq plots por quantile) permiten comparar los cuantiles de dos distribuciones. Cuando en uno de los ejes se colocan los cuantiles de una distribución normal canónica, hablamos de un gráfico de probabilidad normalidad. Si la distribución de los datos es aproximadamente normal, el gráfico de normalidad mostrará los puntos equivalente a los datos distribuidos sobre una línea.


In [111]:
Gadfly.plot(x=ajuste, y=variable, Stat.qq, Geom.point)


Out[111]:
x -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 10 -3.0 -2.8 -2.6 -2.4 -2.2 -2.0 -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0 3.2 3.4 3.6 3.8 4.0 4.2 4.4 4.6 4.8 5.0 5.2 5.4 5.6 5.8 6.0 6.2 6.4 6.6 6.8 7.0 7.2 7.4 7.6 7.8 8.0 8.2 8.4 8.6 8.8 9.0 -5 0 5 10 -3.0 -2.5 -2.0 -1.5 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 8.0 8.5 9.0 -1.0 -0.5 0.0 0.5 1.0 1.5 2.0 2.5 3.0 3.5 4.0 4.5 5.0 5.5 6.0 6.5 7.0 7.5 -0.5 -0.4 -0.3 -0.2 -0.1 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 6.0 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 7.0 -2.5 0.0 2.5 5.0 7.5 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0 3.2 3.4 3.6 3.8 4.0 4.2 4.4 4.6 4.8 5.0 5.2 5.4 5.6 5.8 6.0 6.2 6.4 6.6 6.8 7.0 y

Test de hipótesis

Existen diversos test de hipótesis para testear normalidad (Ghasemi & Zahediasl 2012), estos tienen como hipótesis nula que los datos provienen de una cierta distribución (en particular de una distribución normal). Por lo tanto, p values altos son indicativos de que no hay evidencia suficiente para rechazar que los datos provienen de una distribución normal. Las dos pruebas de normalidad recomendadas son la de Anderson-Darling y la prueba de Shapiro-Wilk, ambas poseen más poder que Kolmogorov-Smirnov para esa tarea.

Ghasemi, Asghar, and Saleh Zahediasl. "Normality tests for statistical analysis: a guide for non-statisticians." International journal of endocrinology and metabolism 10.2 (2012): 486-489.


In [113]:
using HypothesisTests

In [114]:
OneSampleADTest(variable, Normal())


Out[114]:
One sample Anderson-Darling test
--------------------------------
Population details:
    parameter of interest:   not implemented yet
    value under h_0:         NaN
    point estimate:          NaN

Test summary:
    outcome with 95% confidence: reject h_0
    two-sided p-value:           0.020226513622600077 (significant)

Details:
    number of observations:   150
    sample mean:              3.0573333333333337
    sample SD:                0.4358662849366982
    A² statistic:             0.907955047114541

In [115]:
R"shapiro.test($variable)"


Out[115]:
RCall.RObject{RCall.VecSxp}

	Shapiro-Wilk normality test

data:  `#JL`$variable
W = 0.98492, p-value = 0.1012

Teorización Post Hoc

Se denomina teorización post hoc a la generación de hipótesis sugeridas por el conjunto de datos observado, sin testear esta hipótesis en nuevos datos. Hacerlo puede resultar en aceptar hipótesis incorrectas, que sólo son válidas en el presente conjunto de datos, dado que es más probable aceptar una hipótesis testeada en el conjunto de datos en el cual se genero.
Es necesario testear estas nuevas hipotesis en una nueva muestra de la población. Sin embargo, en muchas casos eso puede ser imposible, por ejemplo al analizar un fenómeno natural finito. Este problema de disponer de un conjunto limitado de datos, haciendo difícil o imposible la recolección de nuevos datos para la fase de confirmación fue denominado por John Tukey como uncomfortable science.
Un caso no tan obvio de uncomfortable science o de teorización post hoc puede surgir bioinformática cuando se toman todos los elementos disponibles de una base de datos para hacer los análisis exploratorios sin dejar datos suficientes para testear las hipótesis que surgen de ese análisis. Otro proceso que puede generar este tipo de problemas es el conocido como data fishing, el cual consiste en ir testeando hipótesis sobre un conjunto de datos hasta encontrar una un valor estadísticamente significativo en algún test de hipótesis. El término data fishing posee una connotación negativa, dado que representa el comportamiento poco ético de buscar, seleccionar e informar sólo los resultados positivos sin el debido control, muchas veces como si las hipótesis hubiera sido anterior al análisis (Leung 2011).
Buscar patrones en los datos, muchas veces aplicando test estadísticos, no es incorrecto. Lo incorrecto es utilizar el mismo conjunto de datos (in-sample data) para soportar esa hipótesis. Las alternativas posibles para no caer en este problema son:

  • Recolectar nuevos datos (out-of-sample data), realizar un nuevo experimento, para testear la nueva hipótesis.
  • Si no es posible recolectar nuevos datos, es posible separar el conjunto de datos de manera aleatoria en dos grupos. Uno puede ser usado para plantear nuevas hipótesis, que luego serán testeadas en el otro conjunto.
  • Dado que la teorización post hoc y los casos de uncomfortable science pueden terminar en sobreajuste (overfitting), los métodos de validación cruzada (cross validation) pueden resultar útiles para evitarlo.
  • Aplicar correcciones por testeo múltiple, considerando todas las hipótesis testeadas (por ejemplo, todas las hipótesis testeadas durante el proceso de data fishing).

Leung, Kwok. "Presenting post hoc hypotheses as a priori: Ethical and theoretical issues." Management and Organization Review 7.3 (2011): 471-479.