R基础回顾(一):向量、矩阵、列表、数据框

咱们正式开始动手前,得先把R的几种核心数据结构捋清楚。别担心,不是枯燥的理论课。我自己的经验是,这几种结构搞明白了,后面写Shiny app的时候,数据怎么流转、怎么变形,心里就有底了。

说白了,R里数据就四种基本容器:向量、矩阵、列表、数据框。它们各有各的脾气,选对了事半功倍。

核心结论一句话:向量同类型、矩阵二维同类型、列表啥都能装、数据框像Excel表格。

向量 —— 最基础的单元

向量是R里最基本的对象。就是个一维的同类型元素集合。记住,是同类型。数值、字符、逻辑,混一起会自动转换,这个坑我踩过。

创建向量用 c() 函数,全称是 combine。

# 数值向量
my_numbers <- c(1, 3, 5, 7, 9)

# 字符向量
my_genes <- c("TP53", "BRCA1", "EGFR")

# 逻辑向量
my_flags <- c(TRUE, FALSE, TRUE)

# 向量运算
my_numbers * 2   # 所有元素乘以2
sqrt(my_numbers) # 对每个元素开平方
我个人习惯在创建向量时直接赋好名字,方便后面索引。
exp_values <- c(TP53 = 12.5, BRCA1 = 8.3, EGFR = 0.5)
exp_values["TP53"]  # 按名字取,清晰多了

矩阵 —— 二维的同类型表格

矩阵其实就是一个加了维度属性的向量。它要求所有元素类型一致,这在处理表达矩阵时很常见。

创建方式有两种,我常用 matrix()。

# 创建一个3行4列的矩阵
mat <- matrix(1:12, nrow = 3, ncol = 4)
mat

# 指定是按行填充还是按列填充
mat_byrow <- matrix(1:12, nrow = 3, byrow = TRUE)

# 给行列加名字
rownames(mat) <- c("GeneA", "GeneB", "GeneC")
colnames(mat) <- c("Sample1", "Sample2", "Sample3", "Sample4")

矩阵运算在差异分析里经常用到。比如计算行均值、列均值。

rowMeans(mat)  # 每个基因的平均表达量
colMeans(mat)  # 每个样本的平均表达量
我曾经在合并两个表达矩阵时,忘了检查基因顺序是否一致,结果算出来的差异基因全是错的。后来养成习惯:每次合并前先用 rownames() 核对一遍。

列表 —— 灵活的大杂烩

列表是R里最灵活的数据结构。它允许你往一个对象里塞不同类型、不同长度、甚至不同维度的东西。你想想看,这不就是为复杂数据准备的嘛。

# 创建列表
my_list <- list(
  gene_name = "TP53",
  expression = c(12.5, 8.3, 0.5, 6.7),
  is_significant = TRUE,
  p_value = 0.003
)

# 访问列表元素(两种方式)
my_list$expression
my_list[["expression"]]

差异分析的结果,比如 DESeq2 输出的对象,本质上就是一个大列表。里面装着结果表、归一化计数、模型拟合信息等等。

避坑指南:用 [] 和 [[]] 取列表元素,结果可不一样。[] 返回的还是列表,[[]] 才取出里面的实际数据。别搞混了。

数据框 —— 最常用的结构

这才是咱们的日常。数据框看起来像矩阵,但每列可以是不同类型。你在Excel里看到的表,到R里就是数据框。

咱们做差异分析,结果表就是一个数据框。基因名是字符列,log2FC是数值列,p值也是数值列,还有判断是否显著的逻辑列。

# 创建数据框
de_results <- data.frame(
  gene = c("TP53", "BRCA1", "EGFR", "MYC"),
  log2FC = c(2.5, -1.3, 0.8, 3.1),
  pvalue = c(0.001, 0.04, 0.12, 0.0005),
  significant = c(TRUE, TRUE, FALSE, TRUE)
)

# 查看结构
str(de_results)

# 提取列
de_results$log2FC
de_results[, "log2FC"]

# 筛选行
de_results[de_results$pvalue < 0.05, ]

讲到这里,你可能已经发现了一个规律:数据框里的每一列,本质上都是一个向量。这才有了列操作的一致性。

四种结构的选用逻辑

数据结构 维度 元素类型 适用场景
向量 一维 同类型 单个样本的表达值、p值列表、基因名列表
矩阵 二维 同类型 表达矩阵(所有值都是数值)
列表 递归 可混合 DEseq2/limma 输出对象、复杂分析结果
数据框 二维 每列同类型 差异表达结果表、样本元数据、日常数据分析

清楚了这些差别,你在写Shiny app时就知道:传参用列表、建图表用数据框、存表达值用矩阵。各司其职,代码才清爽。

R基础数据结构体系 R数据结构 向量 (vector) 矩阵 (matrix) 列表 (list) 数据框 (data.frame) 一维,同类型 c() 创建 二维,同类型 matrix() 创建 可混合类型 list() 创建 列可不同类型 data.frame() 创建

实际项目中怎么选?

我举个例子。你在做差异表达分析,流程大概是:

  1. 原始数据读进来,是个数据框(因为列类型不同:样本名是字符,表达值是数值)。
  2. 提取表达值那几列,变成矩阵(方便做数学运算,比如log2转换)。
  3. 跑差异分析(比如DESeq2),结果是个列表(里面装着各种中间结果、统计检验输出)。
  4. 把最终结果表(基因、log2FC、p值等)又转回数据框(方便在Shiny里展示和筛选)。

你看,一圈下来,四种结构都用上了。你想想看,如果在第三步你非要把列表当数据框用,代码是不是就拧巴了?

小技巧:数据框转矩阵用 as.matrix(),矩阵转数据框用 as.data.frame()。但是注意,字符列会强制转换整个矩阵为字符类型,别把数值弄丢了。

嗯,到这里核心内容差不多了。这些基础结构是你做差异分析、搭Shiny界面的地基。多操练几遍,写代码时手自然就顺了。