4. Importar Excel

1 Importar datos desde Excel (readxl) y verificación inicial

Objetivo: leer Salaries.xlsx desde la carpeta Datos/, verificar que se cargó correctamente (dimensiones, nombres, tipos) y dejar identificadas las columnas clave para trabajar en la siguiente sección.

Tip

Estructura de proyecto recomendada: guarda el archivo en Datos/Salaries.xlsx.
Si usas RStudio, abre el proyecto (.Rproj) para que las rutas relativas funcionen (no uses rutas absolutas de tu PC).

1.1 Lectura desde Datos/ y chequeo básico

Code
library(readxl)

# Lectura simple (espera hoja 1 y encabezados en la 1ª fila)
#Salaries <- read_excel("Datos/Salaries.xlsx")

Salaries <- readxl::read_excel(ruta_salaries)  



# Vistazos rápidos
nrow(Salaries); ncol(Salaries)   # dimensiones
[1] 397
[1] 6
Code
names(Salaries)                  # nombres de columnas
[1] "rank"          "discipline"    "yrs.since.phd" "yrs.service"  
[5] "sex"           "salary"       
Code
str(Salaries)                    # tipos por columna
tibble [397 × 6] (S3: tbl_df/tbl/data.frame)
 $ rank         : chr [1:397] "Prof" "Prof" "AsstProf" "Prof" ...
 $ discipline   : chr [1:397] "B" "B" "B" "B" ...
 $ yrs.since.phd: num [1:397] 19.5 20 4 45 40 6 30 45 21 18 ...
 $ yrs.service  : num [1:397] 18 16 3 39 41 6 23 45 20 18 ...
 $ sex          : chr [1:397] "Male" "Male" "Male" "Male" ...
 $ salary       : num [1:397] 139750 173200 79750 115000 141500 ...
Code
head(Salaries, 3)                # primeras filas
Warning

¿Error de archivo? Si aparece “No such file or directory”, confirma que el archivo está en Datos/ (misma carpeta raíz donde está este .qmd). Decimales en R: usa punto como separador (ej. 107300.00).

1.2 Columnas clave y tipos esperados

Para este curso usaremos principalmente: rank, sex, yrs.service, salary.

Code
# Selección de columnas clave (si existen en tu archivo)
cols_clave <- c("rank", "sex", "yrs.service", "salary")
cols_clave %in% names(Salaries)
[1] TRUE TRUE TRUE TRUE
Code
# Subconjunto (no falla si falta alguna: usa any_of)
BaseSal <- dplyr::select(Salaries, dplyr::any_of(cols_clave))
head(BaseSal)
Code
# Tipos esperados (diagnóstico)
# rank/sex: categóricas (character o factor)
# yrs.service/salary: numéricas
sapply(BaseSal, class)
       rank         sex yrs.service      salary 
"character" "character"   "numeric"   "numeric" 
Note

Si salary aparece como texto (por símbolos $, comas o espacios), conviértelo:

  • Opción rápida con readr::parse_number() (parte de tidyverse).
Code
# Solo si detectas salary como texto con símbolos:
# install.packages("readr")  # si no está
library(readr)

if ("salary" %in% names(BaseSal)) {
  if (is.character(BaseSal$salary)) {
    BaseSal <- BaseSal |>
      dplyr::mutate(salary = parse_number(salary))  # quita $ , . espacios
  }
}
str(BaseSal$salary)
 num [1:397] 139750 173200 79750 115000 141500 ...

1.3 Valores faltantes (NA) y duplicados

Code
# Conteo de NA por columna
na_por_col <- sapply(BaseSal, function(x) sum(is.na(x)))
na_por_col
       rank         sex yrs.service      salary 
          0           0           0           0 
Code
# Porcentaje de NA
pct_na <- round(colMeans(is.na(BaseSal)) * 100, 2)
pct_na
       rank         sex yrs.service      salary 
          0           0           0           0 
Code
# Duplicados exactos (en las columnas clave)
dups <- dplyr::distinct(BaseSal) |> nrow() < nrow(BaseSal)
dups  # TRUE si hay filas duplicadas exactas
[1] TRUE
Important

Regla didáctica: no elimines NA o duplicados “a ciegas”. Decide por qué y cómo afectará tu análisis (lo documentarás cuando limpies en dplyr).

1.4 Estándares mínimos antes de analizar

Code
# Normaliza nombres por si llegan con mayúsculas/espacios
# (sin añadir paquetes nuevos)
names(BaseSal) <- names(BaseSal) |>
  tolower() |>
  gsub("\\s+", "_", x = _)

# Convierte tipos si hace falta
if ("rank" %in% names(BaseSal)) BaseSal$rank <- as.factor(BaseSal$rank)
if ("sex"  %in% names(BaseSal)) BaseSal$sex  <- as.factor(BaseSal$sex)
if ("yrs.service" %in% names(Salaries) && !"yrs.service" %in% names(BaseSal)) {
  # Si quedó afuera por nombres, tráela
  BaseSal$yrs.service <- Salaries$`yrs.service`
}
if ("yrs.service" %in% names(BaseSal)) {
  BaseSal$yrs.service <- suppressWarnings(as.numeric(BaseSal$yrs.service))
}
if ("salary" %in% names(BaseSal)) {
  BaseSal$salary <- suppressWarnings(as.numeric(BaseSal$salary))
}

str(BaseSal)
tibble [397 × 4] (S3: tbl_df/tbl/data.frame)
 $ rank       : Factor w/ 3 levels "AssocProf","AsstProf",..: 3 3 2 3 3 1 3 3 3 3 ...
 $ sex        : Factor w/ 2 levels "Female","Male": 2 2 2 2 2 2 2 2 2 1 ...
 $ yrs.service: num [1:397] 18 16 3 39 41 6 23 45 20 18 ...
 $ salary     : num [1:397] 139750 173200 79750 115000 141500 ...

1.5 Ejercicios

  1. Imprime las 3 categorías más frecuentes de rank (pista: table() o dplyr::count() + arrange(desc(n))).

  2. Calcula el porcentaje de NA en salary y di si es aceptable para continuar (propón una acción).

  3. Crea un objeto Base10 con solo filas donde yrs.service >= 10 y solo columnas rank, sex, yrs.service, salary.

  4. (Exploratorio) Si salary venía como texto con $ o comas, demuestra con 2 ejemplos que parse_number() lo dejó numérico (muestra class() y una pequeña operación).

Code
# 1) Top 3 de rank
top_rank <- dplyr::count(BaseSal, rank, sort = TRUE)
head(top_rank, 3)
Code
# 2) % NA en salary
pct_na_salary <- mean(is.na(BaseSal$salary)) * 100
pct_na_salary
[1] 0
Code
# 3) Filtrado por antigüedad (yrs.service >= 10)
Base10 <- BaseSal |>
  dplyr::filter(yrs.service >= 10) |>
  dplyr::select(rank, sex, yrs.service, salary)
head(Base10)
Code
# 4) Verificación numérica (si aplica)
class(BaseSal$salary)
[1] "numeric"
Code
if (is.numeric(BaseSal$salary)) {
  # pequeña operación: promedio con NA ignorados
  mean(BaseSal$salary, na.rm = TRUE)
}
[1] 113706.5