1. R语言入门基础
欢迎来到R语言的世界!R是一种专为统计计算和图形展示而生的强大语言。本章将带您完成最基础的环境配置和操作。
1.1 什么是 R 和 RStudio?
把R想象成汽车的“引擎”,它负责所有的计算和分析。而 RStudio 则是“驾驶舱”,它提供了一个用户友好的界面(代码编辑器、控制台、图形窗口等),让您能更轻松地驾驶R这台“引擎”。
对于初学者,**请始终通过 RStudio 来使用 R**。
RStudio 通常有四个窗口:
- 代码编辑器 (左上): 您编写和保存R脚本 (
.R文件) 的地方。 - 控制台 (Console) (左下): 您与R引擎实时交互的地方,代码在这里被执行。
- 环境/历史 (右上): 显示您当前创建了哪些变量 (环境),以及您运行了哪些命令 (历史)。
- 文件/图形/包 (右下): 显示您的文件、您画的图、您已安装的包。
1.2 R的基本操作
打开 RStudio 后,您会看到一个控制台 (Console) 窗口,可以把R当作一个高级计算器:
# R会忽略以 # 开头的注释行
# 这是“注释”,它不会被执行,用于解释代码
1 + 1
# [1] 2
变量赋值
在R中,我们使用 <- (小于号加减号) 来“赋值”,即把一个值存入一个变量名中。这就像给一个盒子贴上标签。
x <- 10
y <- 5
# 查看变量的值
x
# [1] 10
# 变量间可以运算
x + y
# [1] 15
# 运算结果可以存入新变量
z <- x + y
R包:R的生态核心
R的强大之处在于其拥有海量的“包” (Packages)。每个包都是一个针对特定任务(如数据整理、绘图、空间分析)的工具箱。本教程的大部分内容都依赖于特定的包。
# 1. 安装一个包(例如 'dplyr',一个数据整理包)
# 这一步一生中每个包只需做一次
# 这会从R的官方仓库 (CRAN) 下载并安装
install.packages("dplyr")
# 2. 加载一个包(在每次R会话开始时)
# 告诉R:“我这次要用 'dplyr' 工具箱里的工具”
# 这就像从工具箱里拿出工具放到工作台上
library(dplyr)
# 如果您安装了 Tidyverse (一个包的集合),可以一次性加载所有核心包
# install.packages("tidyverse")
# library(tidyverse)
2. R的核心:数据结构
(源: 4数据结构.html) R中所有的数据都存储在特定的“容器”中,这些容器就是数据结构。理解它们是R编程的第一步。
2.1 向量 (Vector)
向量是R中最基本的数据结构。它是一个包含**相同类型**元素的一维序列。使用 c() (combine) 函数来创建向量。
# 1. 数值型向量 (Numeric)
a <- c(1, 2, 5.3, 6, -2, 4)
# 2. 字符型向量 (Character)
b <- c("one", "two", "three")
# 3. 逻辑型向量 (Logical)
c <- c(TRUE, TRUE, FALSE, TRUE)
# R会强制将所有元素变为同一类型
# "a" 会被强制转换为字符型
mixed_vec <- c(1, "a", TRUE)
# mixed_vec 现在是 c("1", "a", "TRUE")
向量化操作: R的一个核心特性是“向量化”。这意味着R会自动对向量中的**每个元素**执行操作,无需您编写循环。
# a 是 c(1, 2, 5.3, 6, -2, 4)
a * 2
# [1] 2.0 4.0 10.6 12.0 -4.0 8.0
a + 10
# [1] 11.0 12.0 15.3 16.0 8.0 14.0
子集 (Subsetting): 如何从向量中取出元素?使用方括号 []。
# 索引从 1 开始
a[1]
# [1] 1
# 取第 2 和 第 4 个元素
a[c(2, 4)]
# [1] 2 6
# 取除第一个之外的所有元素
a[-1]
2.2 矩阵 (Matrix)
矩阵是二维的向量,同样,所有元素必须是同一类型。
# 创建一个 3 行 2 列的矩阵
m <- matrix(data = 1:6, nrow = 3, ncol = 2)
print(m)
# [,1] [,2]
# [1,] 1 4
# [2,] 2 5
# [3,] 3 6
# 矩阵的子集:[行, 列]
m[1, 2] # 第 1 行, 第 2 列
# [1] 4
m[2, ] # 第 2 行 (所有列)
# [1] 2 5
m[, 1] # 第 1 列 (所有行)
# [1] 1 2 3
2.3 列表 (List)
列表是R中最灵活的数据结构。它像一个“袋子”,可以装**任何类型**的R对象,包括其他列表。
# 创建一个包含不同类型元素的列表
L <- list(
name = "John Smith",
age = 30,
scores = c(95, 88, 100),
is_student = TRUE,
sub_list = list(a = 1, b = 2)
)
列表的子集: 列表的子集操作有两种方式,非常重要!
# 1. 使用 $ (推荐): 按名称访问元素
L$name
# [1] "John Smith"
# 2. 使用 [[]] (双括号): 提取元素本身
L[[1]] # 按索引提取第 1 个元素
# [1] "John Smith"
L[["name"]] # 按名称提取元素
# [1] "John Smith"
# 3. 使用 [] (单括号): 提取的还是一个“列表”
L[1]
# $name
# [1] "John Smith"
# (注意:这返回的是一个包含 'name' 元素的子列表)
2.4 数据框 (Data Frame) 与 Tibble
数据框 (Data Frame) 是R中最重要的结构,是您在Excel或统计软件中看到的标准表格数据。它本质上是一个“列表”,但特殊之处在于它的每个元素(列)都是一个向量,且**所有列的长度必须相同**。
df <- data.frame(
ID = 1:3,
Name = c("Alice", "Bob", "Charlie"),
Score = c(85, 92, 78)
)
print(df)
# ID Name Score
# 1 1 Alice 85
# 2 2 Bob 92
# 3 3 Charlie 78
# 数据框的子集
df$Name # 访问 'Name' 列 (返回一个向量)
df[1, ] # 访问第 1 行 (返回一个数据框)
df[, "Score"] # 访问 'Score' 列 (返回一个向量)
Tibble 是数据框的现代“升级版”,来自 Tidyverse 生态 (源: 4数据结构.html)。它在打印和子集操作上更友好、更稳健。在现代R分析中,我们**强烈推荐使用 tibble**。dplyr 和 ggplot2 都更偏好使用 tibble。
- 打印: Tibble 只会打印前 10 行和适合屏幕的列,不会淹没您的控制台。
- 子集:
tb$Name总是有效, 但tb[, "Name"]返回的*仍然是一个 tibble*,而不是向量。这更可预测,不易出错。 - 创建: 创建时不会自作主张地改变列的类型 (例如把字符串变为因子)。
3. R语言编程
掌握了数据结构,我们就可以开始学习如何用R“编程”——即控制代码的执行流程和创建可重用的工具。
3.1 控制结构 (源: 6.1控制结构.html)
控制结构允许您根据条件执行代码或重复执行代码。
条件判断 (if-else)
如果...那么...否则...。注意R中的逻辑操作符:& (和), | (或), ! (非)。
x <- 10
y <- 5
if (x > 5 & y < 10) {
print("x 大于 5 且 y 小于 10")
} else if (x == 10 | y == 10) {
print("x 或 y 等于 10")
} else {
print("其他情况")
}
for 循环
当您知道需要循环的次数时,使用 for 循环。它会遍历一个序列中的每一个元素。
# 遍历 1 到 5
for (i in 1:5) {
# i 在每次循环中会依次变为 1, 2, 3, 4, 5
print(paste("这是第", i, "次循环"))
}
# 遍历一个字符向量
filenames <- c("file1.txt", "file2.txt", "file3.txt")
for (f in filenames) {
print(paste("正在处理:", f))
}
while 循环
当您不知道要循环多少次,但知道何时停止时,使用 while 循环。只要条件为 TRUE,循环就会继续。
count <- 1
while (count <= 5) {
print(paste("Count is:", count))
count <- count + 1 # 关键:必须更新条件,否则会无限循环!
}
循环控制 (break / next)
break: 立刻跳出整个循环。next: 跳过本次迭代,直接进入下一次循环。
for (i in 1:10) {
if (i %% 2 == 0) {
next # 如果 i 是偶数 (%% 是取余),跳过本次循环
}
print(paste(i, "是奇数"))
if (i == 7) {
break # 当 i=7 时, 终止整个循环
}
}
# 输出: 1 3 5 7
3.2 自定义函数 (源: !1DY函数.html)
函数是R编程的核心。它将一系列复杂操作打包成一个可重用的工具。一个好的函数应该像一个“黑匣子”:您给它输入(参数),它给您输出(返回值)。
函数定义与作用域
# 定义一个函数,名为 add_numbers
# 它有两个参数:x 和 y
add_numbers <- function(x, y) {
# 'result' 是一个局部变量 (local variable)
# 它只存在于函数内部
result <- x + y
# 使用 return() 显式返回结果, 这是好习惯
return(result)
}
# 使用我们定义的函数
sum_val <- add_numbers(x = 5, y = 3)
print(sum_val)
# [1] 8
# 尝试访问函数内部的 'result' 变量
print(result)
# 错误: 找不到对象 'result'
# (因为它在函数执行完毕后就消失了)
默认参数
您可以为参数设置默认值,使其变为可选参数。
my_function <- function(arg1, arg2 = "default", arg3 = TRUE) {
print(paste("arg1 is:", arg1))
print(paste("arg2 is:", arg2))
if (arg3) {
print("arg3 is TRUE")
}
}
my_function(arg1 = "Hello")
# [1] "arg1 is: Hello"
# [1] "arg2 is: default"
# [1] "arg3 is TRUE"
异常处理 (stop / warning)
健壮的函数应该能在用户输入错误时给出提示。
warning(): 给出警告,但函数继续执行。stop(): 抛出错误,函数立即终止。
check_age <- function(age) {
if (age < 0) {
stop("年龄不能为负数!")
}
if (age < 18) {
warning("用户未成年")
}
print("年龄检查通过")
}
check_age(15)
# [1] "年龄检查通过"
# 警告信息: 在 check_age(15) 中: 用户未成年
check_age(-5)
# 错误: 在 check_age(-5) 中: 年龄不能为负数!
# (函数停止执行)
3.3 R的“类循环”:Apply函数族 (源: 6.2类循环apply系列函数.html)
在R中,直接使用 for 循环(尤其是在大数据上)通常效率不高。R提供了更高效、更简洁的“向量化”操作和 apply 函数族,它们是R的“类循环”操作,更符合R的函数式编程思想。
lapply(X, FUN) (List Apply)
用途: 将一个函数 FUN 应用于列表 X 的**每一个元素**,并**始终返回一个列表**。
my_list <- list(a = 1:5, b = 6:10)
# my_list 是一个列表,包含两个向量
# 计算 my_list 中每个元素的平均值
mean_list <- lapply(my_list, mean)
print(mean_list)
# $a
# [1] 3
# $b
# [1] 8
sapply(X, FUN) (Simplify Apply)
用途: lapply 的“简化版”。它会尝试将 lapply 返回的列表**简化**为一个更友好的格式,例如向量或矩阵。
# 同样的操作,使用 sapply
mean_vector <- sapply(my_list, mean)
print(mean_vector)
# a b
# 3 8
# (结果是一个简洁的命名向量)
apply(X, MARGIN, FUN)
用途: 专门用于对矩阵 (Matrix) 或数组 (Array) 的行或列进行操作。
MARGIN = 1: 表示按**行**应用函数。MARGIN = 2: 表示按**列**应用函数。
m <- matrix(1:9, nrow = 3, ncol = 3)
# [,1] [,2] [,3]
# [1,] 1 4 7
# [2,] 2 5 8
# [3,] 3 6 9
# 1. 计算每一列的和 (MARGIN = 2)
col_sums <- apply(m, MARGIN = 2, FUN = sum)
# [1] 6 15 24
# 2. 计算每一行的平均值 (MARGIN = 1)
row_means <- apply(m, MARGIN = 1, FUN = mean)
# [1] 4 5 6
mapply(FUN, ...) (Multiple Apply)
用途: apply 的多参数版本,可将函数 FUN 应用于多个列表或向量的**对应元素**。
x_vals <- c(1, 2, 3)
y_vals <- c(10, 20, 30)
# 计算 x_vals[1]+y_vals[1], x_vals[2]+y_vals[2], ...
mapply(sum, x_vals, y_vals)
# [1] 11 22 33
4. 高效的数据整理 (Tidyverse)
(源: !DY5数据整理.html) 现代R数据分析的核心是 Tidyverse,这是一个包含 dplyr、ggplot2 等一系列包的“生态系统”。dplyr 是数据整理的核心工具,它提供了一套易读、高效的“动词”来操作数据框。
4.1 管道操作符 %>%
dplyr 的灵魂是管道操作符 %>% (读作 "then")。它允许你将代码“串联”起来,从左到右阅读,逻辑非常清晰。
x %>% f(y) 等价于 f(x, y)。
想象一个汽车组装流水线:数据 %>% 第一道工序 %>% 第二道工序 %>% 成品
# 使用管道的代码 (从上到下阅读,清晰)
data %>%
filter(col1 > 100) %>% # 第一步:筛选数据
group_by(col2) %>% # 第二步:按 col2 分组
summarize(mean_val = mean(col3)) # 第三步:计算均值
4.2 dplyr 的核心函数
我们将使用R内置的 mtcars 数据集来演示。
library(dplyr)
cars_data <- as_tibble(mtcars) # 转换为 Tibble
filter(): 按条件筛选行
选择满足特定条件的行。, 逗号等同于 & (和)。
# 筛选所有6缸 (cyl == 6) 且马力 (hp > 110) 的车
cars_data %>%
filter(cyl == 6, hp > 110)
# 筛选6缸 或 马力大于 200 的车
cars_data %>%
filter(cyl == 6 | hp > 200)
select(): 按名称选择列
选择你感兴趣的列。select() 提供了很多“助手函数”。
# 只选择 'mpg', 'cyl', 'hp' 这三列
cars_data %>%
select(mpg, cyl, hp)
# 选择从 'mpg' 到 'hp' 之间的所有列
cars_data %>%
select(mpg:hp)
# 选择所有以 'c' 开头的列 (cyl, carb)
cars_data %>%
select(starts_with("c"))
# 选择所有列,但把 'cyl' 和 'hp' 移到最前面
cars_data %>%
select(cyl, hp, everything())
arrange(): 对行进行排序
默认升序。使用 desc() 来降序排列。可以按多个列排序。
# 按 'cyl' 升序排列, 如果 'cyl' 相同, 则按 'mpg' (油耗) 降序排列
cars_data %>%
arrange(cyl, desc(mpg))
mutate(): 创建或修改列
mutate() 是最强大的函数之一,用于添加新列或修改现有列。
# 增加一列 'hp_per_wt' (马力/重量比)
# 并且将 'mpg' 转换为 'kpl' (公里/升)
cars_data %>%
mutate(
hp_per_wt = hp / wt,
kpl = mpg * 0.425
) %>%
select(hp_per_wt, kpl, everything()) # 把新列放到最前面
group_by() 与 summarize(): 分组汇总
这两个函数通常一起使用。group_by() 本身不做任何事,只是给数据“打上标签”,告诉R接下来的操作要按组进行。summarize() 则对这些组进行汇总统计,汇总后,数据会“折叠”成每个组一行。
# 目标:按气缸数 (cyl) 分组,计算每组的平均马力 (hp) 和平均油耗 (mpg)
cars_data %>%
group_by(cyl) %> # 按 cyl (4, 6, 8) 分组
summarize(
avg_hp = mean(hp), # 计算每组的平均 hp
avg_mpg = mean(mpg), # 计算每组的平均 mpg
count = n() # n() 是一个特殊函数,计算每组的行数
)
# # A tibble: 3 × 4
# cyl avg_hp avg_mpg count
# <dbl> <dbl> <dbl> <int>
# 1 4 82.6 26.7 11
# 2 6 122. 19.7 7
# 3 8 209. 15.1 14
left_join(): 连接数据框
数据分析中,数据常常分散在多个表格中。left_join 是最常用的连接函数。
# 假设有两个数据框
df1 <- data.frame(id = 1:3, name = c("A", "B", "C"))
df2 <- data.frame(id = c(1, 2, 4), score = c(100, 90, 80))
# 以 df1 为基础 (左),将 df2 的信息匹配过来
# 匹配的“钥匙”是 'id' 列
left_join(df1, df2, by = "id")
# id name score
# 1 1 A 100
# 2 2 B 90
# 3 3 C NA (因为 df2 中没有 id=3)
5. R语言数据可视化
R语言拥有无与伦比的绘图能力。主要分为两大系统:基础绘图系统和 ggplot2。
5.1 基础绘图 (源: !常见图形2025.html)
R自带的绘图功能,简单快捷,适合快速探索数据。它们像是在一张“画布”上作画,第一个命令 (如 plot) 会创建画布,后续命令 (如 lines, points) 会在上面**叠加**。
# 1. plot(): 创建画布并画散点图
plot(x = cars_data$wt, y = cars_data$mpg,
main = "车重 vs 油耗", xlab = "车重", ylab = "油耗",
pch = 19, col = "blue") # pch=19 是实心圆, col 是颜色
# 2. lines(): 在已有的图上添加线
# (这里添加一条简单的线性回归线)
model <- lm(mpg ~ wt, data = cars_data) # 建立线性模型
abline(model, col = "red", lwd = 2) # abline 画直线, lwd 是线宽
# 3. legend(): 添加图例
legend("topright", legend = "回归线", col = "red", lty = 1)
5.2 ggplot2 绘图 (源: !!ggplot2_2025.html)
ggplot2 是 Tidyverse 的核心绘图包,是R中最流行、最强大的绘图工具。它基于“图形语法”(Grammar of Graphics),逻辑非常严谨,允许你“图层式”地构建精美图形。
ggplot2 的核心三要素:
- Data (数据): 你要绘制的数据框 (data frame 或 tibble)。
- Aesthetics (
aes(), 审美映射): 数据中的变量如何**映射**到图形属性(如x轴,y轴,color,size,fill等)。 - Geometries (
geom_, 几何对象): 你实际看到的图形(如点geom_point(), 线geom_line(), 柱geom_bar())。
映射 (aes) vs. 设置 (setting)
这是 ggplot2 最关键的概念!
- 映射 (Mapping): 放在
aes()内部。意思是“让**数据变量**来控制图形属性”。(例如:aes(color = cyl), 颜色**取决于**cyl列的值)。 - 设置 (Setting): 放在
aes()外部。意思是“把图形属性**写死**为一个固定值”。(例如:geom_point(color = "blue"), 所有的点都是蓝色)。
# 1. 映射 (Mapping): 颜色由 'cyl' 变量决定
ggplot(cars_data, aes(x = wt, y = mpg, color = factor(cyl))) +
geom_point()
# 2. 设置 (Setting): 所有的点都是蓝色
ggplot(cars_data, aes(x = wt, y = mpg)) +
geom_point(color = "blue")
# 3. 错误的做法 (ggplot会懵掉)
ggplot(cars_data, aes(x = wt, y = mpg, color = "blue")) +
geom_point()
# (这会创建一个名为 "blue" 的图例, 而不是把点设为蓝色)
图层 (Layers)
ggplot2 使用 + 号来添加图层。你可以随意组合它们。
ggplot(data = cars_data, mapping = aes(x = wt, y = mpg)) +
geom_point(aes(color = factor(cyl))) + # 第1层: 带颜色的点
geom_smooth(method = "lm") + # 第2层: 添加线性回归平滑线
labs( # 第3层: 修改标签
title = "车重 vs 油耗 (按气缸数分组)",
x = "车重 (1000 lbs)",
y = "油耗 (MPG)",
color = "气缸数"
) +
theme_minimal() # 第4层: 应用一个简洁的主题
分面 (Faceting)
ggplot2 的另一个强大功能是分面,即“小图表”。
# 目标:按 'cyl' (气缸数) 绘制 3 个独立的子图
ggplot(cars_data, aes(x = wt, y = mpg)) +
geom_point() +
facet_wrap(~ cyl) # 按 'cyl' 变量分面
# (这会为 4缸、6缸、8缸的车分别创建一个散点图)
6. 专题:文本处理
(源: !R语言文本处理.html) R 语言也提供了强大的文本处理能力。虽然现代分析更推荐使用 stringr 包(Tidyverse的一部分),但R的基础函数是理解文本处理的基石。
nchar(): 计算字符数
nchar("Hello")
# [1] 5
paste() / paste0(): 字符串拼接
paste0() 是 paste(..., sep = "") 的简写,即将所有元素无缝拼接。
paste("Hello", "world", "!")
# [1] "Hello world !" (默认用空格分隔)
paste0("Hello", "world", "!")
# [1] "Helloworld!" (无分隔符)
strsplit(): 字符串拆分
根据分隔符将一个字符串拆分为一个列表。
text <- "a,b,c;d,e"
strsplit(text, split = ";")
# [[1]]
# [1] "a,b,c" "d,e"
# (返回的是一个列表,因为一个字符串可能被拆成多块)
模式匹配 (正则表达式)
正则表达式是匹配文本模式的强大语言。例如 \\d 匹配数字, . 匹配任意字符。
grep() / grepl(): 查找匹配项
grep(): 返回匹配项的**索引**或**值**。grepl(): 返回一个**逻辑值 (TRUE/FALSE)**,非常适合用于filter()。
filenames <- c("report_2023.csv", "data_final.txt", "report_2024.csv", "image.png")
# 1. 检查哪些文件名包含 "report"
grepl("report", filenames)
# [1] TRUE FALSE TRUE FALSE
# 2. 查找所有以 ".csv" 结尾的文件名
# $ 符号在正则表达式中表示“结尾”
grep("\\.csv$", filenames, value = TRUE)
# [1] "report_2023.csv" "report_2024.csv"
sub() / gsub(): 替换匹配项
sub(): 替换**第一个**匹配项。gsub(): (Global Sub) 替换**所有**匹配项。
text <- "Hello_world_this_is_R"
# 2. 将所有 "_" 替换为空格
gsub(pattern = "_", replacement = " ", x = text)
# [1] "Hello world this is R"
7. 专题:空间数据分析
(源: 空间数据.html, !!terra处理矢量数据.html, !!!13-矢量数据读取与处理2025-1.html)
R在地理信息系统 (GIS) 领域也非常强大。R中有两个处理空间数据的现代包:
sf(Simple Features): 处理矢量数据(点、线、面)的王者。它将空间数据存储为一种特殊的数据框,与Tidyverse完美兼容。terra: 处理栅格数据(如遥感影像、DEM)的王者。它也具有强大的矢量数据处理能力,是raster和sp包的继任者。
您提供的资料 `!!!13...` 详细介绍了 sf 包的函数,我们将重点讲解它,因为它在矢量分析中更为主流和易用。
7.1 `sf` 包入门
library(sf)
sf 对象的核心就是一个 data.frame,它增加了一个特殊的 geometry 列。这意味着您在第 4 节学到的**所有 dplyr 动词** (filter, mutate, select, left_join...) 都可以**直接**用在 sf 对象上!
数据读取与坐标系 (CRS)
sf 可以使用 st_read() 读取几乎所有的矢量数据格式 (如 Shapefile, GeoPackage)。
# 使用 sf 自带的北卡罗来纳州数据
nc_path <- system.file("gpkg/nc.gpkg", package="sf")
nc <- st_read(nc_path)
print(nc)
# Simple feature collection with 100 features and 14 fields
# Geometry type: MULTIPOLYGON
# ...
# CRS: NAD27 (EPSG:4267)
# 查看坐标系 (CRS)
st_crs(nc)
# NAD27 (EPSG:4267) - 这是一个地理坐标系,单位是“度”。
地理坐标系 (Geographic CRS), 如 EPSG:4267 (NAD27) 或 EPSG:4326 (WGS84),使用“度”(经纬度)作为单位。它们在球体上定义位置,但**不适合**计算面积或距离。因为 1 度的经度在赤道和在北极代表的实际距离是天差地别的。
投影坐标系 (Projected CRS), 如 EPSG:32617 (UTM 17N),使用“米”作为单位。它们将地球“压平”到二维平面上,非常适合计算准确的面积和距离。
结论:在进行任何空间计算 (st_area, st_length, st_buffer) 之前,必须使用 st_transform() 将数据转换为投影坐标系!
# 转换 CRS 到一个以“米”为单位的投影坐标系 (例如 UTM)
nc_utm <- st_transform(nc, crs = 32617) # 32617 是 UTM 17N 的 EPSG 代码
st_crs(nc_utm)
# ... (现在单位是米)
7.2 提取对象几何信息 (源: !!!13...)
以下是 sf 包中用于提取几何属性的核心函数,这些操作都应在投影坐标系下进行。
st_area() / st_length(): 计算面积/周长
# 计算面积 (单位:平方米)
nc_utm$area_sqm <- st_area(nc_utm)
# 计算周长 (单位:米)
nc_utm$perimeter_m <- st_length(nc_utm)
# 我们可以用 dplyr::mutate 来做同样的事
nc_utm <- nc_utm %>%
mutate(
area_sqkm = as.numeric(st_area(.)) / 1000000, # 转换为平方公里
perimeter_km = as.numeric(st_length(.)) / 1000 # 转换为公里
)
st_centroid(): 提取质心
计算每个几何对象的质心,返回点 (POINT) 对象。这对于为多边形创建标签位置非常有用。
county_centers <- st_centroid(nc_utm)
# 几何类型现在是 POINT
st_geometry() / st_drop_geometry()
st_geometry(): 仅提取几何列 (sfc)。st_drop_geometry(): 移除几何列,将其变回一个普通的data.frame。
st_coordinates(): 提取坐标
对于点,返回 X, Y 坐标。对于多边形/线,返回构成它们的所有顶点的坐标。
st_boundary(): 提取边界
将多边形 (POLYGON) 转换为其边界线 (LINESTRING)。
st_voronoi(): 生成泰森多边形
泰森多边形(Voronoi 图)是一种空间剖分。对于一组点,它会生成一系列多边形,使得每个多边形内的区域到其对应的点最近。
# 使用上面的质心点来创建泰森多边形
voronoi_polygons <- st_voronoi(st_geometry(county_centers))
7.3 空间操作与叠置分析 (Overlay) (源: !!!13...)
这是 GIS 的核心,用于组合两个空间图层 (x 和 y)。
st_buffer(x, dist): 缓冲区分析
创建一个围绕 x 的缓冲区,距离为 dist (单位与CRS一致,这里是米)。
# 1. 取第一个县的质心
center_point <- st_centroid(st_geometry(nc_utm)[1])
# 2. 创建一个半径 100 公里 (100000米) 的缓冲区
buffer_circle <- st_buffer(center_point, dist = 100000)
plot(st_geometry(buffer_circle))
plot(st_geometry(center_point), add=TRUE, col="red")
st_intersection(x, y): 空间交集
这是最常用的叠置操作。它返回两个图层中**重叠**的部分。想象一下,用 y 图层作为“饼干切割器”去切割 x 图层。输出的几何是重叠部分,属性是两个图层属性的合并。
# 3. 用这个圆去“切割” nc_utm
intersected_counties <- st_intersection(nc_utm, buffer_circle)
# 绘制结果
plot(st_geometry(nc_utm), border = 'grey')
plot(st_geometry(intersected_counties), col = 'red', add = TRUE)
plot(st_geometry(buffer_circle), border = 'blue', add = TRUE)
st_difference(x, y): 空间差集
从 x 中减去 y 的部分,即 x 中**不**与 y 重叠的部分。
# 减去缓冲区
difference_counties <- st_difference(nc_utm, buffer_circle)
st_crop(x, y): 裁剪
用一个矩形范围 (y 可以是一个 st_bbox 对象) 来快速裁剪 x。比 st_intersection 更快,但只适用于矩形。
# 创建一个裁剪框
crop_box <- st_bbox(c(xmin = 0, xmax = 200000, ymin = 100000, ymax = 200000), crs = st_crs(nc_utm))
cropped_data <- st_crop(nc_utm, crop_box)
7.4 terra 包简介 (源: !!terra...)
虽然 sf 擅长矢量,但 terra 在处理栅格数据时是必须的。terra 也可以处理矢量数据,其函数名通常是动词(如 intersect, buffer, crop),而 sf 的函数名是名词(如 st_intersection, st_buffer, st_crop)。
library(terra)
# 将 sf 对象转换为 terra 的 SpatVector 对象
nc_spatvector <- vect(nc_utm)
# terra 的函数
# intersected_terra <- terra::intersect(nc_spatvector, vect(buffer_circle))
# buffer_terra <- terra::buffer(nc_spatvector, width = 10000)
sf vs. terra (矢量处理):
sf(首选): Tidyverse 原生集成。使用dplyr操作sf对象非常流畅。可读性强。terra: 性能怪兽。在处理超大规模矢量数据 (百万级别多边形) 时,terra的 C++ 底层通常比sf更快。但它的语法与 Tidyverse 不同。