2. R语言基础:数据类型、向量、矩阵、列表、数据框
好了,咱们正式开始动手。这一章,我带你捋一捋R语言的核心数据结构。说白了,这就是你后续所有操作的“地基”。
你可能会问:“为什么非要分清这些?不就是装数据吗?” 嗯,我刚开始用R时也这么想。直到有一次做药物靶点筛选,我把字符型向量直接丢进运算里,R给我吐了一堆NA。排查了一下午,最后发现是数据类型没对齐。所以,咱们从一开始就把它弄明白,省得后面踩坑。
2.1 数据类型:R里的“元素”长什么样
R里最基础的单位是“原子向量”,也就是单个元素。常见的有这么几类:
| 类型 | 示例 | 检查函数 | 说明 |
|---|---|---|---|
| 数值型 | 3.14, -2, 1e5 | is.numeric() |
默认双精度浮点数,整数也属于数值型 |
| 整型 | 1L, 42L | is.integer() |
加 L 后缀明确声明为整数 |
| 字符型 | "aspirin", 'drug' | is.character() |
用双引号或单引号包裹 |
| 逻辑型 | TRUE, FALSE | is.logical() |
比较运算的结果就是它 |
| 复数型 | 1 + 2i | is.complex() |
做频谱分析时才用,药物数据里很少见 |
我个人习惯拿到新数据后,先用 str() 扫描一遍结构,看一眼每个字段的类型。它能帮你提前发现那些“看起来是数字,实际上是字符”的坑。
# 快速检查数据类型
x <- 3.14
y <- "ibuprofen"
z <- TRUE
str(x) # 输出: num 3.14
str(y) # 输出: chr "ibuprofen"
str(z) # 输出: logi TRUE
2.2 向量:最常用的“一维容器”
向量是R里最基础的数据结构。你可以把它想象成一列同类型元素的集合。
核心规则: 向量里所有元素必须是同一种类型。如果混入不同类型,R会自动做“强制转换”。比如
c(1, "a"),数字1会被悄悄转成字符"1"。
2.2.1 创建与索引
# 创建向量
drug_names <- c("aspirin", "ibuprofen", "acetaminophen")
dose <- c(100, 200, 500)
is_active <- c(TRUE, FALSE, TRUE)
# 索引(R的索引从1开始,这点和Python不一样)
dose[1] # 100
dose[c(1, 3)] # 100, 500
dose[-2] # 去掉第二个元素,返回 100, 500
# 逻辑索引,工作中最常用
dose[dose > 150] # 返回 200, 500
你想想看,逻辑索引有多方便?筛选出那些满足条件的药物剂量,一行代码搞定。
2.2.2 向量化运算
R的向量化运算是我最喜欢的功能。不用写循环,直接对整个向量做运算。
dose_mg <- c(100, 200, 500)
dose_g <- dose_mg / 1000 # 返回 c(0.1, 0.2, 0.5)
# 字符串拼接
paste("drug", 1:3, sep = "_") # "drug_1" "drug_2" "drug_3"
2.3 矩阵:二维的“同质”表格
矩阵就是二维的向量。所有元素类型必须一致。做矩阵乘法、特征分解时用得比较多。
# 创建 3 行 4 列的矩阵,默认按列填充
m <- matrix(1:12, nrow = 3, ncol = 4)
rownames(m) <- c("drug_A", "drug_B", "drug_C")
colnames(m) <- c("site_1", "site_2", "site_3", "site_4")
m
# site_1 site_2 site_3 site_4
# drug_A 1 4 7 10
# drug_B 2 5 8 11
# drug_C 3 6 9 12
# 提取第2行第3列
m[2, 3] # 8
注意: 我在做药物-靶点互作矩阵时,曾不小心把字符和数字混在一个矩阵里。结果所有数值都被转成了字符串,后续的计算全乱了。矩阵只适合存单一类型的数据,如果混合类型,请用数据框。
2.4 列表:最能装的“万能口袋”
列表可以装任何东西——向量、矩阵、数据框,甚至是另一个列表。非常灵活,但用起来需要小心。
# 创建一个列表
patient_info <- list(
id = "P001",
drugs = c("aspirin", "ibuprofen"),
dosage = c(100, 200),
notes = "暂无不良反应"
)
# 提取元素:用 [[]] 或 $
patient_info$id # "P001"
patient_info[[2]] # c("aspirin", "ibuprofen")
patient_info[["drugs"]] # c("aspirin", "ibuprofen")
我这里经常用列表来封装一个药物的完整信息——名称、靶点、剂量、副作用,全都放在一个对象里。做复杂分析时非常方便。
2.5 数据框:药物知识图谱的主力
数据框是矩阵的升级版。每一列可以是不同的类型。说白了,它就像Excel里的表格。做药物知识图谱分析,数据框是绝对的主角。
# 创建数据框
drug_db <- data.frame(
drug_name = c("aspirin", "ibuprofen", "acetaminophen"),
target = c("COX1", "COX2", "COX3"),
half_life = c(0.25, 2.0, 2.5),
is_otc = c(TRUE, TRUE, TRUE),
stringsAsFactors = FALSE # 让字符串保持字符类型
)
str(drug_db)
# 'data.frame': 3 obs. of 4 variables:
# $ drug_name : chr "aspirin" "ibuprofen" ...
# $ target : chr "COX1" "COX2" ...
# $ half_life : num 0.25 2 2.5
# $ is_otc : logi TRUE TRUE TRUE
关键操作:
- 用
drug_db$drug_name提取列 - 用
drug_db[drug_db$half_life > 1, ]筛选行 - 用
subset(drug_db, target == "COX2")条件筛选
2.6 一张图理清关系
下面这张SVG图,帮你把这一章的结构串起来。从上到下看,从基础数据类型到容器递进,非常清晰。
2.7 避坑指南 & 核心技巧
- 类型检查:拿到数据先跑
str()和class()。我曾经吃过字符型当数值用的亏。 - 强制转换:R 的转换规则是:逻辑 < 整数 < 数值 < 字符。低级别向高级别自动转。
- 索引效率:用逻辑向量做索引,比写循环快得多。数据量大时差距明显。
- 数据框选列:能用
$就用$,可读性最好。如果列名有空格,用反引号包裹`列名`。 - 列表递归:提取列表元素时
[]返回子列表,[[]]去掉一层包装。这个区别,我大概花了半小时才彻底理解。
一句话总结:
向量是基础,数据框是核心,列表做扩展。做个药物知识图谱分析,80% 的操作都在数据框上。把这一章练好,后面讲 tidyverse 和 dplyr 时,你会感觉非常顺畅。