Autor/a

Aníbal Olivera

Fecha de publicación

8 de enero de 2025

Introducción

Este documento detalla el proceso de limpieza y preparación de los datos de la General Social Survey (GSS) (años 1985 y 2004) para replicar el análisis de homofilia de Smith & McPherson (2014).

El código aquí presentado es una adaptación del script 01_data_prep.R del material de replicación original.

Configuración y Paquetes

Código
library(dplyr)
library(tidyr)
library(haven)
library(readr)

# Configuración de rutas
GSS_1985_PATH <- "data/GSS_1985_NORC.dta"
GSS_2004_PATH <- "data/GSS_2004_NORC.dta"
OUTPUT_DIR <- "data"

if (!dir.exists(OUTPUT_DIR)) dir.create(OUTPUT_DIR)

Mapeo de Variables

Definimos un mapeo para estandarizar los nombres de variables entre los distintos años de la GSS.

Código
# Mapeo de Variables Originales (GSS names) a Variables Estandarizadas
VAR_MAP <- list(
  ID = "id",             # Respondent ID
  AGE = "age",           # Age of respondent
  SEX = "sex",           # Sex of respondent
  RACE = "race",         # Race of respondent
  RELIG = "relig",       # Religion of respondent
  EDUC = "educ",         # Education (years) of respondent
  
  # Atributos de los Alter (Prefixes)
  ALTER_AGE = "age",     # e.g., age1, age2...
  ALTER_SEX = "sex",     # e.g., sex1, sex2...
  ALTER_RACE = "race",   # e.g., race1, race2...
  ALTER_RELIG = "relig", # e.g., relig1, relig2...
  ALTER_EDUC = "educ",   # e.g., educ1, educ2...
  
  # Relaciones
  REL_SPOUSE = "spouse",
  REL_PARENT = "parent",
  REL_SIBLING = "sibling",
  REL_CHILD = "child"
)

# Mapeo de Educación (Categorías a Años de estudio)
# Basado en la recodificación del paper
EDUC_MAPPING <- c(
  "0" = 3.5,  # 1-6 years
  "1" = 8,    # 7-9 years
  "2" = 11,   # 10-12 years (Non-graduate)
  "3" = 12,   # HS grad
  "4" = 13.5, # Some college
  "5" = 14,   # Associate deg
  "6" = 16,   # Bachelor's
  "7" = 18    # Grad/Prof
)

Función de Procesamiento

Creamos una función genérica prepare_gss_data que: 1. Carga el archivo RAW. 2. Extrae atributos del Ego. 3. Reshapea los atributos de los Alters (de Wide a Long). 4. Recodifica Raza y Educación.

Código
prepare_gss_data <- function(file_path, year) {
  
  message(paste("Procesando año:", year))
  
  # 1. Cargar Datos
  if (grepl("\\.dta$", file_path)) {
    # haven lee .dta
    raw_data <- read_dta(file_path)
  } else {
    raw_data <- read.csv(file_path)
  }
  
  # Convertir nombres a minúsculas para consistencia (GSS a veces varía)
  # names(raw_data) <- tolower(names(raw_data)) 
  # NOTA: Asumiremos nombres consistentes con el VAR_MAP por ahora.
  
  # 2. Variables Ego
  # Seleccionamos y renombramos
  ego_vars <- c(VAR_MAP$ID, VAR_MAP$AGE, VAR_MAP$SEX, VAR_MAP$RACE, VAR_MAP$RELIG, VAR_MAP$EDUC)
  
  # Verificar existencia (simple check)
  if (!all(ego_vars %in% names(raw_data))) {
     missing <- ego_vars[!ego_vars %in% names(raw_data)]
     warning(paste("Faltan variables ego:", paste(missing, collapse=", ")))
  }
  
  ego_df <- raw_data %>%
    select(any_of(ego_vars)) %>%
    rename(
      ego_id = !!sym(VAR_MAP$ID),
      ego_age = !!sym(VAR_MAP$AGE),
      ego_sex = !!sym(VAR_MAP$SEX),
      ego_race = !!sym(VAR_MAP$RACE),
      ego_relig = !!sym(VAR_MAP$RELIG),
      ego_educ = !!sym(VAR_MAP$EDUC)
    ) %>%
    mutate(year = year) %>%
    drop_na() # Eliminar casos con datos faltantes en atributos propios
    
  # 3. Variables Alter (Reshape Wide -> Long)
  max_alters <- 5
  alter_long <- data.frame()
  
  for (i in 1:max_alters) {
    # Construir nombres de columnas para el alter i
    col_age <- paste0(VAR_MAP$ALTER_AGE, i)
    col_sex <- paste0(VAR_MAP$ALTER_SEX, i)
    col_race <- paste0(VAR_MAP$ALTER_RACE, i)
    col_relig <- paste0(VAR_MAP$ALTER_RELIG, i)
    col_educ <- paste0(VAR_MAP$ALTER_EDUC, i)
    
    # Columnas esperadas
    current_cols <- c(col_age, col_sex, col_race, col_relig, col_educ)
    
    # Verificar si existen en la data
    if (all(current_cols %in% names(raw_data))) {
      
      temp <- raw_data %>%
        select(!!sym(VAR_MAP$ID), all_of(current_cols)) %>%
        rename(
          ego_id = !!sym(VAR_MAP$ID),
          alter_age = !!sym(col_age),
          alter_sex = !!sym(col_sex),
          alter_race = !!sym(col_race),
          alter_relig = !!sym(col_relig),
          alter_educ_cat = !!sym(col_educ)
        ) %>%
        mutate(alter_rank = i)
      
      # Kinship (simplificado para este ejemplo)
      # Aquí se podría añadir lógica de is_kin basada en spouse1, parent1, etc.
      # Para esta versión "clean", nos enfocaremos en atributos demográficos.
      
      alter_long <- bind_rows(alter_long, temp)
    }
  }
  
  # 4. Join y Limpieza Final
  dyads <- alter_long %>%
    inner_join(ego_df, by = "ego_id") %>%
    filter(!is.na(alter_sex)) # Eliminar alters vacíos
  
  # Recodificación de Raza (Estandarización)
  # GSS: 1=White, 2=Black, 3=Other (Simplificado)
  # Dependiendo del año GSS, esto puede variar. Asumimos codificación estándar del paper.
  # 4->1 (White), 2->2 (Black), Resto->3 (Other)
  
  dyads <- dyads %>%
    mutate(
      alter_race_orig = as.numeric(alter_race),
      alter_race = case_when(
        as.numeric(alter_race) == 4 ~ 1, # White
        as.numeric(alter_race) == 2 ~ 2, # Black
        as.numeric(alter_race) %in% c(1, 3, 5) ~ 3, # Other
        TRUE ~ NA_real_
      ),
      ego_race = as.numeric(ego_race)
    )
    
  # Recodificación de Educación
  dyads <- dyads %>%
    mutate(
      alter_educ = as.numeric(as.character(factor(alter_educ_cat, 
                                                  levels = names(EDUC_MAPPING), 
                                                  labels = EDUC_MAPPING)))
    ) %>%
    drop_na(ego_age, alter_age, ego_educ, alter_educ, ego_sex, alter_sex, ego_race, alter_race) %>%
    haven::zap_labels() # Eliminar etiquetas para evitar incompatibilidad en bind_rows
  
  return(dyads)
}

Ejecución del Procesamiento

Procesamos ambos datasets y guardamos los resultados en formato RDS para su uso en los módulos de análisis.

Código
# Procesar 1985
if (file.exists(GSS_1985_PATH)) {
  clean_1985 <- prepare_gss_data(GSS_1985_PATH, 1985)
  saveRDS(clean_1985, file = file.path(OUTPUT_DIR, "clean_gss_1985.rds"))
  print(paste("1985 guardado. N Dyads:", nrow(clean_1985)))
} else {
  warning("Archivo GSS 1985 no encontrado.")
}
Procesando año: 1985
[1] "1985 guardado. N Dyads: 4258"
Código
# Procesar 2004
if (file.exists(GSS_2004_PATH)) {
  clean_2004 <- prepare_gss_data(GSS_2004_PATH, 2004)
  saveRDS(clean_2004, file = file.path(OUTPUT_DIR, "clean_gss_2004.rds"))
  print(paste("2004 guardado. N Dyads:", nrow(clean_2004)))
} else {
  warning("Archivo GSS 2004 no encontrado.")
}
Procesando año: 2004
[1] "2004 guardado. N Dyads: 2743"

Resumen de Datos Generados

GSS 1985 Dimensiones: 4258 15 
  ego_id alter_age alter_sex alter_race alter_relig alter_educ_cat alter_rank
1      1        32         1          1           3              7          1
2      2        42         2          1           2              3          1
3      3        25         2          1           3              6          1
4      4        26         2          1           4              7          1
5      5        44         2          1           2              3          1
6      6        40         1          1           1              6          1
  ego_age ego_sex ego_race ego_relig ego_educ year alter_race_orig alter_educ
1      33       1        1         3       16 1985               4         18
2      49       1        1         2       19 1985               4         12
3      23       2        1         3       16 1985               4         16
4      26       2        1         3       20 1985               4         18
5      24       2        1         2       17 1985               4         12
6      45       1        1         4       17 1985               4         16