01 · R 语言数据类型与相应运算

1 变量与类型检查

在 R 里可以把“变量”理解成给一块数据贴上的标签:把一个数值、字符或逻辑值存到某个名字下面,后面就可以一直用这个名字来引用它。在中医药数据里,剂量药名是否复诊证型 等信息,都会被存成不同类型的变量。掌握如何创建变量、以及用函数检查它们的类型,是后面一切数据分析的起点。

1.1 创建变量(把数据存到名字里)

# 在中医处方数据里,“剂量”通常是数值
dose_g <- 10

# “药名”是字符
herb <- "黄芪"

# “是否复诊”可以用逻辑
revisit <- TRUE

1.2 类型查看函数

class(dose_g)
typeof(dose_g)
str(dose_g)

class(herb)
class(revisit)

2 数值:剂量与运算

数值型是医学数据中最常见的一类,包括药物剂量、体温、血压、实验室检验值、疗程天数等。R 里所有的数值最终都会以向量的形式存在,可以是一个数,也可以是一整列数据。熟悉整数/小数的表示方式,以及四则运算、取余、幂运算等,是进行剂量计算、指标换算和各种统计量(均值、方差、标准差)分析的基础。

2.1 整数(integer)与小数(double)

R 里 1 默认是小数类型(double),想表示整数可以写 1L

x <- 1
class(x)     # "numeric"(通常是 double)

i <- 1L
class(i)     # "integer"

2.2 常用运算(剂量/天数/分次)

# 假设:黄芪 30g,分 2 次
huangqi_g <- 30
times_per_day <- 2
each_time_g <- huangqi_g / times_per_day
each_time_g

# 取余:比如 7 天为一疗程,15 天能完整做几疗程?剩几天?
days <- 15
days %/% 7  # 完整疗程数
days %% 7   # 剩余天数

2.3 数值向量与“向量化运算”(一次算一串)

# 一张处方里 5 味药的剂量(单位 g)
doses <- c(15, 10, 6, 12, 3)

# 全部剂量加 1g(比如统一加量做对照)
doses + 1

# 计算每味药占总剂量的比例
doses / sum(doses)
说明:R 的多数运算支持向量化(vectorization),可直接对整组数据逐元素计算。

3 逻辑:筛选条件(TRUE / FALSE)

逻辑型变量只取 TRUE / FALSE(以及可能的缺失 NA),在医学数据中常用于表示“是否”类信息,例如“是否合并糖尿病”“是否为女性”“是否完成随访”等。比较运算和逻辑运算(>=&| 等)会生成一整列 TRUE/FALSE,配合下标就能完成数据筛选,是做“按条件取子集”的核心工具。

3.1 比较运算:会得到 TRUE/FALSE

age <- c(18, 20, 19, 22)
age >= 20

doses > 10
doses == 10

3.2 & 与 && 的区别

& 对向量逐个比较;&& 只看第一个元素(常用于 if)。

c(TRUE, FALSE) & c(TRUE, TRUE)
c(TRUE, FALSE) && c(TRUE, TRUE)

4 字符:药名与文本处理(character)

字符型变量用于存放文本信息,例如中药名、方剂名、证型描述、主诉和诊断等。和 Excel 一样,R 也可以对字符串做拼接、替换、截取等操作;配合正则表达式和 stringr 这类包,还能从中医病案全文中批量提取药名、剂量、证型标签,为后续结构化建库和文本挖掘做准备。

4.1 拼接与长度

herbs <- c("黄芪", "当归", "党参")
nchar(herbs)                 # 每个药名的字数
paste(herbs, "10g")          # 拼接(默认有空格)
paste0(herbs, "_10g")        # 拼接(不加空格)

4.2 替换与截取

s <- "当归 10g"
gsub("10g", "12g", s)
substr(s, 1, 2)              # 截取前 2 个字符

4.3 字符转数值(能转就转,不能转就 NA)

as.numeric("12")     # 12
as.numeric("12g")    # NA(转不了)

5 因子:证型分类(factor)

factor 专门用来表示“类别”型数据,是做统计建模时非常关键的一种类型。像 性别(男/女)证型(气虚/血虚/痰湿/湿热…)分组(对照/实验) 等,都适合存成因子而不是普通字符。因子带有 levels(水平)和可能的顺序关系(有序因子),很多统计函数会根据这些水平自动生成分组统计或虚拟变量。

5.1 levels 与频数

# 证型(分类变量)
zheng <- factor(c("气虚", "血虚", "气虚", "湿热", "气虚"))
levels(zheng)
table(zheng)   # 每类出现几次

5.2 因子常见坑:别把因子当字符串乱拼

z <- factor(c("A", "B", "A"))
paste0("组别=", z)              # 会工作,但很多文本处理建议先转字符
paste0("组别=", as.character(z))

6 缺失值:NA(真实临床数据非常常见)

真实世界的医学数据几乎不可能“完完整整”,量血压忘记记录舒张压、实验室报告缺乏某项指标、随访病人失访,这些都需要在 R 中用 NA 来表示“缺失”。一旦数据里出现 NA,很多运算(如 meansum)默认都会给出 NA 作为结果,因此要学会先用 is.na() 找出缺失,再用 na.rm = TRUE 或其他方法进行恰当处理。

6.1 is.na:找出缺失

# 比如:某味药剂量未记录
doses2 <- c(10, NA, 6, 12)
is.na(doses2)
sum(is.na(doses2))

6.2 na.rm:统计时忽略 NA

mean(doses2)                 # NA
mean(doses2, na.rm = TRUE)   # 正常数值
注意:缺失值判断应使用 is.na();表达式 NA == NA 的结果仍为 NA

7 常见容器:用“处方表”理解 vector / list / data.frame

到目前为止出现的各种类型(数值、字符、逻辑、因子)最终都要放进“容器”里,才构成完整的数据结构。在 R 中,最常用的三种基础容器是:一列同类型数据的 vector,能装下一个病例全部信息的 list,以及把很多病例按“行 × 列”排成表格的 data.frame。可以把它们类比为:单列处方剂量表、单个病历卡片、以及整张门诊登记或临床试验数据表。

7.1 vector:一列同类型

# 一列“剂量”(同类型)
dose_col <- c(10, 12, 9, 15)

7.2 list:病人信息的复合记录

patient <- list(
  id = "P001",
  age = 19,
  zheng = "气虚",
  herbs = c("黄芪", "党参", "白术"),
  doses = c(30, 15, 12)
)

patient$id
patient$herbs
patient$doses

7.3 data.frame:处方数据表(最常用)

在医学统计与数据挖掘中,最常见的原始数据形式,就是“像 Excel/数据库那样”的表格:每一行是一条记录(例如一位患者一次就诊或一次随访),每一列是一个变量(如年龄、性别、证型、化验指标、用药剂量等),不同列可以是不同类型的数据。

在 R 语言里,这种“行 = 观测、列 = 变量”的结构就叫做 数据框(data.frame)。它可以看作是一个特殊的 list:每一列本质上都是一个长度相同的向量(数值、因子、字符、日期时间等),同一列中的数据类型必须一致,而不同列之间可以是不同的数据类型。这种设计非常适合承载临床试验数据表、门诊登记表、体检数据等各种医学原始数据。

rx <- data.frame(
  patient_id = c("P001", "P002", "P003"),
  zheng = factor(c("气虚", "湿热", "血虚")),
  formula = c("补中益气汤", "三仁汤", "四物汤"),
  herb = c("黄芪", "薏苡仁", "当归"),
  dose_g = c(30, 20, 10),
  stringsAsFactors = FALSE
)

rx
rx$dose_g
rx[1, ]
rx[, c(\"patient_id\", \"formula\", \"dose_g\")]

8 练习

  1. 创建向量 d <- c(30, 15, NA, 12, 9),求总剂量(忽略 NA)。
  2. 创建字符向量 h <- c(\"黄芪\", \"当归\"),拼出 \"黄芪_当归\"
  3. 创建因子 z <- factor(c(\"气虚\",\"血虚\",\"气虚\")),输出频数。
  4. 在上面的 rx 表里,筛出 dose_g >= 20 的行(示例:rx[rx$dose_g >= 20, ])。
练习入口:01 · R 语言数据类型与运算(练习页)(含入门四段 + 字符/因子/NA/容器加餐,可直接复制代码到 RStudio)。
要点:本节要求能够区分 vector / data.frame / list,并掌握 is.na() 与向量化运算的基本用法。