Fondo difuminado
R y Python
en Osakidetza

Flujo de trabajo

Si nunca hemos trabajado con lenguajes de programación puede resultar complicado e incluso desafiante hacer uso de estas herramientas. Sin embargo, una vez entendida la lógica con la que trabajan encontrareis como las capacidades de estas herramientas superan con crees sus inconvenientes (que únicamente suele ser la curva de aprendizaje que necesitan).

Por ello, para utilizar correctamente estas herramientas ante es necesario conocer, de forma básica, su funcionamiento; objetivo de esta breve sección.

¡Comencemos a entenderla!


Los comandos de trabajo

Los lenguajes de programación trabajan con texto, es decir, las órdenes que el ordenador debe ejecutar se deben escribir. Algunas órdenes viene establecidas, otras se pueden instarla y otras pueden ser creadas por nosotros mismos. Una vez que tenemos las órdenes, podemos combinarlas para que el ordenador haga todo lo que deseamos.

En el siguiente ejemplo disponéis de unas órdenes sencillas. Creamos un objeto que se llama “sueldo” y le sumamos otro objeto llamado “extra” para después restar una retención del 15% y obtener el sueldo neto:

Realizado en R

# Definimos los objetos
sueldo <- 2100
extra <- 1000

# Combinamos los objetos en otro llamado "sueldo íntegro" 
# y le ordenamos al ordenador que resto el 15% para obtener el suelo neto:

sueldo_integro <- sueldo + extra # (mejor no usar tildes ni espacio 
# para nombran objetos ya que traen problemas)

sueldo_neto <- sueldo_integro - (0.15*sueldo_integro)

# Le ordenamos al ordenador que nos imprima el sueldo 
# neto haciendo uso de la orden "print()", orden ya instalada en el ordenador

print(sueldo_neto)
[1] 2635
# Podemos utilizar otra orden ya predefina para que 
# aparezca el resultado mas "visual". Haremos uso de la orden "cat()"

cat("Mi sueldo es de:", sueldo_neto, "euros")
Mi sueldo es de: 2635 euros

Realizado en Python

# Definimos los objetos
sueldo = 2100
extra = 1000

# Combinamos los objetos en otro llamado "sueldo_integro"
# y calculamos el sueldo neto restando el 15%
sueldo_integro = sueldo + extra
sueldo_neto = sueldo_integro - (0.15 * sueldo_integro)

# Imprimimos el sueldo neto con print()
print(sueldo_neto)
2635.0
# Usamos format() para mostrar el resultado de forma más visual
print(f"Mi sueldo es de: {sueldo_neto} euros")
Mi sueldo es de: 2635.0 euros

A partir de esta idea básica se construye todo lo demás. Las ordenes se van combinando unas con otras para hacer órdenes complejas. A su vez, las órdenes puede tener variables que podemos modificar para que el ordenador realice la misma acción pero con otras condiciones.

Pongamos un ejemplo sencillo. Podemos calcular el valor de la prueba chi-cuadrado para una confianza al 95% utilizando o no la corrección de Yates. Se trata de la misma orden, calcular la prueba chi-cuadrado pero con dos condiciones distintas.

Realizado en R

# Creamos una tabla de contingencia y la visualizamos
datos <- matrix(c(38, 12, 14, 8), nrow = 2, byrow = TRUE)
rownames(datos) <- c("Boliviana", "Extranjera")
colnames(datos) <- c("Menor a 10.000", "Mayor a 10.000")
tabla <- as.table(datos)
print(tabla)
           Menor a 10.000 Mayor a 10.000
Boliviana              38             12
Extranjera             14              8
# Realizar la prueba chi-cuadrado con correción de Yates (correct = TRUE)
resultado <- chisq.test(tabla, correct = TRUE)

# Mostramos los resultados
print(resultado)

    Pearson's Chi-squared test with Yates' continuity correction

data:  tabla
X-squared = 0.62937, df = 1, p-value = 0.4276
# Realizamos la prueba chi-cuadrado sin correción de Yates (correct = FALSE)
resultado <- chisq.test(tabla, correct = FALSE)

# Mostramos los resultados
print(resultado)

    Pearson's Chi-squared test

data:  tabla
X-squared = 1.1641, df = 1, p-value = 0.2806

Realizado en Python

import numpy as np
from scipy.stats import chi2_contingency

# Creamos una tabla de contingencia
datos = np.array([[38, 12], [14, 8]])
filas = ["Boliviana", "Extranjera"]
columnas = ["Menor a 10.000", "Mayor a 10.000"]

# Mostramos la tabla de contingencia
print("Tabla de contingencia:")
Tabla de contingencia:
print(datos)
[[38 12]
 [14  8]]
# Realizamos la prueba chi-cuadrado con corrección de Yates
resultado_correcto = chi2_contingency(datos, correction=True)
print("\nResultados con corrección de Yates:")

Resultados con corrección de Yates:
print(f"Estadístico: {resultado_correcto[0]}, p-valor: {resultado_correcto[1]}")
Estadístico: 0.6293706293706294, p-valor: 0.4275862651639998
# Realizamos la prueba chi-cuadrado sin corrección de Yates
resultado_sin_correccion = chi2_contingency(datos, correction=False)
print("\nResultados sin corrección de Yates:")

Resultados sin corrección de Yates:
print(f"Estadístico: {resultado_sin_correccion[0]}, p-valor: {resultado_sin_correccion[1]}")
Estadístico: 1.1640839160839163, p-valor: 0.2806201795677896

Órdenes predefinidas, a instalar y propias.

Las órdenes utilizadas por el ordenador pueden venir instaladas con los lenguajes de programación y ser básicas: Operaciones sencillas, unión de varias formulas… o pueden ser instalas directamente desde otra parte (desde Internet o desde una memoria externa como un USB).

Órdenes a instalar

Las ordenes a instalar suele venir compactadas en unos archivos llamado Librerías. Cada librería tiene un objetivo (tendremos algunas especializadas en manipular datos, otras en análisis estadísticos básicos, otras en minerías de texto…). Las librerías suelen ser realizadas de forma general por científicos (como tú) que desarrollan un procedimiento y lo “donan” al público para que todo el mundo pueda hacer uso de él (el modelo Open Science).

A continuación vamos a instalar una librería que se llama DescTools (que dispone de ordenes para realizar el análisis descriptivo de los datos) y vamos a describir los datos que disponemos utilizando sus comandos:

Realizado en R

# Verificamos si DescTools está instalada; si no, se instala
if (!require("DescTools")) {
  install.packages("DescTools")
  library(DescTools)
}
Cargando paquete requerido: DescTools
# Ejemplo: Calculamos intervalo de confianza para una proporción binomial
n_exitos <- 50
n_total <- 100

# Utilizamos la orden BinomCI() de la librería

resultado <- BinomCI(x = n_exitos, n = n_total, conf.level = 0.95, method = "wilson")

# Mostramos el resultado
print(resultado)
     est    lwr.ci    upr.ci
[1,] 0.5 0.4038315 0.5961685

Realizado en Python

import statsmodels.api as sm

# Definimos los parámetros
n_exitos = 50
n_total = 100

# Calculamos el intervalo de confianza binomial con método Wilson
intervalo = sm.stats.proportion_confint(count=n_exitos, 
                                      nobs=n_total, 
                                      alpha=0.05, 
                                      method='wilson')

# Formateamos el resultado similar al output de R
resultado = [[n_exitos/n_total, intervalo[0], intervalo[1]]]
print("           est     lwr.ci     upr.ci")
           est     lwr.ci     upr.ci
print(f"resultado {resultado[0][0]:.4f}   {resultado[0][1]:.4f}   {resultado[0][2]:.4f}")
resultado 0.5000   0.4038   0.5962

Si no sabemos qué es lo que hace una orden podemos poner una interrogación antes de la orden y el ordenar buscará la información adjunta a dicha orden:

?BinomCI()

Órdenes propias

Si no encuentras una librería que tenga las órdenes que necesitas siempre pueden crearlas tu para luego utilizarlas. Aquí te mostramos un ejemplo de como se crearía la prueba de chi cuadrado de forma casera:

Realizado en R

# Función casera para la prueba chi-cuadrado
chi_cuadrado_casera <- function(tabla_observada) {
  # Calcular totales de filas y columnas
  totales_filas <- rowSums(tabla_observada)
  totales_columnas <- colSums(tabla_observada)
  total_general <- sum(tabla_observada)
  
  # Calcular frecuencias esperadas
  frecuencias_esperadas <- outer(totales_filas, totales_columnas) / total_general
  
  # Calcular el estadístico chi-cuadrado
  chi_cuadrado <- sum((tabla_observada - frecuencias_esperadas)^2 / frecuencias_esperadas)
  
  # Calcular grados de libertad
  grados_libertad <- (nrow(tabla_observada) - 1) * (ncol(tabla_observada) - 1)
  
  # Calcular el valor p
  valor_p <- 1 - pchisq(chi_cuadrado, df = grados_libertad)
  
  # Crear y devolver el resultado
  resultado <- list(
    estadistico = chi_cuadrado,
    grados_libertad = grados_libertad,
    valor_p = valor_p
  )
  
  return(resultado)
}

# Ejemplo de uso
tabla_ejemplo <- matrix(c(30, 10, 20, 15), nrow = 2)
colnames(tabla_ejemplo) <- c("Grupo A", "Grupo B")
rownames(tabla_ejemplo) <- c("Categoría 1", "Categoría 2")
print(tabla_ejemplo)
            Grupo A Grupo B
Categoría 1      30      20
Categoría 2      10      15
# Usar la función casera
resultado_casero <- chi_cuadrado_casera(tabla_ejemplo)

# Imprimir resultados de la función casera
cat("Valor p:", resultado_casero$valor_p, "\n\n")
Valor p: 0.1017069 
# Comparar con la función incorporada chisq.test()
resultado_r <- chisq.test(tabla_ejemplo, correct = F)

# Imprimir resultados de chisq.test()
cat("Resultados de chisq.test() de R:\n")
Resultados de chisq.test() de R:
print(resultado_r)

    Pearson's Chi-squared test

data:  tabla_ejemplo
X-squared = 2.6786, df = 1, p-value = 0.1017

Realizado en Python

import numpy as np
from scipy.stats import chi2, chi2_contingency

def chi_cuadrado_casera(tabla_observada):
    # Calcular totales de filas y columnas
    totales_filas = tabla_observada.sum(axis=1)
    totales_columnas = tabla_observada.sum(axis=0)
    total_general = tabla_observada.sum()
    
    # Calcular frecuencias esperadas usando producto externo
    frecuencias_esperadas = np.outer(totales_filas, totales_columnas) / total_general
    
    # Calcular estadístico chi-cuadrado
    chi_cuadrado = np.sum((tabla_observada - frecuencias_esperadas)**2 / frecuencias_esperadas)
    
    # Calcular grados de libertad
    grados_libertad = (tabla_observada.shape[0] - 1) * (tabla_observada.shape[1] - 1)
    
    # Calcular valor p usando función de supervivencia
    valor_p = chi2.sf(chi_cuadrado, grados_libertad)
    
    return {
        'estadistico': chi_cuadrado,
        'grados_libertad': grados_libertad,
        'valor_p': valor_p
    }

# Ejemplo de uso
tabla_ejemplo = np.array([[30, 10], [20, 15]])
print("Tabla de ejemplo:")
Tabla de ejemplo:
print(tabla_ejemplo)
[[30 10]
 [20 15]]
# Usar la función casera
resultado_casero = chi_cuadrado_casera(tabla_ejemplo)
print("\nResultados de la función casera:")

Resultados de la función casera:
print(f"Estadístico Chi-cuadrado: {resultado_casero['estadistico']:.4f}")
Estadístico Chi-cuadrado: 2.6786
print(f"Grados de libertad: {resultado_casero['grados_libertad']}")
Grados de libertad: 1
print(f"Valor p: {resultado_casero['valor_p']:.4f}\n")
Valor p: 0.1017
# Comparar con SciPy (sin corrección de Yates)
chi2_stat, p_valor, dof, expected = chi2_contingency(tabla_ejemplo, correction=False)
print("Resultados de chi2_contingency (SciPy):")
Resultados de chi2_contingency (SciPy):
print(f"Estadístico Chi-cuadrado: {chi2_stat:.4f}")
Estadístico Chi-cuadrado: 2.6786
print(f"Grados de libertad: {dof}")
Grados de libertad: 1
print(f"Valor p: {p_valor:.4f}")
Valor p: 0.1017

Lugar de escritura

Por último para escribir las órdenes que le vamos a dar al ordenador tenemos dos opciones:

  • Escribir directamente en la consola de la programación

  • Escribir en un archivo de texto denominado “script” de código

La ventaja que supone escribir en los script es que podemos escribir varias ordenes (como si fuera una hoja de word) a la vez, guardarlas y decidir cuales de ellas tendrá que ejecutar el ordenador. En este ejemplo tengo un conjunto de datos. Tengo ordenes para hacer algo de estadística básica pero solo vamos a ejecutar la línea donde se encuentra el histograma (la orden se llama hist()):

# 1. Generar un conjunto de datos aleatorios (100 números entre 1 y 100)
datos <- sample(1:100, size = 100, replace = TRUE)

# 2. Calcular la media de los datos
media_datos <- mean(datos)

# 3. Calcular la desviación estándar de los datos
desviacion_estandar <- sd(datos)

# 4. Crear un histograma para visualizar los datos
hist(datos, main = "Histograma de Datos Aleatorios", col = "skyblue", xlab = "Valores", 
     ylab = "Frecuencia")