Saltar al contenido
Volver a DMetrics
SerieR: de cero a investigación reproducible· Capítulo 3 de 12
ArtículoIntermedio12 min
R

Vectores: el modelo mental que sostiene todo R

En R no existen los escalares: todo es un vector. Entender esa idea — crear, indexar, vectorizar y esquivar el reciclaje silencioso — es entender el lenguaje.

DM
Daniel MolinaEconomista & Data Scientist

1. En R no existen los escalares

¿Alguna vez te preguntaste por qué R imprime [1] 5 cuando escribes 5? Ese [1] es la pista de la idea más importante del lenguaje: en R no existen los números sueltos. Cuando escribes 5, R lo trata como un vector numérico de longitud 1, y el [1] te dice 'este es el elemento en la posición 1'. Toda función de R está diseñada pensando en vectores, y eso explica por qué el lenguaje se siente tan natural para análisis de datos: una columna de ventas, una serie de precios o las respuestas de una encuesta SON vectores. Todo lo demás — matrices, factores, data frames — se construye sobre ellos. Cada filtro que escribas será una condición sobre un vector; cada función de resumen (mean(), sum(), max()) recibe un vector. Dominar esta estructura no es aprender 'una más': es aprender el idioma nativo.

2. Crear vectores: c(), secuencias y repeticiones

La función c() (de combine) es la más usada de todo R, pero para secuencias regulares hay herramientas más expresivas. Cada creador tiene su especialidad: c() combina valores sueltos (y concatena vectores enteros), el operador : es el atajo para secuencias enteras de paso 1, seq() te deja controlar el paso (by) o el número de elementos (length.out), y rep() repite — con dos argumentos que la gente confunde: times repite el bloque completo, each repite cada elemento antes de pasar al siguiente. ¿Dónde se usa esto en la vida real? Etiquetas de periodos, grupos de un experimento, rejillas de escenarios, ejes de gráficos:

R
ventas <- c(150, 172, 168, 195)    # c() = combinar valores
seq(0, 1, by = 0.25)               # controlas el paso
# [1] 0.00 0.25 0.50 0.75 1.00
seq(0, 100, length.out = 5)        # controlas cuántos elementos
# [1]   0  25  50  75 100

rep(c("T1", "T2"), times = 3)      # el bloque entero, 3 veces
# [1] "T1" "T2" "T1" "T2" "T1" "T2"
rep(c("T1", "T2"), each = 3)       # cada elemento, 3 veces seguidas
# [1] "T1" "T1" "T1" "T2" "T2" "T2"

3. Las 5 formas de indexar (¡empieza en 1!)

Indexar es pedirle al vector un subconjunto con corchetes, y dominar las cinco formas paga doble: son exactamente las mismas que luego usarás con matrices y data frames. Posición positiva (dame el elemento 1), negativa (todo MENOS el 1), condición lógica (los que cumplen), por nombre, y which() — que no devuelve los valores sino sus posiciones. La condición lógica merece pausa: ventas > 165 produce FALSE TRUE TRUE TRUE, y al meterlo en los corchetes R conserva solo los TRUE; ese patrón es el corazón de todo filtro que harás en tu vida con R. Y una advertencia que evita bugs silenciosos: en R los índices empiezan en 1, no en 0 — v[0] no da error, devuelve un vector vacío, que es peor porque pasa desapercibido. Bonus: los corchetes también escriben — asignarles un valor reemplaza exactamente esas posiciones, el patrón estándar de la limpieza de datos:

R
ventas <- c(ene = 150, feb = 172, mar = 168, abr = 195)

ventas[c(2, 4)]        # por posición:      feb abr → 172 195
ventas[-1]             # todo menos la 1:   feb mar abr
ventas[ventas > 165]   # condición lógica:  feb mar abr
ventas["mar"]          # por nombre:        mar → 168
which(ventas > 165)    # ¿en qué POSICIONES? 2 3 4

# Los corchetes también escriben:
ventas["mar"] <- 170          # corregir un dato puntual
ventas[ventas < 160] <- NA    # marcar sospechosos de un golpe
ventas
# ene feb mar abr
#  NA 172 170 195

4. Vectorización: el superpoder

En la mayoría de lenguajes, para aplicar el IVA a 4 precios escribirías un bucle. En R, las operaciones actúan sobre todo el vector a la vez — y el 'bucle' ocurre internamente en código C compilado, por eso es más corto, más legible y más rápido. Cuando pienses 'necesito hacer X a cada elemento', tu primer reflejo no debe ser un bucle sino preguntarte si la operación ya es vectorizada: casi siempre lo es (+, *, sqrt(), round(), comparaciones, paste()...). Y la vectorización también opera entre DOS vectores, emparejando posición con posición — exactamente lo que harás entre columnas de una tabla. Mira cómo dos miradas al mismo dato cuentan historias distintas: el segundo producto deja el mayor margen absoluto, pero el tercero tiene el mejor margen relativo:

R
precios <- c(100, 250, 80, 120)
con_iva <- precios * 1.19       # una línea, sin índices, sin bucle
# [1] 119.0 297.5  95.2 142.8

costos <- c(80, 190, 60, 95)
margen <- precios - costos      # entre dos vectores, par a par
# [1] 20 60 20 25
round(margen / precios * 100, 1)  # margen % de cada producto
# [1] 20.0 24.0 25.0 20.8

5. Reciclaje: la regla y el peligro

¿Qué pasa si operas dos vectores de distinta longitud? R recicla el más corto: lo repite hasta alcanzar al largo. Es lo que hace que precios * 1.19 funcione (el 1.19 se recicla 4 veces). La regla: si la longitud mayor es múltiplo exacto de la menor, R recicla en silencio; si no, recicla igual pero advierte. Y ahí está la trampa: el peligro real no es la advertencia, sino el caso donde NO hay advertencia. Si sumas por accidente un vector de 12 meses con uno de 4 trimestres, las longitudes encajan (12 es múltiplo de 4), R no dice nada, y obtienes números plausibles pero incorrectos. Ante resultados sospechosos, lo primero: verificar longitudes con length():

R
c(1, 2, 3, 4) + c(10, 20)   # 4 es múltiplo de 2: recicla SIN avisar
# [1] 11 22 13 24

c(1, 2, 3) + c(10, 20)      # 3 no es múltiplo de 2: recicla Y advierte
# [1] 11 22 13
# Warning: longer object length is not a multiple of shorter object length

6. Los modismos del analista

Cierro con el ejemplo que junta todo: seis meses de ventas (en millones) y cinco preguntas de negocio respondidas en cinco líneas. Fíjate en dos modismos que usan todos los analistas de R: mean() de un vector lógico da la PROPORCIÓN de casos que cumplen (porque TRUE vale 1), y sum() de un lógico los CUENTA. Y un detalle fino en el crecimiento porcentual: la base es ventas[-6] (todos menos junio, porque el último mes no es base de nadie) — emparejar bien numerador y base es la diferencia entre un crecimiento correcto y uno desfasado un mes:

R
ventas <- c(ene = 150, feb = 172, mar = 168, abr = 195, may = 210, jun = 250)

cumsum(ventas)                     # acumulado: cierra el semestre en 1145
diff(ventas)                       # variación mensual: solo marzo cayó (-4)
# feb mar abr may jun
#  22  -4  27  15  40
round(diff(ventas) / ventas[-6] * 100, 1)  # crecimiento % mes a mes
#  feb  mar  abr  may  jun
# 14.7 -2.3 16.1  7.7 19.0
names(ventas)[which.max(ventas)]   # el mejor mes → "jun"
mean(ventas > 180)                 # proporción sobre la meta → 0.5
Índice de la serieR: de cero a investigación reproducible

3 de 12 capítulos publicados

  1. 01R básico: aprende R desde cero
  2. 02RStudio como un profesional
  3. 03Vectores: el modelo mental que sostiene todo REstás aquí
  4. 04Tipos de datos y coerción: por qué 0.1 + 0.2 != 0.3Próximamente
  5. 05Factores: la trampa de as.numeric()Próximamente
  6. 06Listas: [ vs [[ vs $ (y por qué un modelo es una lista)Próximamente
  7. 07Importar datos en Latinoamérica: punto y coma, coma decimal y tildesPróximamente
  8. 08Transformar datos con dplyr y tidyrPróximamente
  9. 09Funciones propias y tryCatch: pipelines que no se caenPróximamente
  10. 10data.table vs. dplyr: cuándo usar cada unoPróximamente
  11. 11Tu checklist de EDA reutilizablePróximamente
  12. 12Quarto y Git: publicar un análisis reproduciblePróximamente
Capítulo 2RStudio como un profesional
Capítulo 4 · PróximamenteTipos de datos y coerción: por qué 0.1 + 0.2 != 0.3

También te puede interesar