04生成序列、抽样、排序与分批

使用 seq、rep、sample、sort、order、取余和整除生成向量、模拟数据、重排行列并建立固定大小的批次。

2026-04-06
RVectorsSequencesSamplingSorting
本章目录 · 6

生成编号、重复标签、随机样本和批次索引,都是在构造或重新排列向量。Base R 已经提供了这些基础操作,不需要为每种情况手写循环。

生成数值序列

seq() 可以按步长或目标长度生成序列:

seq(from = 1, to = 10, by = 2)
# [1] 1 3 5 7 9

seq(from = 1, to = 10, length.out = 3)
# [1] 1.0 5.5 10.0

从 1 生成到一个长度时,优先使用 seq_len()

seq_len(5)
# [1] 1 2 3 4 5

它在长度为 0 时返回空向量,而 1:n 会产生意外结果:

seq_len(0)
# integer(0)

1:0
# [1] 1 0

沿已有对象的位置生成索引,使用 seq_along()

x <- c("A", "B", "C")
seq_along(x)
# [1] 1 2 3

这两个函数适合循环和程序化代码,因为它们明确表达“长度”与“对象位置”。

重复元素与模式

rep()times 重复整个向量,each 重复每个元素:

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

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

生成分组标签:

group <- rep(c("Control", "Case"), each = 5)
sample_id <- paste0("Sample_", seq_along(group))

data.frame(sample_id, group)

如果目标长度已知,也可以使用 length.out

rep(c("A", "B"), length.out = 5)
# [1] "A" "B" "A" "B" "A"

随机抽样与模拟

sample() 从已有向量抽样:

set.seed(2025)

sample(1:100, size = 5)
sample(letters, size = 10, replace = TRUE)
  • replace = FALSE 表示无放回抽样;
  • replace = TRUE 表示同一元素可以多次被抽到;
  • set.seed() 让同一随机数算法下的结果可以复现。

模拟常见分布:

set.seed(2025)

uniform_values <- runif(5, min = 0, max = 10)
normal_values <- rnorm(5, mean = 5, sd = 2)

sample(x) 对长度为 1 的正整数有特殊行为:

sample(10)

这会从 1:10 中打乱抽样,而不是只返回数字 10。程序化代码若要抽取整数位置,可以明确使用 sample.int()

sample.int(n = 10, size = 3)

排序、反转与排序索引

x <- c(3, 1, 5, 2)

sort(x)
# [1] 1 2 3 5

sort(x, decreasing = TRUE)
# [1] 5 3 2 1

rev(x)
# [1] 2 5 1 3

sort() 返回排好序的值;order() 返回这些值在原向量中的位置:

order(x)
# [1] 2 4 1 3

x[order(x)]
# [1] 1 2 3 5

order() 特别适合按一个或多个变量重排行:

df <- data.frame(
  group = c("B", "A", "B", "A"),
  score = c(8, 9, 6, 7)
)

df[order(df$group, -df$score), ]

这里先按 group 升序,再按 score 降序。需要名次而不是重排顺序时,使用 rank()

取余与整除

17 %% 5
# [1] 2

17 %/% 5
# [1] 3
  • %% 返回余数;
  • %/% 返回整数商。

它们可以标记周期位置。例如每 5 个元素为一批:

x <- seq_len(20)
batch <- (x - 1) %/% 5 + 1

data.frame(x, batch)

公式中的 x - 1 先把从 1 开始的位置转为从 0 开始,再整除批大小,最后加 1 恢复从 1 开始的批次编号。

找出每批的第一个和最后一个位置:

x[(x - 1) %% 5 == 0]
# [1] 1 6 11 16

x[x %% 5 == 0]
# [1] 5 10 15 20

任意长度的对象按固定大小分批:

batch_size <- 7
batch_id <- (seq_along(x) - 1) %/% batch_size + 1

split(x, batch_id)

最后一批可以少于 batch_size。如果使用字符标签,应先根据实际批次数生成足够标签,避免下标超过标签向量长度。

一个完整示例

生成 12 个模拟样本,随机打乱顺序,再分成每批 5 个:

set.seed(2025)

samples <- data.frame(
  sample_id = paste0("Sample_", seq_len(12)),
  group = rep(c("Control", "Case"), each = 6),
  value = rnorm(12)
)

samples <- samples[sample(seq_len(nrow(samples))), ]
samples$batch <- (seq_len(nrow(samples)) - 1) %/% 5 + 1

samples[order(samples$batch, samples$sample_id), ]

这里的批次只是计算任务分块,不应被误当作实验设计中的 biological batch。后者需要在采样和实验阶段定义,不能靠行号事后生成。