第一章:R与RStudio环境搭建

1.1 R语言简介与特点

什么是R语言?

R语言是一种专门用于统计分析数据可视化的编程语言。简单来说,它是一个强大的”计算器”,不仅能做加减乘除,还能处理复杂的数据分析任务。

R语言的主要特点

  1. 免费开源:任何人都可以免费使用和修改
  2. 专为数据分析设计:内置大量统计函数
  3. 丰富的扩展包:全球开发者贡献了数万个扩展包
  4. 强大的可视化能力:可以绘制精美的统计图形
  5. 活跃的社区:遇到问题很容易找到解决方案

R语言能做什么?

  • 数据清洗和整理
  • 统计分析和假设检验
  • 机器学习建模
  • 数据可视化(图表制作)
  • 生物信息学分析(基因数据处理)
  • 生成自动化报告

1.2 R软件的下载与安装

下载R软件

  1. 访问CRAN官网:https://cran.r-project.org/
  2. 根据你的操作系统选择对应版本:
    • Windows用户:点击”Download R for Windows”
    • Mac用户:点击”Download R for macOS”
    • Linux用户:选择对应的发行版
  3. 下载最新版本的安装包

安装步骤(Windows)

  1. 双击下载的安装文件
  2. 选择安装语言(建议选择中文或英文)
  3. 点击”下一步”接受许可协议
  4. 选择安装路径(建议不要安装在中文路径下)
  5. 选择组件(默认即可)
  6. 选择启动选项(建议选择”No”以自定义设置)
  7. 完成安装

提示:安装路径中避免出现中文和空格,例如 C:\Program Files\R\R-4.x.x 是推荐的路径格式。


1.3 RStudio的下载、安装与界面介绍

什么是RStudio?

RStudio是R语言的集成开发环境(IDE)。如果把R比作汽车的发动机,那么RStudio就是一辆完整的汽车——它让R更易用、更美观、功能更强大。

为什么需要RStudio?

虽然R自带了一个简单的界面,但RStudio提供了: - 代码高亮显示(不同颜色区分代码元素) - 代码自动补全 - 项目管理功能 - 内置帮助系统 - 更好的图形显示

下载RStudio

  1. 访问:https://posit.co/download/rstudio/
  2. 选择免费版本(RStudio Desktop Free)
  3. 下载对应操作系统的安装包

安装RStudio

安装过程非常简单,按照向导点击”下一步”即可。重要提示:必须先安装R,再安装RStudio


1.4 RStudio主要面板介绍

打开RStudio后,你会看到四个主要面板:

左上角:脚本编辑器(Source)

这是你编写代码的地方。你可以: - 创建新的R脚本文件(File → New File → R Script) - 保存代码以便下次使用 - 选中代码按 Ctrl+Enter 运行

左下角:控制台(Console)

这是执行代码的地方。你可以: - 直接输入代码并按回车执行 - 查看代码运行结果 - 查看错误和警告信息

# 这是一个简单的加法运算
# R会自动计算并输出结果
1 + 1
## [1] 2

右上角:环境/历史(Environment/History)

  • Environment:显示当前创建的所有变量和数据
  • History:记录你执行过的所有命令

右下角:多用途面板

包含多个标签页: - Files:文件浏览器,显示当前目录的文件 - Plots:显示绘制的图形 - Packages:管理已安装的R包 - Help:查看函数帮助文档 - Viewer:显示本地网页内容


1.5 R项目的创建与管理(.Rproj)

什么是R项目?

R项目是RStudio提供的一种工作组织方式。它将所有相关的代码、数据、结果保存在一个文件夹中,方便管理和分享。

为什么使用R项目?

  1. 自动设置工作目录:打开项目自动定位到项目文件夹
  2. 保持工作独立:不同项目之间互不干扰
  3. 方便分享:整个项目文件夹可以直接分享给他人
  4. 版本控制友好:便于与Git配合使用

创建R项目

  1. 点击菜单:File → New Project
  2. 选择”New Directory”(新建目录)或”Existing Directory”(已有目录)
  3. 输入项目名称,选择保存位置
  4. 点击”Create Project”

创建后会生成一个 .Rproj 文件,双击它即可打开整个项目。


1.6 工作目录的查看与设置

什么是工作目录?

工作目录是R默认读取和保存文件的文件夹。就像你在电脑上有一个”我的文档”文件夹一样,R也需要知道从哪里找文件、把文件存到哪里。

查看当前工作目录

使用 getwd() 函数:

# getwd() 函数用于获取当前工作目录
# 工作目录是R默认读取和保存文件的文件夹
getwd()
## [1] "C:/Users/XTS-green/Desktop/medical_student_rescue_plan-main/R语言与生信分析/R语言/001R语言基础"

设置工作目录

使用 setwd() 函数:

# setwd() 函数用于设置工作目录
# 注意:Windows系统中路径使用正斜杠 / 或双反斜杠 \\
# 单反斜杠 \ 会被R识别为转义字符,导致错误
setwd("C:/Users/你的用户名/Documents/my_project")

注意:Windows系统中路径使用正斜杠 / 或双反斜杠 \\,不能使用单反斜杠 \

在RStudio中设置工作目录

更简单的方法: 1. 点击菜单:Session → Set Working Directory → Choose Directory 2. 或在Files面板中导航到目标文件夹,点击”More” → “Set As Working Directory”


1.7 R语言的注释与代码排版

什么是注释?

注释是给人看的说明文字,R在执行代码时会忽略注释内容。注释的作用是: 解释代码的功能 标记重要信息 暂时禁用某些代码

如何写注释

使用 # 符号:

# 使用 <- 进行赋值,这是R语言最常用的赋值方式
# 将数值10存储到变量x中
x <- 10

# 使用变量x进行计算
# R会输出计算结果
x + 5
## [1] 15

代码排版建议

良好的代码排版让代码更易读:

# 创建数值向量x,包含1到5
x <- c(1, 2, 3, 4, 5)

# 创建数值向量y,包含偶数序列
y <- c(2, 4, 6, 8, 10)

# 计算向量x的平均值
mean_x <- mean(x)

# 计算向量y的平均值
mean_y <- mean(y)

# 将两个平均值相加
result <- mean_x + mean_y

# 输出结果
result
## [1] 9

排版原则

  1. 适当空行:不同功能的代码块之间空一行
  2. 合理缩进:使用Tab或2个空格缩进
  3. 有意义的变量名:变量名要能表达其含义
  4. 添加注释:复杂逻辑要添加说明

第二章:R语言基础语法与操作

2.1 表达式与赋值

什么是表达式?

表达式是可以被R计算并产生结果的代码片段。最简单的表达式就是数学运算:

# 加法表达式:1加2
1 + 2
## [1] 3
# 乘法表达式:3乘以4
3 * 4
## [1] 12
# 函数调用表达式:计算16的平方根
sqrt(16)
## [1] 4

什么是赋值?

赋值就是把一个值存储到变量中,以便后续使用。可以理解为给数据起一个名字。

赋值符号

R语言有多种赋值方式:

# 方式1:使用 <- 赋值(推荐)
# 将数值10存储到变量x中
x <- 10
x
## [1] 10
# 方式2:使用 = 赋值
# 将数值20存储到变量y中
y = 20
y
## [1] 20
# 方式3:使用 -> 赋值(从左向右)
# 将数值30存储到变量z中
30 -> z
z
## [1] 30

三种赋值符号的区别

符号 方向 推荐使用场景
<- 左箭头(向左赋值) R语言传统写法,推荐使用
= 等号 函数参数设置时使用
-> 右箭头(向右赋值) 较少使用,管道操作时可能用到
# 使用 <- 进行赋值并计算
# 先计算5+3得到8,再将8存储到result变量中
result <- 5 + 3
result
## [1] 8

2.2 基本算术运算

R支持所有常见的数学运算:

# 定义两个变量
a <- 10
b <- 3

# 加法:10 + 3 = 13
a + b
## [1] 13
# 减法:10 - 3 = 7
a - b
## [1] 7
# 乘法:10 * 3 = 30
a * b
## [1] 30
# 除法:10 / 3 = 3.333...
a / b
## [1] 3.333333
# 幂运算:10的3次方 = 1000
a ^ b
## [1] 1000
# 取余数:10除以3的余数 = 1
a %% b
## [1] 1
# 整除:10除以3的整数部分 = 3
a %/% b
## [1] 3

算术运算符总结

运算符 含义 示例 结果
+ 加法 5 + 3 8
- 减法 5 - 3 2
* 乘法 5 * 3 15
/ 除法 5 / 3 1.667
^ 幂运算 5 ^ 3 125
%% 取余数 5 %% 3 2
%/% 整除 5 %/% 3 1

2.3 关系运算

关系运算用于比较两个值,结果是逻辑值(TRUE或FALSE):

# 定义两个变量用于比较
x <- 5
y <- 10

# 大于:5 > 10 吗?结果为 FALSE
x > y
## [1] FALSE
# 小于:5 < 10 吗?结果为 TRUE
x < y
## [1] TRUE
# 大于等于:5 >= 5 吗?结果为 TRUE
x >= 5
## [1] TRUE
# 小于等于:10 <= 10 吗?结果为 TRUE
y <= 10
## [1] TRUE
# 等于:x的值等于5吗?结果为 TRUE
# 注意:判断相等用双等号 ==
x == 5
## [1] TRUE
# 不等于:x的值不等于5吗?结果为 FALSE
x != 5
## [1] FALSE

关系运算符总结

运算符 含义 示例
> 大于 5 > 3 返回 TRUE
< 小于 5 < 3 返回 FALSE
>= 大于等于 5 >= 5 返回 TRUE
<= 小于等于 5 <= 3 返回 FALSE
== 等于 5 == 5 返回 TRUE
!= 不等于 5 != 3 返回 TRUE

重要提示:判断相等用 ==(双等号),单等号 = 是赋值!


2.4 逻辑运算

逻辑运算用于组合多个条件

x <- 5

# 与运算(AND):两个条件都为TRUE才返回TRUE
# x > 3 且 x < 10 吗?结果为 TRUE
x > 3 & x < 10
## [1] TRUE
# 或运算(OR):只要有一个条件为TRUE就返回TRUE
# x < 3 或 x > 10 吗?结果为 FALSE
x < 3 | x > 10
## [1] FALSE
# 非运算(NOT):取反
# !TRUE 结果为 FALSE
!TRUE
## [1] FALSE
# 对逻辑表达式取反
# x > 10 为 FALSE,取反后为 TRUE
!(x > 10)
## [1] TRUE

逻辑运算符详解

# 定义两个逻辑变量
a <- TRUE
b <- FALSE

# 与运算:TRUE AND FALSE = FALSE
a & b
## [1] FALSE
# 或运算:TRUE OR FALSE = TRUE
a | b
## [1] TRUE
# 非运算:NOT TRUE = FALSE
!a
## [1] FALSE

单符号与双符号的区别

&/|&&/|| 的区别:

# 创建两个逻辑向量
x <- c(TRUE, FALSE, TRUE)
y <- c(FALSE, FALSE, TRUE)

# & 是向量化运算,对每个元素逐一进行AND运算
# TRUE & FALSE = FALSE, FALSE & FALSE = FALSE, TRUE & TRUE = TRUE
x & y
## [1] FALSE FALSE  TRUE
# && 是标量运算,只比较第一个元素
# TRUE && FALSE = FALSE
TRUE && FALSE
## [1] FALSE
# TRUE && TRUE = TRUE
TRUE && TRUE
## [1] TRUE
# || 是标量运算,只比较第一个元素
# TRUE || FALSE = TRUE
TRUE || FALSE
## [1] TRUE
运算符 说明
& 向量化AND,对每个元素进行运算
&& 标量AND,只用于单个逻辑值(if条件判断)
| 向量化OR,对每个元素进行运算
|| 标量OR,只用于单个逻辑值(if条件判断)

建议:处理向量时用 &|;if条件判断时用 &&||


2.5 常见数学函数

R内置了丰富的数学函数:

# 定义一个负数
x <- -4.5

# abs():取绝对值,|-4.5| = 4.5
abs(x)
## [1] 4.5
# sqrt():计算平方根,√16 = 4
sqrt(16)
## [1] 4
# log():自然对数(以e为底),ln(100) ≈ 4.605
log(100)
## [1] 4.60517
# log10():以10为底的对数,log10(100) = 2
log10(100)
## [1] 2
# log2():以2为底的对数,log2(8) = 3
log2(8)
## [1] 3
# exp():e的x次方,e^1 ≈ 2.718
exp(1)
## [1] 2.718282
# sin():正弦函数,sin(π/2) = 1
# pi 是R内置的圆周率常量
sin(pi/2)
## [1] 1
# cos():余弦函数,cos(0) = 1
cos(0)
## [1] 1
# tan():正切函数,tan(π/4) ≈ 1
tan(pi/4)
## [1] 1
# round():四舍五入到指定小数位
# 将3.14159保留2位小数 = 3.14
round(3.14159, 2)
## [1] 3.14
# ceiling():向上取整,3.2 → 4
ceiling(3.2)
## [1] 4
# floor():向下取整,3.8 → 3
floor(3.8)
## [1] 3
# sign():符号函数,负数返回-1,正数返回1,零返回0
sign(-5)
## [1] -1

数学函数总结

函数 功能 示例
abs(x) 绝对值 abs(-5) = 5
sqrt(x) 平方根 sqrt(16) = 4
log(x) 自然对数 log(2.718) ≈ 1
log10(x) 以10为底的对数 log10(100) = 2
log2(x) 以2为底的对数 log2(8) = 3
exp(x) e的x次方 exp(1) ≈ 2.718
sin(x) 正弦 sin(0) = 0
cos(x) 余弦 cos(0) = 1
tan(x) 正切 tan(0) = 0
round(x, n) 四舍五入到n位小数 round(3.14, 1) = 3.1
ceiling(x) 向上取整 ceiling(3.1) = 4
floor(x) 向下取整 floor(3.9) = 3
sign(x) 符号函数 sign(-5) = -1

2.6 变量命名规则与查看变量

变量命名规则

变量名必须遵循以下规则:

# 以下是合法的变量名
# 使用下划线连接(推荐风格)
my_data <- 1

# 使用点连接
my.data <- 2

# 驼峰命名法
myData <- 3

# 输出变量值
my_data
## [1] 1

命名规则: 1. 只能包含字母、数字、下划线 _ 和点 . 2. 必须以字母或点开头(不能以数字开头) 3. 不能使用R的保留字(如 ifelseforwhile等) 4. 区分大小写(myVarmyvar 是不同的变量)

# 这是错误的命名方式(以数字开头),会报错
2nd_value <- 10

查看当前变量

使用 ls() 函数列出当前环境中的所有变量:

# 创建几个变量
a <- 1
b <- 2
my_var <- 3

# ls() 列出所有变量名
ls()
##  [1] "a"       "b"       "mean_x"  "mean_y"  "my.data" "my_data" "my_var" 
##  [8] "myData"  "result"  "x"       "y"       "z"

使用 ls.str() 查看变量及其结构:

# ls.str() 显示变量名和简要结构信息
ls.str()
## a :  num 1
## b :  num 2
## mean_x :  num 3
## mean_y :  num 6
## my.data :  num 2
## my_data :  num 1
## my_var :  num 3
## myData :  num 3
## result :  num 8
## x :  num -4.5
## y :  logi [1:3] FALSE FALSE TRUE
## z :  num 30

2.7 删除变量

删除单个变量

# 创建一个临时变量
temp_var <- 100
temp_var
## [1] 100
# 使用 rm() 函数删除变量
rm(temp_var)

# 此时再输出 temp_var 会报错(变量已不存在)
# temp_var

删除多个变量

# 创建三个变量
x <- 1
y <- 2
z <- 3

# 删除 x 和 y 两个变量
rm(x, y)

# 查看剩余变量,z 还在
ls()
##  [1] "a"       "b"       "mean_x"  "mean_y"  "my.data" "my_data" "my_var" 
##  [8] "myData"  "result"  "z"

删除所有变量

# 删除当前环境中的所有变量
# list = ls() 表示"所有变量组成的列表"
rm(list = ls())

警告:此操作会删除当前环境中的所有变量,请谨慎使用!


2.8 对象查看与概览

R提供了多个函数来查看对象的详细信息:

# 创建一个数值向量
my_vector <- c(1, 2, 3, 4, 5)

# str():显示对象的结构(structure)
# 输出:类型、长度、内容预览
str(my_vector)
##  num [1:5] 1 2 3 4 5
# class():显示对象的类
# 数值向量的类是 "numeric"
class(my_vector)
## [1] "numeric"
# mode():显示存储模式
# 表示数据的存储方式
mode(my_vector)
## [1] "numeric"
# typeof():显示底层类型
# R内部存储的具体类型
typeof(my_vector)
## [1] "double"
# length():显示长度(元素个数)
length(my_vector)
## [1] 5

各函数的区别

函数 作用 返回内容
str() 显示对象结构 类型、维度、内容预览
class() 显示对象类 面向对象的类属性
mode() 显示存储模式 数据的存储方式
typeof() 显示底层类型 R内部存储类型
length() 显示长度 元素个数

不同类型对象的查看

# 创建一个列表(包含不同类型的数据)
my_list <- list(name = "张三", age = 25, scores = c(85, 90, 78))

# str() 显示列表的完整结构
# 可以看到每个元素的名称、类型和内容
str(my_list)
## List of 3
##  $ name  : chr "张三"
##  $ age   : num 25
##  $ scores: num [1:3] 85 90 78
# class() 显示对象是列表类型
class(my_list)
## [1] "list"
# length() 显示列表有3个元素
length(my_list)
## [1] 3

第三章:数据类型与数据结构

3.1 基本数据类型

R语言有几种基本数据类型,理解它们是学习R的基础。

3.1.1 数值型(numeric)

数值型是最常用的数据类型,包括整数和双精度浮点数:

# 双精度浮点数(带小数点的数)
x <- 3.14
class(x)
## [1] "numeric"
# 整数:加 L 后缀表示整数类型
y <- 100L
class(y)
## [1] "integer"
# is.numeric():检查是否为数值型
# 整数和双精度都是数值型
is.numeric(x)
## [1] TRUE
# is.integer():检查是否为整数类型
is.integer(y)
## [1] TRUE
# is.double():检查是否为双精度浮点数
is.double(x)
## [1] TRUE

整数与双精度的区别: - 整数:不带小数点的整数,加 L 后缀表示 - 双精度:带小数点的数,R默认的数值类型

# typeof() 查看R内部存储类型
# 3.14 是双精度浮点数
typeof(3.14)
## [1] "double"
# 不加L,R默认存储为双精度
typeof(3)
## [1] "double"
# 加L,存储为整数
typeof(3L)
## [1] "integer"

3.1.2 字符型(character)

字符型用于存储文本数据:

# 使用双引号创建字符串
name <- "张三"
class(name)
## [1] "character"
# 使用单引号也可以创建字符串
message <- 'Hello World'
class(message)
## [1] "character"
# 字符串中包含引号:外双内单,或外单内双
sentence <- "这是一个包含'引号'的字符串"
sentence
## [1] "这是一个包含'引号'的字符串"
# nchar():计算字符串的字符数
nchar("你好世界")
## [1] 4

3.1.3 逻辑型(logical)

逻辑型只有两个值:TRUE 和 FALSE:

# 定义逻辑变量
flag1 <- TRUE
flag2 <- FALSE

# 查看类型
class(flag1)
## [1] "logical"
# 比较运算返回逻辑值
# 5 > 3 为 TRUE
5 > 3
## [1] TRUE
# 10 == 20 为 FALSE
10 == 20
## [1] FALSE
# 数值转逻辑:非0为TRUE,0为FALSE
as.logical(1)
## [1] TRUE
as.logical(0)
## [1] FALSE
# 逻辑转数值:TRUE为1,FALSE为0
as.numeric(TRUE)
## [1] 1

3.1.4 因子型(factor)

因子型用于存储分类数据,如性别、血型等:

# 创建因子:将字符向量转换为因子
gender <- factor(c("男", "女", "男", "男", "女"))
gender
## [1] 男 女 男 男 女
## Levels: 男 女
# levels():查看因子的水平(所有可能的类别)
levels(gender)
## [1] "男" "女"
# nlevels():查看水平的数量
nlevels(gender)
## [1] 2
# 指定水平的顺序
# levels参数定义所有可能的水平(包括数据中没有的)
blood_type <- factor(c("A", "B", "O", "AB", "A"), 
                     levels = c("A", "B", "AB", "O"))
blood_type
## [1] A  B  O  AB A 
## Levels: A B AB O
# 创建有序因子(有大小关系)
# ordered = TRUE 表示这是一个有序因子
status <- factor(c("低", "中", "高", "低"), 
                 levels = c("低", "中", "高"),
                 ordered = TRUE)
status
## [1] 低 中 高 低
## Levels: 低 < 中 < 高
# 有序因子可以比较大小
# "低" < "高" 为 TRUE
status[1] < status[3]
## [1] TRUE

3.1.5 日期与时间

R有专门的日期和时间类型:

# Sys.Date():获取当前日期
today <- Sys.Date()
today
## [1] "2026-03-19"
# 查看类型:Date类型
class(today)
## [1] "Date"
# as.Date():将字符串转换为日期
my_date <- as.Date("2024-01-15")
my_date
## [1] "2024-01-15"
# 日期可以进行算术运算
# 日期加7天
my_date + 7
## [1] "2024-01-22"
# 自定义日期格式
# format参数指定输入格式
as.Date("2024/03/15", format = "%Y/%m/%d")
## [1] "2024-03-15"
# Sys.time():获取当前日期和时间
now <- Sys.time()
now
## [1] "2026-03-19 20:48:30 CST"
# 查看类型:POSIXct类型(包含日期和时间)
class(now)
## [1] "POSIXct" "POSIXt"
# format():格式化日期时间输出
# %Y年%m月%d日 %H:%M:%S 表示:年月日 时分秒
format(now, "%Y年%m月%d日 %H:%M:%S")
## [1] "2026年03月19日 20:48:30"

常用日期格式符号

符号 含义 示例
%Y 四位年份 2024
%y 两位年份 24
%m 月份(01-12) 03
%d 日期(01-31) 15
%H 小时(00-23) 14
%M 分钟(00-59) 30
%S 秒(00-59) 45

3.2 向量(Vector)

什么是向量?

向量是R中最基本的数据结构,它是一组相同类型数据的有序集合。可以把向量理解为一个”一排数据”。

3.2.1 向量的创建

使用 c() 函数创建向量(c代表combine,合并):

# 创建数值向量
# c() 函数将多个值合并成一个向量
numbers <- c(1, 2, 3, 4, 5)
numbers
## [1] 1 2 3 4 5
# 创建字符向量
names <- c("张三", "李四", "王五")
names
## [1] "张三" "李四" "王五"
# 创建逻辑向量
logics <- c(TRUE, FALSE, TRUE, FALSE)
logics
## [1]  TRUE FALSE  TRUE FALSE

使用 seq() 创建等差序列:

# seq(from, to):从1到10,默认步长为1
seq(1, 10)
##  [1]  1  2  3  4  5  6  7  8  9 10
# seq(from, to, by):从1到10,步长为2
# 结果:1, 3, 5, 7, 9
seq(1, 10, by = 2)
## [1] 1 3 5 7 9
# seq(from, to, length.out):从1到10,生成5个等间距的数
seq(1, 10, length.out = 5)
## [1]  1.00  3.25  5.50  7.75 10.00

使用 rep() 创建重复序列:

# rep(x, times):将1重复5次
rep(1, times = 5)
## [1] 1 1 1 1 1
# rep(x, times):将向量c(1,2)整体重复3次
# 结果:1, 2, 1, 2, 1, 2
rep(c(1, 2), times = 3)
## [1] 1 2 1 2 1 2
# rep(x, each):将向量中每个元素各重复3次
# 结果:1, 1, 1, 2, 2, 2
rep(c(1, 2), each = 3)
## [1] 1 1 1 2 2 2

使用 : 运算符创建连续整数:

# 从1到5的连续整数
1:5
## [1] 1 2 3 4 5
# 从5到1的递减序列
5:1
## [1] 5 4 3 2 1

3.2.2 向量的命名

可以为向量的每个元素命名:

# 创建分数向量
scores <- c(85, 90, 78, 92)

# 使用 names() 为每个元素命名
names(scores) <- c("语文", "数学", "英语", "物理")
scores
## 语文 数学 英语 物理 
##   85   90   78   92
# 通过名称访问元素
scores["数学"]
## 数学 
##   90
ages <- c(张三 = 25, 李四 = 30, 王五 = 28)
ages
## 张三 李四 王五 
##   25   30   28

3.2.3 向量的索引与切片

位置索引(从1开始,不是从0):

x <- c(10, 20, 30, 40, 50)

# 获取第1个元素
x[1]
## [1] 10
# 获取第1、3、5个元素
x[c(1, 3, 5)]
## [1] 10 30 50
# 获取第2到第4个元素
x[2:4]
## [1] 20 30 40
# 使用负号排除元素:排除第1个
x[-1]
## [1] 20 30 40 50
# 排除第1和第2个元素
x[-c(1, 2)]
## [1] 30 40 50

逻辑索引

x <- c(10, 20, 30, 40, 50)

# 筛选大于25的元素
x[x > 25]
## [1] 30 40 50
# 筛选20到40之间的元素
x[x >= 20 & x <= 40]
## [1] 20 30 40
# 使用逻辑向量筛选
# TRUE表示保留,FALSE表示排除
x[c(TRUE, FALSE, TRUE, FALSE, TRUE)]
## [1] 10 30 50

名称索引

# 创建带名称的向量
scores <- c(语文 = 85, 数学 = 90, 英语 = 78)

# 通过名称获取元素
scores["数学"]
## 数学 
##   90
# 获取多个元素
scores[c("语文", "英语")]
## 语文 英语 
##   85   78

[][[]] 的区别

x <- c(a = 10, b = 20, c = 30)

# [] 返回命名的向量(保留名称)
x[1]
##  a 
## 10
# [[]] 返回元素的值(不保留名称)
x[[1]]
## [1] 10

3.2.4 向量元素的修改与添加

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

# 修改第1个元素为10
x[1] <- 10
x
## [1] 10  2  3  4  5
# 同时修改多个元素
x[c(2, 4)] <- c(20, 40)
x
## [1] 10 20  3 40  5
# 添加第6个元素
x[6] <- 60
x
## [1] 10 20  3 40  5 60
# 使用 c() 在末尾添加元素
x <- c(x, 70, 80)
x
## [1] 10 20  3 40  5 60 70 80
# append():在指定位置插入元素
# 在第3个元素后插入100
append(x, 100, after = 3)
## [1]  10  20   3 100  40   5  60  70  80

3.2.5 向量化运算与循环补齐

向量化运算:R可以直接对向量进行数学运算,无需写循环:

a <- c(1, 2, 3, 4, 5)
b <- c(10, 20, 30, 40, 50)

# 向量加法:对应元素相加
a + b
## [1] 11 22 33 44 55
# 向量与标量运算:每个元素都乘以2
a * 2
## [1]  2  4  6  8 10
# 向量乘法:对应元素相乘
a * b
## [1]  10  40  90 160 250
# 函数也支持向量化:对每个元素求平方根
sqrt(a)
## [1] 1.000000 1.414214 1.732051 2.000000 2.236068

循环补齐:当两个向量长度不同时,R会自动循环较短的向量:

# 长度3的向量 + 长度6的向量
# 短向量会循环:c(1,2,3,1,2,3) + c(10,20,30,40,50,60)
c(1, 2, 3) + c(10, 20, 30, 40, 50, 60)
## [1] 11 22 33 41 52 63
# 长度2的向量 * 长度4的向量
# c(1,2,1,2) * c(10,20,30,40)
c(1, 2) * c(10, 20, 30, 40)
## [1] 10 40 30 80

3.3 矩阵(Matrix)

什么是矩阵?

矩阵是一个二维的数据结构,所有元素必须是相同类型。可以把它想象成一个表格,有行和列。

3.3.1 矩阵的创建

使用 matrix() 函数:

# matrix(data, nrow, ncol):创建矩阵
# data:数据,nrow:行数,ncol:列数
# 默认按列填充数据
m <- matrix(1:12, nrow = 3, ncol = 4)
m
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
# byrow = TRUE:按行填充数据
m2 <- matrix(1:12, nrow = 3, ncol = 4, byrow = TRUE)
m2
##      [,1] [,2] [,3] [,4]
## [1,]    1    2    3    4
## [2,]    5    6    7    8
## [3,]    9   10   11   12

使用 cbind() 按列合并:

# cbind():column bind,按列合并向量
a <- c(1, 2, 3)
b <- c(4, 5, 6)
cbind(a, b)
##      a b
## [1,] 1 4
## [2,] 2 5
## [3,] 3 6

使用 rbind() 按行合并:

# rbind():row bind,按行合并向量
rbind(a, b)
##   [,1] [,2] [,3]
## a    1    2    3
## b    4    5    6

3.3.2 矩阵的维度与属性

m <- matrix(1:12, nrow = 3, ncol = 4)

# dim():查看维度(行数,列数)
dim(m)
## [1] 3 4
# nrow():查看行数
nrow(m)
## [1] 3
# ncol():查看列数
ncol(m)
## [1] 4
# 设置行名和列名
rownames(m) <- c("行1", "行2", "行3")
colnames(m) <- c("列1", "列2", "列3", "列4")
m
##     列1 列2 列3 列4
## 行1   1   4   7  10
## 行2   2   5   8  11
## 行3   3   6   9  12

3.3.3 矩阵的索引与子集提取

m <- matrix(1:12, nrow = 3, ncol = 4)
rownames(m) <- c("R1", "R2", "R3")
colnames(m) <- c("C1", "C2", "C3", "C4")

# 获取第1行第2列的元素
m[1, 2]
## [1] 4
# 获取第1行(所有列)
m[1, ]
## C1 C2 C3 C4 
##  1  4  7 10
# 获取第2列(所有行)
m[, 2]
## R1 R2 R3 
##  4  5  6
# 获取子矩阵:第1-2行,第2-3列
m[1:2, 2:3]
##    C2 C3
## R1  4  7
## R2  5  8
# 通过名称获取元素
m["R2", "C3"]
## [1] 8
# 获取指定列
m[, c("C1", "C4")]
##    C1 C4
## R1  1 10
## R2  2 11
## R3  3 12

3.3.4 矩阵的基本运算

m <- matrix(1:4, nrow = 2)
m
##      [,1] [,2]
## [1,]    1    3
## [2,]    2    4
# t():矩阵转置(行列互换)
t(m)
##      [,1] [,2]
## [1,]    1    2
## [2,]    3    4
# diag():提取对角线元素
diag(m)
## [1] 1 4
# diag():创建对角矩阵
diag(c(1, 2, 3))
##      [,1] [,2] [,3]
## [1,]    1    0    0
## [2,]    0    2    0
## [3,]    0    0    3
# 矩阵乘法
A <- matrix(1:4, nrow = 2)
B <- matrix(5:8, nrow = 2)
#矩阵乘法很重要,在机器学习、深度学习中都有大量应用,忘记了的同学回去看看线代书

# %*%:矩阵乘法(线性代数中的矩阵乘法)
A %*% B
##      [,1] [,2]
## [1,]   23   31
## [2,]   34   46
# *:对应元素相乘(不是矩阵乘法)
A * B
##      [,1] [,2]
## [1,]    5   21
## [2,]   12   32

3.4 数组(Array)

什么是数组?

数组是矩阵的扩展,可以有多个维度。矩阵是二维数组,数组可以是三维、四维甚至更高维。

数组的创建

# array(data, dim):创建数组
# dim = c(3, 4, 2) 表示:3行、4列、2层
arr <- array(1:24, dim = c(3, 4, 2))
arr
## , , 1
## 
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
## 
## , , 2
## 
##      [,1] [,2] [,3] [,4]
## [1,]   13   16   19   22
## [2,]   14   17   20   23
## [3,]   15   18   21   24

数组的索引

# 获取第1层、第1行、第2列的元素
arr[1, 2, 1]
## [1] 4
# 获取第1层的所有数据(3行4列的矩阵)
arr[, , 1]
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
# 获取第2层的第1行所有数据
arr[1, , 2]
## [1] 13 16 19 22

3.5 列表(List)

什么是列表?

列表是一种可以存储不同类型元素的数据结构。向量只能存同类型数据,而列表可以存任意类型,甚至可以嵌套其他列表。

3.5.1 列表的创建

# list():创建列表
# 列表可以包含不同类型的数据
my_list <- list(
  name = "张三",           # 字符型
  age = 25,                # 数值型
  scores = c(85, 90, 78),  # 向量
  passed = TRUE            # 逻辑型
)
my_list
## $name
## [1] "张三"
## 
## $age
## [1] 25
## 
## $scores
## [1] 85 90 78
## 
## $passed
## [1] TRUE

3.5.2 列表的命名与索引

my_list <- list(
  name = "张三",
  age = 25,
  scores = c(85, 90, 78)
)

# 使用 $ 符号通过名称访问元素
my_list$name
## [1] "张三"
# 使用 [[ ]] 通过名称访问元素
my_list[["name"]]
## [1] "张三"
# 使用 [[ ]] 通过位置访问元素
my_list[[1]]
## [1] "张三"
# 使用 [ ] 返回子列表(仍是列表类型)
my_list["name"]
## $name
## [1] "张三"
# 获取前2个元素组成的子列表
my_list[1:2]
## $name
## [1] "张三"
## 
## $age
## [1] 25

索引方式总结

方式 返回类型 示例
$ 元素本身 list$name
[[]] 元素本身 list[["name"]]list[[1]]
[] 子列表 list["name"]list[1:2]

3.5.3 列表元素的添加、删除与修改

my_list <- list(name = "张三", age = 25)

# 添加新元素:直接用 $ 赋值
my_list$gender <- "男"
my_list
## $name
## [1] "张三"
## 
## $age
## [1] 25
## 
## $gender
## [1] "男"
# 修改元素:重新赋值
my_list$age <- 26
my_list$age
## [1] 26
# 删除元素:赋值为 NULL
my_list$age <- NULL
my_list
## $name
## [1] "张三"
## 
## $gender
## [1] "男"

3.5.4 列表的递归结构

列表可以嵌套列表,形成层级结构:

# 创建嵌套列表
student <- list(
  info = list(
    name = "张三",
    age = 25
  ),
  grades = list(
    math = 90,
    english = 85
  )
)

# 访问嵌套元素:逐层访问
student$info$name
## [1] "张三"
student$grades$math
## [1] 90

3.6 数据框(Data Frame)

什么是数据框?

数据框是R中最常用的数据结构,类似于Excel表格。每一列可以是不同类型的数据,但同一列必须是相同类型。

3.6.1 数据框的创建

# data.frame():创建数据框
# 每个参数是一列,列名就是参数名
df <- data.frame(
  name = c("张三", "李四", "王五"),      # 字符型列
  age = c(25, 30, 28),                  # 数值型列
  score = c(85.5, 90.0, 78.5),          # 数值型列
  passed = c(TRUE, TRUE, FALSE)         # 逻辑型列
)
df
##   name age score passed
## 1 张三  25  85.5   TRUE
## 2 李四  30  90.0   TRUE
## 3 王五  28  78.5  FALSE
# str():查看数据框结构
str(df)
## 'data.frame':    3 obs. of  4 variables:
##  $ name  : chr  "张三" "李四" "王五"
##  $ age   : num  25 30 28
##  $ score : num  85.5 90 78.5
##  $ passed: logi  TRUE TRUE FALSE

3.6.2 数据框的列名与行名

df <- data.frame(
  name = c("张三", "李四", "王五"),
  age = c(25, 30, 28)
)

# colnames():获取列名
colnames(df)
## [1] "name" "age"
# rownames():获取行名(默认是行号)
rownames(df)
## [1] "1" "2" "3"
# 修改列名和行名
colnames(df) <- c("姓名", "年龄")
rownames(df) <- c("学生A", "学生B", "学生C")
df
##       姓名 年龄
## 学生A 张三   25
## 学生B 李四   30
## 学生C 王五   28
# names() 也可以获取列名
names(df)
## [1] "姓名" "年龄"

3.6.3 数据框的索引

df <- data.frame(
  name = c("张三", "李四", "王五"),
  age = c(25, 30, 28),
  score = c(85, 90, 78)
)

# 使用 $ 获取列(返回向量)
df$name
## [1] "张三" "李四" "王五"
# 使用 [行, 列] 获取列
df[, "age"]
## [1] 25 30 28
# 获取第1行(所有列)
df[1, ]
##   name age score
## 1 张三  25    85
# 获取第1行第2列的元素
df[1, 2]
## [1] 25
# 条件筛选:分数大于80的学生
df[df$score > 80, ]
##   name age score
## 1 张三  25    85
## 2 李四  30    90
# subset():更简洁的筛选方式
subset(df, score > 80)
##   name age score
## 1 张三  25    85
## 2 李四  30    90
# 多条件筛选
subset(df, age > 26 & score > 80)
##   name age score
## 2 李四  30    90

3.6.4 数据框的基本信息查看

df <- data.frame(
  name = c("张三", "李四", "王五", "赵六"),
  age = c(25, 30, 28, 35),
  score = c(85, 90, 78, 88)
)

# head():查看前几行(默认6行)
head(df, 2)
##   name age score
## 1 张三  25    85
## 2 李四  30    90
# tail():查看后几行
tail(df, 2)
##   name age score
## 3 王五  28    78
## 4 赵六  35    88
# summary():查看统计摘要
summary(df)
##      name                age            score      
##  Length:4           Min.   :25.00   Min.   :78.00  
##  Class :character   1st Qu.:27.25   1st Qu.:83.25  
##  Mode  :character   Median :29.00   Median :86.50  
##                     Mean   :29.50   Mean   :85.25  
##                     3rd Qu.:31.25   3rd Qu.:88.50  
##                     Max.   :35.00   Max.   :90.00
# dim():查看维度(行数,列数)
dim(df)
## [1] 4 3
# nrow():查看行数
nrow(df)
## [1] 4
# ncol():查看列数
ncol(df)
## [1] 3

3.6.5 数据框与列表的转换

df <- data.frame(
  name = c("张三", "李四"),
  age = c(25, 30)
)

# as.list():将数据框转换为列表
# 每列变成列表的一个元素
as.list(df)
## $name
## [1] "张三" "李四"
## 
## $age
## [1] 25 30
split(df$name, df$age)
## $`25`
## [1] "张三"
## 
## $`30`
## [1] "李四"

3.7 特殊值

3.7.1 NA(缺失值)

NA表示”缺失值”或”数据不可用”:

# 创建包含缺失值的向量
x <- c(1, 2, NA, 4, 5)

# is.na():检测是否为NA,返回逻辑向量
is.na(x)
## [1] FALSE FALSE  TRUE FALSE FALSE
# 统计缺失值的数量
sum(is.na(x))
## [1] 1
# 含NA的运算结果也是NA
mean(x)
## [1] NA
# na.rm = TRUE:计算时忽略NA
mean(x, na.rm = TRUE)
## [1] 3
# 将NA替换为0
x[is.na(x)] <- 0
x
## [1] 1 2 0 4 5
# na.omit():删除包含NA的行
na.omit(c(1, 2, NA, 4))
## [1] 1 2 4
## attr(,"na.action")
## [1] 3
## attr(,"class")
## [1] "omit"

3.7.2 NULL(空对象)

NULL表示”空”或”不存在”:

# NULL 是空对象
x <- NULL

# is.null():检测是否为NULL
is.null(x)
## [1] TRUE
# NULL 的长度为0
length(NULL)
## [1] 0
# NA 的长度为1
length(NA)
## [1] 1
# NULL 在向量中会被忽略
c(1, 2, NULL, 4)
## [1] 1 2 4
# NA 在向量中会保留
c(1, 2, NA, 4)
## [1]  1  2 NA  4

3.7.3 NaN与Inf

# NaN:Not a Number,非数值
# 0除以0的结果
0 / 0
## [1] NaN
# is.nan():检测是否为NaN
is.nan(0/0)
## [1] TRUE
# Inf:正无穷
# 1除以0的结果
1 / 0
## [1] Inf
# -Inf:负无穷
-1 / 0
## [1] -Inf
# is.infinite():检测是否为无穷
is.infinite(1/0)
## [1] TRUE
# is.finite():检测是否为有限数
is.finite(1)
## [1] TRUE

特殊值总结

特殊值 含义 检测函数
NA 缺失值 is.na()
NULL 空对象 is.null()
NaN 非数值 is.nan()
Inf 正无穷 is.infinite()
-Inf 负无穷 is.infinite()

第四章:基本运算与函数

4.1 常用统计函数

# 创建分数向量
scores <- c(85, 90, 78, 92, 88, 76, 95, 82)

# sum():求和
sum(scores)
## [1] 686
# mean():计算平均值
mean(scores)
## [1] 85.75
# median():计算中位数
median(scores)
## [1] 86.5
# sd():计算标准差
sd(scores)
## [1] 6.734771
# var():计算方差
var(scores)
## [1] 45.35714
# min():最小值
min(scores)
## [1] 76
# max():最大值
max(scores)
## [1] 95
# range():范围(最小值和最大值)
range(scores)
## [1] 76 95
# quantile():计算分位数(默认四分位数)
quantile(scores)
##   0%  25%  50%  75% 100% 
## 76.0 81.0 86.5 90.5 95.0
# 计算指定的分位数
quantile(scores, probs = c(0.1, 0.9))
##  10%  90% 
## 77.4 92.9

统计函数总结

函数 功能 示例结果
sum() 求和 686
mean() 平均值 85.75
median() 中位数 86.5
sd() 标准差 6.69
var() 方差 44.79
min() 最小值 76
max() 最大值 95
range() 范围 76, 95
quantile() 分位数 多个百分位点

4.2 排序与排名

x <- c(3, 1, 4, 1, 5, 9, 2, 6)

# sort():直接返回排序后的向量
sort(x)
## [1] 1 1 2 3 4 5 6 9
# decreasing = TRUE:降序排列
sort(x, decreasing = TRUE)
## [1] 9 6 5 4 3 2 1 1
# order():返回排序后的索引位置
# 结果表示:第2个元素最小,第4个元素第二小...
order(x)
## [1] 2 4 7 1 3 5 8 6
# 使用order()对向量排序
x[order(x)]
## [1] 1 1 2 3 4 5 6 9
# rank():返回每个元素的排名
rank(x)
## [1] 4.0 1.5 5.0 1.5 6.0 8.0 3.0 7.0
# ties.method:处理相同值的方式
# "min":相同值取最小排名
rank(x, ties.method = "min")
## [1] 4 1 5 1 6 8 3 7

排序函数的区别

函数 返回值 用途
sort() 排序后的向量 直接获取排序结果
order() 排序后的索引位置 用于对其他相关向量排序
rank() 每个元素的排名 获取排名信息
# 创建数据框
df <- data.frame(
  name = c("张三", "李四", "王五"),
  score = c(85, 92, 78)
)

# 按分数降序排列数据框
# order(df$score, decreasing = TRUE) 返回排序后的行号
df[order(df$score, decreasing = TRUE), ]
##   name score
## 2 李四    92
## 1 张三    85
## 3 王五    78

4.3 唯一值与去重

# 创建有重复值的向量
x <- c(1, 2, 2, 3, 3, 3, 4, 4, 4, 4)

# unique():返回唯一值(去重后的向量)
unique(x)
## [1] 1 2 3 4
# duplicated():返回逻辑向量,标记是否为重复值
# 第一次出现为FALSE,后续重复为TRUE
duplicated(x)
##  [1] FALSE FALSE  TRUE FALSE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE
# 使用逻辑取反获取唯一值
x[!duplicated(x)]
## [1] 1 2 3 4
# 统计唯一值的个数
length(unique(x))
## [1] 4

4.4 集合运算

# 定义两个集合
A <- c(1, 2, 3, 4, 5)
B <- c(4, 5, 6, 7, 8)

# union():并集(A和B的所有元素,去重)
union(A, B)
## [1] 1 2 3 4 5 6 7 8
# intersect():交集(A和B的共同元素)
intersect(A, B)
## [1] 4 5
# setdiff():差集(A有但B没有的元素)
setdiff(A, B)
## [1] 1 2 3
# setdiff(B, A):B有但A没有的元素
setdiff(B, A)
## [1] 6 7 8
# %in%:判断元素是否在集合中
3 %in% A
## [1] TRUE
10 %in% A
## [1] FALSE
# 可以判断多个元素
c(1, 3, 10) %in% A
## [1]  TRUE  TRUE FALSE
# setequal():判断两个集合是否相等(不考虑顺序)
setequal(c(1, 2, 3), c(3, 2, 1))
## [1] TRUE

集合运算总结

函数/运算符 功能 示例
union() 并集 A和B的所有元素
intersect() 交集 A和B的共同元素
setdiff() 差集 A有但B没有的元素
%in% 成员判断 元素是否在集合中
setequal() 集合相等判断 两个集合是否相同

4.5 字符处理函数

name <- "张三"

# paste():连接字符串,默认用空格分隔
paste("姓名:", name)
## [1] "姓名: 张三"
# paste():使用自定义分隔符
paste("A", "B", "C", sep = "-")
## [1] "A-B-C"
# paste0():连接字符串,无分隔符
paste0("Hello", "World")
## [1] "HelloWorld"
# paste():将向量元素连接成一个字符串
paste(c("A", "B", "C"), collapse = ", ")
## [1] "A, B, C"
# strsplit():按指定分隔符拆分字符串
sentence <- "苹果,香蕉,橙子"
strsplit(sentence, ",")
## [[1]]
## [1] "苹果" "香蕉" "橙子"
# sub():替换第一个匹配项
text <- "Hello World"
sub("World", "R", text)
## [1] "Hello R"
# gsub():替换所有匹配项
text2 <- "apple apple apple"
gsub("apple", "orange", text2)
## [1] "orange orange orange"
# toupper():转大写
toupper("hello")
## [1] "HELLO"
# tolower():转小写
tolower("HELLO")
## [1] "hello"
# nchar():统计字符数
nchar("你好世界")
## [1] 4
# substr():提取子字符串(从第1个到第5个字符)
substr("Hello World", 1, 5)
## [1] "Hello"
# trimws():去除首尾空格
trimws("  Hello World  ")
## [1] "Hello World"

字符函数总结

函数 功能 示例
paste() 连接字符串(可指定分隔符) paste("A", "B") → “A B”
paste0() 连接字符串(无分隔符) paste0("A", "B") → “AB”
strsplit() 分割字符串 按指定字符拆分
sub() 替换第一个匹配 只替换第一个
gsub() 替换所有匹配 替换所有匹配项
toupper() 转大写 “hello” → “HELLO”
tolower() 转小写 “HELLO” → “hello”
nchar() 字符数 统计字符个数
substr() 提取子串 按位置截取
trimws() 去除首尾空格 清理空白字符

4.6 类型转换函数

# as.numeric():转换为数值型
as.numeric("123")
## [1] 123
# as.character():转换为字符型
as.character(123)
## [1] "123"
# as.logical():转换为逻辑型
# 非零为TRUE,零为FALSE
as.logical(1)
## [1] TRUE
as.logical(0)
## [1] FALSE
# as.factor():转换为因子
as.factor(c("A", "B", "A"))
## [1] A B A
## Levels: A B
# as.Date():转换为日期
as.Date("2024-01-15")
## [1] "2024-01-15"
# as.vector():转换为向量
as.vector(matrix(1:4, nrow = 2))
## [1] 1 2 3 4
# as.data.frame():转换为数据框
as.data.frame(matrix(1:6, nrow = 2))
##   V1 V2 V3
## 1  1  3  5
## 2  2  4  6
# as.list():转换为列表
as.list(c(1, 2, 3))
## [[1]]
## [1] 1
## 
## [[2]]
## [1] 2
## 
## [[3]]
## [1] 3

类型判断函数

# is.numeric():判断是否为数值型
is.numeric(123)
## [1] TRUE
# is.character():判断是否为字符型
is.character("hello")
## [1] TRUE
# is.logical():判断是否为逻辑型
is.logical(TRUE)
## [1] TRUE
# is.factor():判断是否为因子
is.factor(factor(c("A", "B")))
## [1] TRUE
# is.vector():判断是否为向量
is.vector(c(1, 2, 3))
## [1] TRUE
# is.data.frame():判断是否为数据框
is.data.frame(data.frame(x = 1))
## [1] TRUE
# is.list():判断是否为列表
is.list(list(a = 1))
## [1] TRUE

第五章:向量化操作与apply族

5.1 向量化运算的本质

向量化运算是R语言的核心特性之一。它的意思是:对整个向量进行操作,而不需要写循环

传统循环方式 vs 向量化方式

假设要计算向量中每个元素的平方:

# 创建向量
x <- 1:5

# 向量化方式:直接对向量进行运算
# R会自动对每个元素求平方
x^2
## [1]  1  4  9 16 25
# 传统循环方式:需要显式写循环
# 先创建一个空向量存储结果
result <- numeric(5)
# 循环计算每个元素的平方
for (i in 1:5) {
  result[i] <- x[i]^2
}
result
## [1]  1  4  9 16 25

向量化运算的优势: 1. 代码简洁:一行代码完成 2. 执行效率高:R内部用C语言优化 3. 易于阅读:意图清晰明了


5.2 ifelse()条件向量化

ifelse() 是向量化版的 if-else:

# 创建分数向量
scores <- c(85, 60, 72, 45, 90)

# ifelse(条件, 条件为TRUE时的值, 条件为FALSE时的值)
# 对每个元素判断:>=60为"及格",否则为"不及格"
ifelse(scores >= 60, "及格", "不及格")
## [1] "及格"   "及格"   "及格"   "不及格" "及格"
# 嵌套ifelse实现多条件判断
# >=90为"优秀",>=60为"及格",否则为"不及格"
ifelse(scores >= 90, "优秀",
       ifelse(scores >= 60, "及格", "不及格"))
## [1] "及格"   "及格"   "及格"   "不及格" "优秀"

5.3 apply系列函数

apply系列函数用于替代循环,对数据的行、列或列表元素进行操作。

5.3.1 apply()

apply() 用于矩阵或数据框,按行或列应用函数:

# 创建矩阵
m <- matrix(1:12, nrow = 3)
m
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
# apply(数据, 维度, 函数)
# 维度:1=按行,2=按列

# 按行求和(对每一行应用sum函数)
apply(m, 1, sum)
## [1] 22 26 30
# 按列求和(对每一列应用sum函数)
apply(m, 2, sum)
## [1]  6 15 24 33
# 按行计算平均值
apply(m, 1, mean)
## [1] 5.5 6.5 7.5
# 使用匿名函数:将每列元素乘以2
apply(m, 2, function(x) x * 2)
##      [,1] [,2] [,3] [,4]
## [1,]    2    8   14   20
## [2,]    4   10   16   22
## [3,]    6   12   18   24

参数说明: - 第1个参数:数据(矩阵或数据框) - 第2个参数:维度(1=行,2=列) - 第3个参数:要应用的函数

5.3.2 lapply()

lapply() 用于列表或向量,返回列表

# 创建列表
my_list <- list(
  a = c(1, 2, 3),
  b = c(10, 20, 30, 40),
  c = c(100, 200)
)

# lapply(列表, 函数):对每个元素应用函数
# 计算每个元素的平均值
lapply(my_list, mean)
## $a
## [1] 2
## 
## $b
## [1] 25
## 
## $c
## [1] 150
# 计算每个元素的和
lapply(my_list, sum)
## $a
## [1] 6
## 
## $b
## [1] 100
## 
## $c
## [1] 300

5.3.3 sapply()

sapply()lapply() 的简化版,返回向量或矩阵

my_list <- list(
  a = c(1, 2, 3),
  b = c(10, 20, 30, 40),
  c = c(100, 200)
)

# sapply() 返回向量(比lapply更简洁)
sapply(my_list, mean)
##   a   b   c 
##   2  25 150
# 计算每个元素的长度
sapply(my_list, length)
## a b c 
## 3 4 2

5.3.4 vapply()

vapply() 类似 sapply(),但需要指定返回值类型,更安全:

my_list <- list(a = 1:3, b = 4:6)

# vapply(列表, 函数, 返回值类型模板)
# numeric(1) 表示返回单个数值
vapply(my_list, mean, numeric(1))
## a b 
## 2 5

5.3.5 tapply()

tapply()分组应用函数:

# 创建分数和对应的班级
scores <- c(85, 90, 78, 92, 88, 76)
classes <- c("A", "A", "B", "B", "A", "B")

# tapply(数据, 分组变量, 函数)
# 按班级计算平均分
tapply(scores, classes, mean)
##        A        B 
## 87.66667 82.00000

5.3.6 mapply()

mapply() 是多变量版本的 sapply()

# mapply(函数, 向量1, 向量2, ...)
# 将两个向量的对应元素相加
mapply(function(x, y) x + y, 
       c(1, 2, 3), 
       c(10, 20, 30))
## [1] 11 22 33
# 重复字符:A重复1次,B重复2次,C重复3次
mapply(rep, times = 1:3, x = c("A", "B", "C"))
## [[1]]
## [1] "A"
## 
## [[2]]
## [1] "B" "B"
## 
## [[3]]
## [1] "C" "C" "C"

5.4 replicate()重复计算

replicate() 用于重复执行某个操作:

# 重复3次计算1:10的平均值
replicate(3, mean(1:10))
## [1] 5.5 5.5 5.5
# 设置随机种子,保证结果可重复
set.seed(123)
# 重复5次:生成10个正态随机数并计算平均值
replicate(5, mean(rnorm(10)))
## [1]  0.074625644  0.208621961 -0.424558873  0.322044550 -0.008715537

第六章:控制流

6.1 条件判断:if-else

基本if语句

x <- 10

# if (条件) { 执行代码 }
# 条件为TRUE时执行花括号内的代码
if (x > 5) {
  print("x大于5")
}
## [1] "x大于5"

if-else语句

score <- 75

# if-else:二选一
# 条件为TRUE执行if块,否则执行else块
if (score >= 60) {
  print("及格")
} else {
  print("不及格")
}
## [1] "及格"

if-else if-else语句

score <- 85

# if-else if-else:多条件判断
# 从上到下依次判断,遇到第一个TRUE的条件就执行对应代码块
if (score >= 90) {
  print("优秀")
} else if (score >= 80) {
  print("良好")
} else if (score >= 60) {
  print("及格")
} else {
  print("不及格")
}
## [1] "良好"

6.2 多分支:switch()函数

day <- "周一"

# switch(判断值, 情况1=结果1, 情况2=结果2, ..., 默认结果)
# 根据day的值返回对应的活动
activity <- switch(day,
  "周一" = "开会",
  "周二" = "培训",
  "周三" = "调研",
  "周四" = "写作",
  "周五" = "总结",
  "周末"  # 默认值(没有匹配时返回)
)

activity
## [1] "开会"
# switch也可以使用数字索引
num <- 2
# 返回第2个值:"第二"
switch(num, "第一", "第二", "第三")
## [1] "第二"

6.3 循环结构

6.3.1 for循环

遍历向量

# for (变量 in 序列) { 执行代码 }
# 变量依次取序列中的每个值
for (i in 1:5) {
  print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

遍历字符向量

fruits <- c("苹果", "香蕉", "橙子")
# fruit依次取向量中的每个元素
for (fruit in fruits) {
  print(paste("我喜欢", fruit))
}
## [1] "我喜欢 苹果"
## [1] "我喜欢 香蕉"
## [1] "我喜欢 橙子"

遍历列表

my_list <- list(a = 1:3, b = 4:6)
# names()获取列表的元素名称
for (name in names(my_list)) {
  print(paste(name, "的均值是", mean(my_list[[name]])))
}
## [1] "a 的均值是 2"
## [1] "b 的均值是 5"

遍历数据框

df <- data.frame(name = c("张三", "李四"), score = c(85, 90))
# nrow()获取行数,逐行遍历
for (i in 1:nrow(df)) {
  print(paste(df$name[i], "的分数是", df$score[i]))
}
## [1] "张三 的分数是 85"
## [1] "李四 的分数是 90"

6.3.2 while循环

# while (条件) { 执行代码 }
# 条件为TRUE时重复执行,直到条件为FALSE
count <- 1
while (count <= 5) {
  print(count)
  count <- count + 1  # 更新计数器,否则会无限循环
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

6.3.3 repeat循环与break、next

repeat循环(无限循环,必须用break退出):

count <- 1
# repeat会无限循环,直到遇到break
repeat {
  print(count)
  count <- count + 1
  # 当count > 5时退出循环
  if (count > 5) {
    break
  }
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4
## [1] 5

break:跳出整个循环

# 当i等于5时,跳出循环
for (i in 1:10) {
  if (i == 5) {
    break  # 跳出循环,不再继续
  }
  print(i)
}
## [1] 1
## [1] 2
## [1] 3
## [1] 4

next:跳过当前迭代,继续下一次

# 当i等于3时,跳过本次循环,继续下一次
for (i in 1:5) {
  if (i == 3) {
    next  # 跳过本次,继续i=4
  }
  print(i)
}
## [1] 1
## [1] 2
## [1] 4
## [1] 5

6.4 循环的向量化替代思想

在R中,很多循环可以用向量化操作替代,效率更高:

x <- 1:1000000

# 向量化方式:直接对向量运算(推荐)
# 简洁且高效
y <- x^2

# 循环方式:需要显式写循环(不推荐)
# 代码冗长且效率低
y <- numeric(length(x))
for (i in seq_along(x)) {
  y[i] <- x[i]^2
}

原则:能用向量化就用向量化,必要时用apply系列函数,最后才考虑显式循环。


第七章:函数定义与作用域

7.1 函数的定义

使用 function() 创建函数:

# 定义函数:function(参数) { 函数体 }
# greet 是函数名,name 是参数
greet <- function(name) {
  result <- paste("你好,", name)
  return(result)  # return() 返回结果
}

# 调用函数
greet("张三")
## [1] "你好, 张三"

7.2 形式参数与实际参数

# 定义函数:a和b是形式参数(形参)
add <- function(a, b) {
  return(a + b)
}

# 调用函数:3和5是实际参数(实参)
# 按位置传递参数
add(3, 5)
## [1] 8
# 按名称传递参数
add(a = 3, b = 5)
## [1] 8
# 按名称传递时,顺序可以改变
add(b = 5, a = 3)
## [1] 8

7.3 参数的默认值

# greeting = "你好" 设置默认值
# 调用时不传该参数,就使用默认值
greet <- function(name, greeting = "你好") {
  paste(greeting, name)
}

# 使用默认值
greet("张三")
## [1] "你好 张三"
# 覆盖默认值
greet("张三", "早上好")
## [1] "早上好 张三"

7.4 返回值

# 使用 return() 显式返回
add <- function(a, b) {
  return(a + b)
}
add(1, 2)
## [1] 3
# 隐式返回:最后一行表达式的值就是返回值
add2 <- function(a, b) {
  a + b  # 没有return,最后一行自动返回
}
add2(1, 2)
## [1] 3
# 返回多个值:使用列表
multi_return <- function(x) {
  list(
    original = x,   # 原始值
    squared = x^2,  # 平方
    cubed = x^3     # 立方
  )
}
multi_return(3)
## $original
## [1] 3
## 
## $squared
## [1] 9
## 
## $cubed
## [1] 27

7.5 作用域规则

# 全局变量
x <- 10

my_func <- function() {
  # 局部变量:只在函数内部有效
  x <- 20
  print(paste("函数内 x =", x))
}

my_func()
## [1] "函数内 x = 20"
# 函数外部的x不受影响
print(paste("函数外 x =", x))
## [1] "函数外 x = 10"
# 函数可以读取全局变量
y <- 10
my_func2 <- function() {
  # 函数内没有定义y,所以使用全局变量y
  print(paste("y =", y))
}
my_func2()
## [1] "y = 10"

作用域规则: 1. 函数内部创建的变量是局部变量,只在函数内有效 2. 函数可以访问外部(全局)变量,但不能直接修改 3. 如需在函数内修改全局变量,使用 <<- 运算符

x <- 10
modify_global <- function() {
  # <<- 超赋值运算符:修改全局变量
  x <<- 20
}
modify_global()
# x已被修改为20
x
## [1] 20

7.6 函数作为对象传递

在R中,函数也是对象,可以作为参数传递:

# 定义一个接受函数作为参数的函数
apply_function <- function(x, func) {
  func(x)  # 调用传入的函数
}

# 传入mean函数
apply_function(c(1, 2, 3, 4, 5), mean)
## [1] 3
# 传入sum函数
apply_function(c(1, 2, 3, 4, 5), sum)
## [1] 15

7.7 匿名函数与闭包

匿名函数

没有名字的函数,通常用于一次性操作:

# 匿名函数:没有函数名,直接定义在调用处
# function(x) x^2 就是匿名函数
sapply(1:5, function(x) x^2)
## [1]  1  4  9 16 25
# 另一个例子:将字符转为大写并添加感叹号
sapply(c("a", "b", "c"), function(x) paste(toupper(x), "!"))
##     a     b     c 
## "A !" "B !" "C !"

闭包

函数可以”记住”创建时的环境:

# 闭包:函数返回另一个函数
# 内部函数可以访问外部函数的变量
counter <- function() {
  count <- 0  # 这个变量会被内部函数"记住"
  function() {
    count <<- count + 1  # 使用 <<- 修改外部函数的变量
    count
  }
}

# 创建一个计数器
my_counter <- counter()
# 每次调用计数器,count都会增加
my_counter()  # 1
## [1] 1
my_counter()  # 2
## [1] 2
my_counter()  # 3
## [1] 3

7.8 …参数(可变参数)

... 允许函数接受任意数量的参数:

# ... 表示可以接受任意数量的参数
my_sum <- function(...) {
  # list(...) 将所有参数转换为列表
  args <- list(...)
  # unlist() 将列表展开为向量,然后求和
  sum(unlist(args))
}

# 可以传入任意数量的参数
my_sum(1, 2, 3, 4, 5)
## [1] 15
# 另一个例子:拼接字符串
my_cat <- function(prefix, ...) {
  args <- list(...)
  paste(prefix, paste(args, collapse = " "))
}

my_cat("结果:", "A", "B", "C")
## [1] "结果: A B C"

第八章:数据输入与输出

8.1 从文本文件读取

read.table()

# read.table():读取通用文本文件
# file:文件路径
# header:第一行是否为列名
# sep:分隔符(\t表示制表符)
df <- read.table("data.txt", header = TRUE, sep = "\t")

read.csv()

# read.csv():读取CSV文件(逗号分隔)
# 默认header=TRUE
df <- read.csv("data.csv")

# stringsAsFactors = FALSE:不将字符转为因子
df <- read.csv("data.csv", header = TRUE, stringsAsFactors = FALSE)

read.delim()

# read.delim():读取制表符分隔的文件
# 默认sep="\t"
df <- read.delim("data.txt")

8.2 从剪贴板读取

# 从剪贴板读取数据(先复制Excel中的数据)
# "clipboard" 表示从剪贴板读取
df <- read.table("clipboard", header = TRUE)

8.3 读取Excel文件

使用 readxl 包:

# 需要先安装并加载readxl包
library(readxl)

# 读取Excel文件
df <- read_excel("data.xlsx")

# 指定工作表名称
df <- read_excel("data.xlsx", sheet = "Sheet1")

# 指定工作表序号
df <- read_excel("data.xlsx", sheet = 2)

8.4 保存数据到文件

write.table()

# write.table():写入文本文件
# sep:分隔符
# row.names = FALSE:不写入行名
write.table(df, "output.txt", sep = "\t", row.names = FALSE)

write.csv()

# write.csv():写入CSV文件
write.csv(df, "output.csv", row.names = FALSE)

8.5 save()与load()

保存和加载R对象:

x <- 1:10
y <- c("a", "b", "c")

# save():保存多个R对象到.RData文件
save(x, y, file = "my_data.RData")

# load():加载.RData文件
load("my_data.RData")

# save.image():保存整个工作空间
save.image("workspace.RData")

# 加载工作空间
load("workspace.RData")

8.6 saveRDS()与readRDS()

保存和加载单个R对象:

my_data <- data.frame(x = 1:10, y = letters[1:10])

# saveRDS():保存单个对象到.rds文件
# 与save()的区别:加载时可以赋值给任意变量名
saveRDS(my_data, "my_data.rds")

# readRDS():读取.rds文件
loaded_data <- readRDS("my_data.rds")

8.7 键盘输入

scan()

# scan():从键盘读取数据
# 默认读取数值,按Enter结束
numbers <- scan()

# what = "character":读取字符
words <- scan(what = "character")

readline()

# readline():读取一行文本
# prompt:提示信息
name <- readline(prompt = "请输入你的名字: ")

8.8 输出打印

x <- 10

# print():打印对象
print(x)
## [1] 10
# cat():连接并输出
# "\n" 表示换行
cat("数值是:", x, "\n")
## 数值是: 10
# message():输出消息(用于提示信息)
message("这是一条消息")
## 这是一条消息
# warning():输出警告
warning("这是一个警告")
## Warning: 这是一个警告

第九章:R包管理

9.1 R包的概念与来源

什么是R包?

R包是R函数、数据和文档的集合。可以把R包理解为”扩展模块”,安装后可以获得额外的功能。

R包的来源

  1. CRAN:官方仓库,最稳定可靠
  2. Bioconductor:生物信息学专用
  3. GitHub:开发者个人发布,最新但可能不稳定

9.2 安装包

从CRAN安装

# install.packages():从CRAN安装包
install.packages("ggplot2")

# 同时安装多个包
install.packages(c("dplyr", "tidyr", "ggplot2"))

从Bioconductor安装

# Bioconductor是生物信息学专用仓库
# 需要先安装BiocManager
if (!require("BiocManager")) {
  install.packages("BiocManager")
}
# 使用BiocManager安装Bioconductor包
BiocManager::install("DESeq2")

从GitHub安装

# 需要先安装devtools包
install.packages("devtools")
# 从GitHub安装
devtools::install_github("用户名/包名")

9.3 加载包

# library():加载包(推荐)
library(ggplot2)
library(dplyr)

# require():加载包,返回TRUE/FALSE
require(tidyr)

# 智能加载:如果包不存在则先安装
if (!require(some_package)) {
  install.packages("some_package")
  library(some_package)
}

9.4 查看已安装包

# installed.packages():查看所有已安装包的详细信息
installed.packages()

# library():不带参数,打开包列表窗口
library()

# search():查看当前已加载的包
search()

9.5 更新与卸载包

# update.packages():更新所有包
update.packages()

# 更新指定包
update.packages("ggplot2")

# remove.packages():卸载包
remove.packages("old_package")

9.6 包文档与帮助

# library(help = 包名):查看包的帮助文档
library(help = ggplot2)

# vignette():查看包的教程文档
vignette("ggplot2")

# 查看所有可用的vignette
vignette()

# 在浏览器中打开vignette
browseVignettes("ggplot2")

第十章:实用技巧与帮助系统

10.1 查看函数帮助

# ?函数名:查看函数帮助
?mean

# help(函数名):等价于 ?函数名
help(mean)

# 查看运算符帮助(需要用反引号包裹)
?`+`
help("+")

10.2 搜索帮助

# help.search():搜索帮助文档
help.search("regression")

# ??关键词:等价于 help.search()
??regression

# apropos():搜索包含指定字符串的函数名
apropos("mean")

10.3 示例运行

# example():运行函数的示例代码
example(mean)

# 运行ggplot包的示例
example(ggplot)

10.4 工作空间管理

# save.image():保存整个工作空间到文件
save.image("my_workspace.RData")

# load():加载工作空间
load("my_workspace.RData")

# save():保存指定的变量
save(list = c("x", "y"), file = "selected.RData")

10.5 历史命令

# history():查看命令历史
history()

# 查看最近50条命令
history(50)

# savehistory():保存命令历史
savehistory("my_history.Rhistory")

# loadhistory():加载命令历史
loadhistory("my_history.Rhistory")

10.6 代码调试基础

traceback()

# 定义嵌套函数
f <- function(x) g(x)
g <- function(x) h(x)
h <- function(x) stop("出错了!")
# 调用函数会报错
f(1)
# traceback():显示错误发生时的调用栈
traceback()

debug()

# debug():进入函数调试模式
debug(mean)
mean(1:10)
# undebug():退出调试模式
undebug(mean)

browser()

# browser():在代码中设置断点
my_func <- function(x) {
  y <- x + 1
  browser()  # 程序会在这里暂停,可以检查变量
  z <- y * 2
  return(z)
}
my_func(5)

10.7 常用快捷键

快捷键 功能
Ctrl + Enter 运行当前行或选中代码
Ctrl + Shift + Enter 运行整个脚本
Ctrl + L 清空控制台
Ctrl + S 保存文件
Ctrl + Shift + C 注释/取消注释
Ctrl + D 删除整行
Ctrl + Shift + K 编译R Markdown
Tab 代码自动补全
Ctrl + Space 触发自动补全
Ctrl + 1 切换到脚本编辑器
Ctrl + 2 切换到控制台
Ctrl + Shift + N 新建R脚本
Ctrl + O 打开文件
Ctrl + W 关闭当前文件

总结

本节课涵盖了以下核心内容:

  1. 环境搭建:R和RStudio的安装与配置
  2. 基础语法:变量、运算符、表达式
  3. 数据类型:数值、字符、逻辑、因子、日期
  4. 数据结构:向量、矩阵、数组、列表、数据框
  5. 函数应用:统计函数、字符处理、类型转换
  6. 向量化操作:apply系列函数
  7. 控制流:条件判断和循环
  8. 函数编写:自定义函数和作用域
  9. 数据I/O:文件读写操作
  10. 包管理:安装、加载、更新R包