seq() y rep() en R: crear secuencias y repetir vectores

Introducción a R Estructuras de datos
Crear secuencias y repetir valores en R con seq y rep

Crear secuencias de números y repetir valores son dos de las tareas más habituales en R. En este tutorial aprenderás a usar el operador :, la función seq y sus versiones rápidas seq_len y seq_along, y la función rep con sus argumentos times, each y length.out. También verás los errores que provocan más fallos: la precedencia de :, la sorpresa de los decimales en coma flotante con seq y el bucle 1:length(x) sobre un vector vacío.

El operador :

La forma más rápida de crear una secuencia de números en R es el operador :, que devuelve todos los valores desde el primer número hasta el segundo de 1 en 1:

1:10
5:1    # Secuencia decreciente
-2:2
1.5:4  # De 1 en 1, se para antes de pasar de 4
 [1]  1  2  3  4  5  6  7  8  9 10
[1] 5 4 3 2 1
[1] -2 -1  0  1  2
[1] 1.5 2.5 3.5

Fíjate en que si el primer valor es mayor que el segundo, : cuenta hacia atrás en lugar de devolver un vector vacío. A veces es útil, pero también es el origen del error en bucles que verás más adelante. Cuando los dos valores son enteros, el resultado es un vector de tipo entero.

Precedencia del operador :

El operador : tiene más precedencia que los operadores aritméticos +, -, * y /, pero menos que ^ y el signo menos unario. Esto significa que 1:n-1 no es “de 1 a n - 1”, sino “la secuencia de 1 a n, menos 1”:

n <- 5

1:n-1    # (1:n) - 1
1:(n-1)  # Lo que probablemente querías
[1] 0 1 2 3 4
[1] 1 2 3 4

Lo mismo ocurre con otras operaciones. Fíjate en los siguientes ejemplos:

2*1:3    # 2 * (1:3)
-1:3     # (-1):3, el menos se aplica antes al 1
-(1:3)
1:n^2    # 1:(n^2), la potencia va primero
[1] 2 4 6
[1] -1  0  1  2  3
[1] -1 -2 -3
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

Cuando los límites de una secuencia son expresiones, usa siempre paréntesis: 1:(n - 1), (i + 1):n. No cuestan nada y evitan el error más frecuente con :. Tienes la tabla completa de precedencias en el tutorial de operadores en R.

La función seq

Cuando necesitas un paso distinto de 1 o un número fijo de valores, usa la función seq. Su sintaxis es la siguiente:

seq(from = 1,        # Valor inicial
    to = 1,          # Valor final
    by,              # Incremento de la secuencia
    length.out,      # Longitud deseada de la secuencia
    along.with)      # Toma la longitud de este objeto

Lo normal es indicar from, to y uno de los dos argumentos by o length.out. Si indicas todos, R devolverá el error too many arguments, porque la secuencia estaría sobredeterminada.

Secuencias con un paso dado: by

El argumento by fija el incremento entre valores consecutivos. La secuencia empieza en from y termina en el último valor que no supera to:

seq(1, 10, by = 2)
seq(0, 100, by = 25)
seq(1, 10, by = 4)   # No llega al 10
[1] 1 3 5 7 9
[1]   0  25  50  75 100
[1] 1 5 9

Para una secuencia decreciente el paso tiene que ser negativo. Si pones un by positivo cuando from es mayor que to, R da un error:

seq(10, 1, by = -3)
seq(10, 1, by = 3)
[1] 10  7  4  1
Error in seq.default(10, 1, by = 3) : wrong sign in 'by' argument

Sin by, seq(10, 1) funciona como 10:1 y cuenta hacia atrás de 1 en 1.

Secuencias con una longitud dada: length.out

A veces no te importa el paso, sino el número de valores. En ese caso usa length.out (puedes abreviarlo como length) y R calculará el paso por ti:

seq(0, 1, length.out = 5)
seq(2, 20, length.out = 4)
seq(1, 2, length.out = 4)
[1] 0.00 0.25 0.50 0.75 1.00
[1]  2  8 14 20
[1] 1.000000 1.333333 1.666667 2.000000

Con length.out los dos extremos se incluyen siempre, algo que con by no está garantizado. Es la opción que te interesa cuando creas una rejilla de valores para un gráfico.

Secuencias con decimales y la sorpresa de la coma flotante

Puedes crear secuencias con pasos decimales, pero ten cuidado cuando compares el resultado con otros números. La siguiente secuencia parece perfecta, pero ninguno de sus elementos es igual a 0.3:

x <- seq(0, 1, by = 0.1)
x

x[4]
x[4] == 0.3
which(x == 0.3)
 [1] 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0
[1] 0.3
[1] FALSE
integer(0)

El motivo es que números como 0.1 no se pueden representar de forma exacta en binario, así que seq acumula pequeños errores. R muestra el valor redondeado, pero si pides más dígitos puedes ver el valor real:

print(x[4], digits = 17)
[1] 0.30000000000000004

Para comparar números decimales usa una tolerancia, redondea antes los valores o utiliza all.equal:

which(abs(x - 0.3) < 1e-8)       # Tolerancia
which(round(x, 10) == 0.3)       # Redondeo
isTRUE(all.equal(x[4], 0.3))     # all.equal
[1] 4
[1] 4
[1] TRUE

seq con un único argumento tiene un comportamiento confuso. seq(10) devuelve 1:10, pero si le pasas un vector de longitud mayor que 1 devuelve sus índices: seq(c(2, 7)) devuelve 1 2, no los números del 2 al 7. Si x puede tener uno o varios elementos, seq(x) se comportará de forma distinta según su longitud. Usa seq_len o seq_along en su lugar.

Las funciones seq_len y seq_along

seq_len(n) crea la secuencia de enteros de 1 a n, y seq_along(x) crea la secuencia de 1 a la longitud de x. Son más rápidas que seq y, sobre todo, tratan bien el caso de longitud 0:

seq_len(5)
seq_len(0)

x <- c(10, 20, 30)
seq_along(x)
[1] 1 2 3 4 5
integer(0)
[1] 1 2 3

Fíjate en que seq_len(0) devuelve un vector vacío, mientras que 1:0 devuelve 1 0. Esa diferencia es el motivo para preferir estas funciones.

El error de 1:length(x) en los bucles for

Mucha gente escribe los bucles for con for (i in 1:length(x)). Funciona mientras x tenga al menos un elemento, pero si x está vacío el bucle se ejecuta dos veces, con i = 1 e i = 0:

x <- numeric(0) # Vector vacío

length(x)
for (i in 1:length(x)) {
  print(paste("Iteración", i, "- valor:", x[i]))
}
[1] 0
[1] "Iteración 1 - valor: NA"
[1] "Iteración 0 - valor: "

En un script real el cuerpo del bucle trabajaría con un NA y con un elemento vacío, y el error (o el resultado incorrecto) aparecería lejos de su causa. Con seq_along el bucle simplemente no se ejecuta cuando el vector está vacío, y funciona con normalidad en el resto de casos:

x <- numeric(0)
for (i in seq_along(x)) {
  print(paste("Iteración", i, "- valor:", x[i]))
}

x <- c(4, 7, 1)
for (i in seq_along(x)) {
  print(paste("Iteración", i, "- valor:", x[i]))
}
[1] "Iteración 1 - valor: 4"
[1] "Iteración 2 - valor: 7"
[1] "Iteración 3 - valor: 1"

Lo mismo pasa con las filas de un data frame. Un filtro puede devolver cero filas sin que te des cuenta. Por ejemplo, ningún día de airquality tiene una temperatura superior a 100 ºF:

calor <- subset(airquality, Temp > 100)
nrow(calor)

1:nrow(calor)        # Mal: recorre las filas 1 y 0
seq_len(nrow(calor)) # Bien: ninguna iteración
[1] 0
[1] 1 0
integer(0)

Regla práctica: usa seq_along(x) para recorrer los elementos de un vector o una lista, y seq_len(nrow(df)) o seq_len(n) cuando lo que tienes es un número.

La función rep

La función rep repite los elementos de un vector o de una lista. Su sintaxis es la siguiente:

rep(x,          # Vector o lista a repetir
    times,      # Número de veces que se repite el vector entero (o cada elemento)
    each,       # Número de veces que se repite cada elemento
    length.out) # Longitud deseada del resultado

La diferencia entre times y each está en el orden del resultado: times repite el vector entero, mientras que each repite cada elemento antes de pasar al siguiente.

rep(1:3, times = 2)
rep(1:3, each = 2)
[1] 1 2 3 1 2 3
[1] 1 1 2 2 3 3

Como times es el segundo argumento, rep(1:3, 2) es lo mismo que rep(1:3, times = 2). Aun así, escribe el nombre del argumento: cuando vuelvas al código lo entenderás mucho mejor.

Un número de repeticiones distinto para cada elemento

Si times es un vector con la misma longitud que x, cada elemento se repite el número de veces correspondiente. Es muy útil para crear grupos de distinto tamaño:

rep(1:3, times = c(3, 1, 2))
rep(c("A", "B"), times = c(3, 2))
[1] 1 1 1 2 3 3
[1] "A" "A" "A" "B" "B"

Combinar each, times y length.out

Puedes combinar each y times. En ese caso R aplica primero each y después repite el resultado times veces. Con length.out el resultado se corta (o se recicla) hasta la longitud deseada:

rep(1:3, each = 2, times = 2)
rep(1:3, length.out = 7)
 [1] 1 1 2 2 3 3 1 1 2 2 3 3
[1] 1 2 3 1 2 3 1

length.out es práctico cuando la longitud del resultado no depende del número de repeticiones, por ejemplo, para crear un patrón alterno en un vector de 7 elementos. Si indicas length.out, el argumento times se ignora.

Repetir caracteres y factores para crear grupos

rep funciona con cualquier tipo de vector, no solo con números. Un caso típico es crear la columna de grupo de un conjunto de datos, como en un diseño experimental con 3 grupos y 2 réplicas:

data.frame(grupo = rep(c("ctrl", "trt1", "trt2"), each = 2),
           replica = rep(1:2, times = 3))
  grupo replica
1  ctrl       1
2  ctrl       2
3  trt1       1
4  trt1       2
5  trt2       1
6  trt2       2

Fíjate en cómo trabajan juntos each y times: el grupo cambia cada 2 filas y el número de réplica va 1, 2, 1, 2… Si repites un factor, el resultado conserva los niveles:

f <- factor(c("bajo", "alto", "bajo"), levels = c("bajo", "alto"))
rep(f, times = 2)
[1] bajo alto bajo bajo alto bajo
Levels: bajo alto

Para crear directamente un factor de grupos también tienes la función gl (generate levels), que equivale a factor(rep(..., each = ...)):

gl(3, 2, labels = c("ctrl", "trt1", "trt2"))
[1] ctrl ctrl trt1 trt1 trt2 trt2
Levels: ctrl trt1 trt2

Invertir una secuencia con rev

Para invertir el orden de una secuencia (o de cualquier vector) usa rev. Es la opción más sencilla cuando ya tienes la secuencia y no quieres reescribir la llamada a seq:

rev(1:5)
rev(seq(0, 1, by = 0.25))
[1] 5 4 3 2 1
[1] 1.00 0.75 0.50 0.25 0.00

Ten en cuenta que rev solo invierte el orden de los elementos. Si quieres ordenarlos de mayor a menor, usa sort con decreasing = TRUE.

Casos de uso habituales

Crear datos de ejemplo

Combinando seq_len, rep y un generador aleatorio puedes crear en pocas líneas un conjunto de datos pequeño para probar tu código. Recuerda fijar una semilla si quieres obtener siempre los mismos valores:

set.seed(1)
datos <- data.frame(id = seq_len(6),
                    grupo = rep(c("A", "B"), each = 3),
                    valor = round(rnorm(6, mean = 10, sd = 2), 1))
datos
  id grupo valor
1  1     A   8.7
2  2     A  10.4
3  3     A   8.3
4  4     B  13.2
5  5     B  10.7
6  6     B   8.4

También puedes construir identificadores combinando una secuencia con paste0, por ejemplo paste0("ID_", seq_len(5)), que devuelve "ID_1" "ID_2" "ID_3" "ID_4" "ID_5".

Rejilla de valores para dibujar una curva

Para dibujar una función matemática o una densidad, como las de la distribución normal o la distribución F, necesitas una rejilla de valores para el eje X. Usa seq con length.out, porque el número de puntos determina lo suave que se ve la curva:

x_gruesa <- seq(-3, 3, length.out = 7)
x_fina <- seq(-3, 3, length.out = 200)

plot(x_fina, dnorm(x_fina), type = "l", lwd = 2, col = "blue",
     xlab = "x", ylab = "Densidad")
lines(x_gruesa, dnorm(x_gruesa), type = "b", lwd = 2, col = "red", pch = 19)
legend("topright", legend = c("length.out = 200", "length.out = 7"),
       col = c("blue", "red"), lwd = 2, box.lty = 0)

Densidad normal dibujada con una rejilla de 7 y 200 valores creada con seq en R

Con 7 puntos la curva es un polígono. Para la mayoría de gráficos bastan entre 100 y 500 puntos.

seq también funciona con fechas. Por ejemplo, seq(as.Date("2026-01-01"), by = "month", length.out = 4) devuelve el primer día de los cuatro primeros meses de 2026. Puedes aprender más en el tutorial de fechas en R.

¿Qué función deberías usar?

En la siguiente tabla tienes un resumen de las opciones para crear secuencias y repeticiones en R:

Código Resultado Cuándo usarlo
1:5 1 2 3 4 5 Secuencias rápidas de enteros con límites fijos
seq(1, 10, by = 3) 1 4 7 10 Un paso dado, incluso decimal o negativo
seq(0, 1, length.out = 5) 0 0.25 0.5 0.75 1 Un número de valores dado, como rejillas para gráficos
seq_len(n) 1 … n (vacío si es 0) Bucles e índices cuando tienes un número
seq_along(x) 1 … length(x) Bucles sobre los elementos de un vector o lista
rep(x, times = 2) 1 2 3 1 2 3 Repetir el vector entero
rep(x, each = 2) 1 1 2 2 3 3 Repetir cada elemento (etiquetas de grupo)
rep(x, length.out = 7) 1 2 3 1 2 3 1 Reciclar un patrón hasta una longitud fija
rev(x) 3 2 1 Invertir el orden de un vector existente

En la tabla, x es 1:3. Como regla general, usa : solo con límites constantes, seq_len y seq_along en bucles y funciones, y seq cuando necesites un paso o una longitud distintos de los de por defecto.