生成编号、重复标签、随机样本和批次索引,都是在构造或重新排列向量。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。后者需要在采样和实验阶段定义,不能靠行号事后生成。