R: R 运算符:算术、比较、逻辑运算全解析
最后更新:2026-08-26
上一课我们学了向量和数据类型,这一课进入 R 编程的"基本功"——运算符。所有 R 程序——从简单计算到复杂统计模型——底层都是运算符在工作。
R 的运算符体系跟其他语言大同小异,但有两个 R 特有的小细节:整数除法 %% %/%、和向量化的"广播"行为。这一课我们要把所有运算符吃透。
1. 你将学到
- 4 大类算术运算符(基础运算 + 整数除法 + 向量运算)
- 3 类比较运算符(数值比较 + 字符串比较 + 特殊值)
- 3 类逻辑运算符(与或非 + 短路求值)
- 5 个 R 特有运算符(
%in%%*%%/%%%:) - 运算符优先级(避免歧义表达式)
- 实战中常见的运算陷阱
2. 一个财务计算的故事
(1) 痛点:手算利润
Bob是会计,月底要给manager算"分店销售报告":
公司有 5 个分店,本月销售额分别是
120, 150, 80, 200, 175万元。需要计算:
- 总销售额、平均销售额
- 每家店的利润(销售额 × 30% 利润率)
- 哪些店销售额超过平均(需要重点关注)
- 利润总额的整数部分(万元,向下取整)
如果用计算器手算,要 5 分钟;用 Excel 要建表、敲公式;用 R——
(2) R 的解法
# 5 个分店销售额(万元)
sales <- c(120, 150, 80, 200, 175)
# 一行代码完成所有计算
total_sales <- sum(sales) # 总销售 725
avg_sales <- mean(sales) # 平均 145
profit <- sales * 0.3 # 利润向量
high_sales <- sales[sales > avg_sales] # 高于平均的分店
profit_int <- profit %/% 1 # 整数利润(整数除法)
cat("总销售:", total_sales, "万元\n")
cat("平均销售:", avg_sales, "万元\n")
cat("利润总额(整数):", sum(profit_int), "万元\n")
cat("高于平均的分店销售额:", high_sales, "\n")
10 行代码解决 5 个计算任务。这就是 R 运算符的威力——一句话就是一个运算向量。
3. 算术运算符:数学计算
(1) 基础算术运算符
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
+ |
加 | 2 + 3 |
5 |
- |
减 | 5 - 2 |
3 |
* |
乘 | 4 * 3 |
12 |
/ |
除 | 7 / 2 |
3.5 |
^ 或 ** |
幂 | 2 ^ 3 |
8 |
%% |
取模(余数) | 7 %% 2 |
1 |
%/% |
整数除法 | 7 %/% 2 |
3 |
(2) 整数除法:R 特有
# 7 / 2 = 3.5(普通除法)
7 / 2
# [1] 3.5
# 7 %/% 2 = 3(整数除法,向下取整)
7 %/% 2
# [1] 3
# 7 %% 2 = 1(取模,余数)
7 %% 2
# [1] 1
# 实战:把秒数转成"时:分:秒"
total_seconds <- 3725
hours <- total_seconds %/% 3600
minutes <- (total_seconds %% 3600) %/% 60
seconds <- total_seconds %% 60
cat(hours, "时", minutes, "分", seconds, "秒\n")
# 1 时 2 分 5 秒
%% 和 %/% 在数据处理中极其常用:分页(page %/% page_size)、分组(id %% 10 按尾数分 10 组)、时间转换。
(3) 向量化运算(重点)
R 的算术运算默认就是向量化的——这是 R 的核心优势:
graph LR
A["x = 1, 2, 3"] --> C["+ 10"]
C --> D["11, 12, 13"]
E["x = 1, 2, 3"] --> F["+ y = 10, 20, 30"]
F --> G["11, 22, 33"]
style A fill:#cce5ff
style C fill:#d4edda
style D fill:#d4edda
# 向量 + 标量(标量"广播"到每个元素)
c(1, 2, 3) + 10
# [1] 11 12 13
# 向量 + 向量(对应元素运算)
c(1, 2, 3) + c(10, 20, 30)
# [1] 11 22 33
# 长度不同时会"循环"
c(1, 2, 3, 4) + c(10, 20)
# Warning: longer object length is not a multiple of shorter object length
# [1] 11 22 13 24
(4) 常用数学函数
| 函数 | 作用 | 示例 |
|---|---|---|
abs() |
绝对值 | abs(-5) → 5 |
sqrt() |
平方根 | sqrt(16) → 4 |
log() |
自然对数 | log(exp(1)) → 1 |
log10() |
常用对数 | log10(1000) → 3 |
log2() |
以 2 为底 | log2(8) → 3 |
exp() |
e 的 x 次方 | exp(1) → 2.718 |
round() |
四舍五入 | round(3.14159, 2) → 3.14 |
floor() |
向下取整 | floor(3.7) → 3 |
ceiling() |
向上取整 | ceiling(3.2) → 4 |
4. 比较运算符:真假判断
(1) 6 个比较运算符
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
== |
等于 | 5 == 5 |
TRUE |
!= |
不等于 | 5 != 3 |
TRUE |
< |
小于 | 3 < 5 |
TRUE |
> |
大于 | 5 > 3 |
TRUE |
<= |
小于等于 | 5 <= 5 |
TRUE |
>= |
大于等于 | 5 >= 6 |
FALSE |
(2) ⚠️ 重要陷阱:单个等号 vs 双等号
# 单个 = 是赋值
x = 5
# 双等号 == 是比较
x == 5
# [1] TRUE
==,不能写 =。R 不会报"=` 错(因为它是合法赋值),但结果完全不对。
(3) 字符串比较(按字典序)
# 字符按 ASCII 编码比较
"apple" < "banana"
# [1] TRUE ← 'a' 编码 < 'b'
# 数字字符不能直接比较大小(按字符比较,不是按数值)
"9" > "10"
# [1] TRUE ← '9' (0x39) > '1' (0x31),不是数值比较!
# 正确做法:转成数字
as.numeric("9") > as.numeric("10")
# [1] FALSE
(4) 特殊值的比较
# NA 的比较结果是 NA(不是 TRUE/FALSE)
NA == 5
# [1] NA
# 判断 NA 必须用 is.na()
is.na(NA)
# [1] TRUE
# NaN 的比较
NaN == NaN
# [1] NA ← NaN == NaN 也是 NA!
is.na() 专门判断。
5. 逻辑运算符:组合条件
(1) 3 个基本逻辑运算符
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
& |
元素级 AND | TRUE & FALSE |
FALSE |
| |
元素级 OR | TRUE | FALSE |
TRUE |
! |
取反 | !TRUE |
FALSE |
(2) 向量化(重点)
x <- c(TRUE, TRUE, FALSE, FALSE)
y <- c(TRUE, FALSE, TRUE, FALSE)
# 元素级 AND(向量化)
x & y
# [1] TRUE FALSE FALSE FALSE
# 元素级 OR
x | y
# [1] TRUE TRUE TRUE FALSE
(3) 短路求值:&& 和 ||
| 运算符 | 行为 | 用途 |
|---|---|---|
& |
元素级 AND,全部计算 | 向量逻辑运算 |
&& |
短路 AND,只算第一个 | if 条件 |
| |
元素级 OR,全部计算 | 向量逻辑运算 |
|| |
短路 OR,只算第一个 | if 条件 |
# if 条件里用 &&(只判断第一个元素)
if (x > 0 && x < 10) {
cat("x 是 0-10 之间\n")
}
# 向量逻辑用 &(判断所有元素)
c(1, 2, 11) > 0 & c(1, 2, 11) < 10
# [1] TRUE TRUE FALSE
if 条件里必须用 && 和 ||,不能用 & 和 |。否则可能得到意外结果。
(4) 实战:组合条件筛选
# 找出 18-30 岁的成年人
ages <- c(15, 22, 28, 35, 40, 19)
adults <- ages[ages >= 18 & ages <= 30]
adults
# [1] 22 28 19
# 找出不及格或满分
scores <- c(58, 60, 75, 100, 45, 90)
special <- scores[scores < 60 | scores == 100]
special
# [1] 58 100 45
6. R 特有运算符
(1) 5 个特色运算符
| 运算符 | 含义 | 示例 | 结果 |
|---|---|---|---|
%in% |
属于(成员判断) | 3 %in% c(1,2,3) |
TRUE |
%*% |
矩阵乘法 | matrix(1:4,2) %*% matrix(1:4,2) |
矩阵 |
%/% |
整数除法 | 7 %/% 2 |
3 |
%% |
取模 | 7 %% 2 |
1 |
: |
序列 | 1:5 |
1 2 3 4 5 |
(2) %in% 详解
%in% 是数据筛选的"灵魂"运算符:
# 元素是否在向量中
c(1, 2, 3) %in% c(2, 4, 6)
# [1] FALSE TRUE FALSE ← 1, 3 不在;2 在
# 实战:筛选"北上广"城市
cities <- c("北京", "上海", "深圳", "广州", "杭州")
target <- c("北京", "上海", "广州")
cities[cities %in% target]
# [1] "北京" "上海" "广州"
(3) 矩阵乘法 %*% 简介
# 普通乘法(元素级)
matrix(1:4, 2, 2) * matrix(1:4, 2, 2)
# [,1] [,2]
# [1,] 1 9
# [2,] 4 16
# 矩阵乘法(线性代数)
matrix(1:4, 2, 2) %*% matrix(1:4, 2, 2)
# [,1] [,2]
# [1,] 7 15
# [2,] 10 22
7. 运算符优先级(避免歧义)
R 的运算符有优先级,不确定时加括号最安全:
| 优先级 | 运算符 | 说明 |
|---|---|---|
| 高 | ^ |
幂运算 |
| ↑ | * / |
乘除 |
| ↑ | + - |
加减 |
| ↑ | < <= > >= == != |
比较 |
| ↑ | ! |
取反 |
| ↑ | & && |
与 |
| ↓ | | || |
或 |
| 低 | <- |
赋值 |
# 不加括号(按优先级)
1 + 2 * 3
# [1] 7 ← 2*3=6,再+1
# 加括号(明确意图)
(1 + 2) * 3
# [1] 9
# 复杂表达式一定要加括号
# 找出 18-65 岁
ages <- c(15, 25, 70, 30)
adults <- ages[ages >= 18 & ages <= 65] # ✅ 加括号更清晰
8. 完整示例:分店销售综合分析
下面是一个完整工作流示例,把本课所有运算符串起来。
▶ 示例:分店销售综合分析
# ============================================
# 分店销售综合分析
# 功能:用各类运算符分析 5 个分店销售数据
# ============================================
# 1. Prepare data
sales <- c(北京 = 120, 上海 = 150, 深圳 = 80, 广州 = 200, 杭州 = 175)
cat("原始销售数据(万元):\n")
print(sales)
# 2. 算术运算:总销售、平均、最高、最低
total <- sum(sales) # 求和
avg <- mean(sales) # 平均
cat("\n总销售:", total, "万元\n")
cat("平均销售:", avg, "万元\n")
cat("最高销售:", max(sales), "万元\n")
cat("最低销售:", min(sales), "万元\n")
# 3. 算术运算:利润(30% 利润率)
profit_rate <- 0.3
profit <- sales * profit_rate # 向量 × 标量
cat("\n利润总额:", sum(profit), "万元\n")
# 4. 比较 + 逻辑:找出高于平均的分店
is_above_avg <- sales > avg # 比较:哪些高于平均
cat("\n高于平均的分店:")
print(sales[is_above_avg])
# 5. 比较 + 逻辑:找出低销售分店(< 1,000,000)
is_low <- sales < 100
cat("\n低销售分店(< 1,000,000):")
print(sales[is_low])
# 6. 整数运算:利润取整 + 分组
profit_int <- profit %/% 1 # 整数除法(向下取整)
cat("\n利润取整:")
print(profit_int)
# 7. %in% 筛选
target_cities <- c("北京", "上海", "广州")
selected <- sales[names(sales) %in% target_cities]
cat("\n目标城市销售:")
print(selected)
预期输出(节选):
原始销售数据(万元):
北京 上海 深圳 广州 杭州
120 150 80 200 175
总销售: 725 万元
平均销售: 145 万元
最高销售: 200 万元
最低销售: 80 万元
高于平均的分店:
广州 杭州
200 175
利润总额: 217.5 万元
低销售分店(< 1,000,000):
深圳
80
❓ 常见问题
%% 和 %/% 区别是什么?%% 是取模(返回余数),%/% 是整数除法(返回商)。例如 7 %/% 2 = 3(商),7 %% 2 = 1(余数)。在分页、时间转换、分组场景极其常用。& 和 && 该用哪个?&(向量化,判断所有元素);if 条件用 &&(短路求值,只判断第一个元素)。R 不像其他语言严格区分,但用错会导致 if 条件判断错误。📖 小节
- 4 大类运算符:算术(
+ - * / ^ %% %/%)、比较(== != < > <= >=)、逻辑(& \| !)、赋值(<- = -> <<-) - R 特色:整数除法
%%%/%、向量化的"广播"行为、%in%成员判断 - 向量 + 标量 = 标量广播到每个元素;向量 + 向量 = 对应元素运算
- 字符串比较按 ASCII 编码(不是数值),数字字符要
as.numeric()转 if条件用&&\|\|(短路求值),向量逻辑用&\|(向量化)- 运算符有优先级,不确定就加括号(可读性 > 简洁性)
NA == 5结果是NA(不是 TRUE/FALSE),要用is.na()判断
📝 作业
-
基础题:用 R 算 1+2+3+...+100,用 3 种方法:①
sum(1:100)② 循环 ③ 公式n(n+1)/2。验证三者结果一致。 -
基础题:把秒数
total_seconds <- 3725转换"时:分:秒"格式(参考本课整数除法示例),把代码和输出截图保存。 -
基础题:用
%in%找出向量c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)中的偶数(用c(2, 4, 6, 8, 10) %in%的方式),把输出截图。 -
进阶题:构造 5 个学生成绩
scores <- c(85, 92, 78, 95, 88),用比较 + 逻辑运算符完成:① 找出 90 分以上的分数 ② 找出 60-89 之间的分数 ③ 统计 80 分以上的人数。 -
挑战题:写一段脚本,用
sample(1:100, 20)随机生成 20 个数字,统计:① 有多少个偶数(%% 2 == 0)② 有多少个能被 3 整除(%% 3 == 0)③ 有多少个同时是偶数且能被 3 整除(&组合条件)④ 计算这些数字的总和与平均。