|
| 1 | +--- |
| 2 | +title: R 语言中的数学函数 |
| 3 | +description: R 提供了广泛的内置数学函数,方便进行各种数学运算、计算和分析。本文将介绍 R 中常用的数学函数及其应用,包括 round、max、sqrt、log、sin、crossprod 等 |
| 4 | +date: "2025-07-21" |
| 5 | +lang: zh |
| 6 | +tags: |
| 7 | + - R |
| 8 | + - 数据分析 |
| 9 | + - 数学 |
| 10 | +category: 笔记 |
| 11 | +cover: https://cdn.qladgk.com/images/20250721134728901.png |
| 12 | +--- |
| 13 | + |
| 14 | +import Image from "@/components/mdx/Image"; |
| 15 | + |
| 16 | +<Image |
| 17 | + src="https://cdn.qladgk.com/images/20250721134728901.png" |
| 18 | + alt="cover" |
| 19 | + width={999} |
| 20 | + height={527} |
| 21 | + isArticleImage={true} |
| 22 | +/> |
| 23 | + |
| 24 | +## 取整函数 |
| 25 | + |
| 26 | +R 提供了几个用于对小数进行取整的函数,这些函数包括 round 、 ceiling 、 floor 、 trunc 和 signif 函数 |
| 27 | + |
| 28 | +### round 函数 |
| 29 | + |
| 30 | +R 中最常见的取整函数就是 `round` 函数。它会把小数进行四舍五入为最接近的整数,如果小数部分等于 0.5,则取离它最近的偶数。 |
| 31 | + |
| 32 | +```R |
| 33 | +x <- c(2, 4.5, 5.6534, 9.18, -1.5, -8.35, -10.78) |
| 34 | +round(x) |
| 35 | + |
| 36 | +# 输出 2 4 6 9 -2 -8 -11 |
| 37 | +``` |
| 38 | + |
| 39 | +这种取整方法称作半偶数舍入(Round Half to Even),也称为“银行家舍入”或“四舍、六入、五留双” |
| 40 | + |
| 41 | +比如十进制: |
| 42 | + |
| 43 | +```md |
| 44 | +0.5 --> 0 |
| 45 | +1.5 --> 2 |
| 46 | +2.5 --> 2 |
| 47 | +3.5 --> 4 |
| 48 | +``` |
| 49 | + |
| 50 | +这种半偶数舍入的方法采用的是一种统计学上更为合理的取整方式,能够减少累积误差 |
| 51 | + |
| 52 | +对比四舍五入和半偶数舍入的区别: |
| 53 | + |
| 54 | +| 数据 | 四舍五入 | 半偶数舍入 | |
| 55 | +| ---- | -------- | ---------- | |
| 56 | +| 0 | 0 | 0 | |
| 57 | +| 0.5 | 1 | 0 | |
| 58 | +| 1 | 1 | 1 | |
| 59 | +| 1.5 | 2 | 2 | |
| 60 | +| 2 | 2 | 2 | |
| 61 | +| 2.5 | 3 | 2 | |
| 62 | +| 3 | 3 | 3 | |
| 63 | + |
| 64 | +取总和分别为:10.5、12、10 |
| 65 | + |
| 66 | +可看出半偶数舍入将一半向下舍入(前一个数字为偶数),一半向上舍入(前一个数字为奇数)来保持总和更稳定,因此舍入的效果大致抵消 |
| 67 | + |
| 68 | +但是此函数主要用例是使用名为 digits 的参数将值取整到特定的小数位数,比如取整小数点后两位:`round(x, digits = 2)` 或者 `round(x, 2)` |
| 69 | + |
| 70 | +```R |
| 71 | +x <- c(2.153, 4.557, 5.665, 9.1255) |
| 72 | +round(x, 2) |
| 73 | + |
| 74 | +# 输出 2.15 4.56 5.66 9.13 |
| 75 | +``` |
| 76 | + |
| 77 | +可能你会疑问为什么 9.1255 为什么取整后是 9.13 而不是 9.12?这是因为刚才上文提到:**它会把小数进行四舍五入为最接近的整数,如果小数部分等于 0.5,则取离它最近的偶数。** |
| 78 | + |
| 79 | +所以当我们用 round(9.1255, 2) 时,如果舍入位恰好等于 0.5(即后面全是 0),则才会取离它最近的偶数,即才会触发银行家舍入 |
| 80 | + |
| 81 | +而当前的舍入位是 0.0055,大于 0.005,因此会直接四舍五入到 9.13 |
| 82 | + |
| 83 | +请注意,如果 digits 参数为负数,则会将数字舍入到小数点左侧的位数 |
| 84 | + |
| 85 | +```R |
| 86 | +x <- c(2, 4.5, 5, 5.1, 10, 15, -10.5, -10.51) |
| 87 | +round(x, digits = -1) |
| 88 | + |
| 89 | +# 输出 0 0 0 10 10 20 -10 -10 |
| 90 | +``` |
| 91 | + |
| 92 | +当 `digits = -1` 时,round() 把数值“按 10 位”取整,也就是保留到**十位**(个位及以下的数字全部变为 0)。 |
| 93 | +负号只表示方向,不影响舍入规则本身;规则仍然是: |
| 94 | + |
| 95 | +- 先看真正要被舍掉的那一位(个位)上的数字 |
| 96 | +- 如果是 0–4 → 向下舍 |
| 97 | +- 如果是 6–9 → 向上入 |
| 98 | +- 如果恰好是 5 且后面全是 0 → “五留双”(取离它最近的偶数十位) |
| 99 | + |
| 100 | +逐项验证: |
| 101 | + |
| 102 | +| 原值 | 看个位数字 | 规则说明 | 结果 | |
| 103 | +| ------ | ---------- | -------------------------- | ---- | |
| 104 | +| 2 | 2 | 个位 2 < 5 → 向下舍 | 0 | |
| 105 | +| 4.5 | 4 | 个位 4 < 5 → 向下舍 | 0 | |
| 106 | +| 5 | 5 | 个位 5 且后面全 0 → 五留双 | 0 | |
| 107 | +| 5.1 | 5 | 个位 5 后非 0(.1)→ 六入 | 10 | |
| 108 | +| 10 | 0 | 个位 0 < 5 → 向下舍 | 10 | |
| 109 | +| 15 | 5 | 个位 5 且后面全 0 → 五留双 | 20 | |
| 110 | +| –10.5 | 0 | 个位 0 < 5 → 向下舍 | –10 | |
| 111 | +| –10.51 | 0 | 个位 0 < 5 → 向下舍 | –10 | |
| 112 | + |
| 113 | +当 `digits = -k` 时,把数值按 $$10^k$$ 位取整即可。 |
| 114 | + |
| 115 | +同理如下: |
| 116 | + |
| 117 | +```R |
| 118 | +round(15,-1) # 20 |
| 119 | +round(15,-2) # 0 |
| 120 | +round(55,-2) # 100 |
| 121 | +``` |
| 122 | + |
| 123 | +### floor 和 ceiling 函数 |
| 124 | + |
| 125 | +`floor` 函数用于向下取整,即返回小于或等于给定值的最大整数。它不会进行四舍五入,而是直接向下取整到最接近的整数。 |
| 126 | + |
| 127 | +```R |
| 128 | +x <- c(2, 4.5, 5.6534, 9.18, -1.5, -8.35, -10.78) |
| 129 | +floor(x) |
| 130 | + |
| 131 | +# 输出 2 4 5 9 -2 -9 -11 |
| 132 | +``` |
| 133 | + |
| 134 | +floor 的反函数是 ceiling ,它将值向上舍入为不小于该值本身的最小整数。 |
| 135 | + |
| 136 | +```R |
| 137 | +x <- c(2, 4.5, 5.6534, 9.18, -1.5, -8.35, -10.78) |
| 138 | +ceiling(x) |
| 139 | + |
| 140 | +# 输出 2 5 6 10 -1 -8 -10 |
| 141 | +``` |
| 142 | + |
| 143 | +这两个函数与 round(x) 的半偶数舍入不同,它们没有“四舍六入五留双”的逻辑,而是无条件地向下或向上取整。 |
| 144 | + |
| 145 | +它们的优势主要体现在业务语义简单、可预测、易实现。比如某些运营商不足一分钟按一分钟收费 |
| 146 | + |
| 147 | +满足“绝不超发/绝不缺额”这类硬性业务约束,代价是单次和长期都可能出现系统性偏差。 |
| 148 | + |
| 149 | +### trunc 函数 |
| 150 | + |
| 151 | +`trunc` 函数用于截断小数部分,直接返回整数部分。它不会进行四舍五入,而是简单地去掉小数部分。 |
| 152 | + |
| 153 | +```R |
| 154 | +x <- c(2, 4.5, 5.6534, 9.18, -1.5, -8.35, -10.78) |
| 155 | +trunc(x) |
| 156 | + |
| 157 | +# 输出 2 4 5 9 -1 -8 -10 |
| 158 | +``` |
| 159 | + |
| 160 | +trunc(truncate,截断)的核心优势只有一句话:速度最快、规则最简单、结果绝对可预测,且天然满足“只保留整数部分,绝不引入额外偏移”的需求。 |
| 161 | + |
| 162 | +### signif 函数 |
| 163 | + |
| 164 | +signif 函数用于将值舍入到指定的有效数字位数(默认为 6 位)。 |
| 165 | + |
| 166 | +```R |
| 167 | +x <- c(2, 4.5, 5.6534, 9.18, -1.5, -8.35, -10.78) |
| 168 | +signif(x) |
| 169 | + |
| 170 | +# 输出 2.0000 4.5000 5.6534 9.1800 -1.5000 -8.3500 -10.7800 |
| 171 | +``` |
| 172 | + |
| 173 | +此函数还允许您使用 digits 参数指定所需的有效数字数。 |
| 174 | + |
| 175 | +```R |
| 176 | +x <- c(2, 4.5, 5.6534, 9.18, -1.5, -8.35, -10.78) |
| 177 | +signif(x, digits = 3) |
| 178 | + |
| 179 | +# 输出 2.00 4.50 5.65 9.18 -1.50 -8.35 -10.80 |
| 180 | +``` |
| 181 | + |
| 182 | +至于这里你可能会疑惑 `signif(2)` 为什么显示的是 `2.0000` 而不是 `2.00000`。以及 `signif(-10.78)` 为什么显示的是 `-10.80` 而不是 `-10.8`。 |
| 183 | + |
| 184 | +这是因为打印规则和计算规则不是一套东西,signif() 计算时的确会保留 6 位有效数字,但打印时会根据实际情况进行格式化。 |
| 185 | + |
| 186 | +## 最值函数 |
| 187 | + |
| 188 | +R 中最值函数有 max、min、pmax、pmin。 |
| 189 | + |
| 190 | +### max 和 min 函数 |
| 191 | + |
| 192 | +max 和 min 将分别返回单个向量的最大值和最小值,它只返回一个值。 |
| 193 | + |
| 194 | +```R |
| 195 | +x <- c(45, 12, 12, 15, 61, 56) |
| 196 | +max(x) |
| 197 | +min(x) |
| 198 | + |
| 199 | +# 输出:61 12 |
| 200 | +``` |
| 201 | + |
| 202 | +但是,如果向量包含缺失值( NA ),则该函数将返回 NA 。 |
| 203 | + |
| 204 | +```R |
| 205 | +x <- c(45, 12, 12, NA, 15, 61, 56) |
| 206 | +max(x) |
| 207 | + |
| 208 | +# 输出:NA |
| 209 | +``` |
| 210 | + |
| 211 | +如果您想避免这种情况,可以将函数的 na.rm 参数设置为 TRUE ,这样在获取最大值之前就会删除缺失值。 |
| 212 | + |
| 213 | +```R |
| 214 | +x <- c(45, 12, 12, NA, 15, 61, 56) |
| 215 | +max(x, na.rm = TRUE) |
| 216 | + |
| 217 | +# 输出:61 |
| 218 | +``` |
| 219 | + |
| 220 | +### pmax 和 pmin 函数 |
| 221 | + |
| 222 | +pmax 和 pmin 函数用于计算多个向量的逐元素最大值和最小值。它们可以接受多个向量作为参数,并返回一个新的向量,其中每个元素是对应位置上所有输入向量的最大值或最小值。 |
| 223 | + |
| 224 | +```R |
| 225 | +x1 <- c(45, 12, 12, 15, 61, 56) |
| 226 | +x2 <- c(15, 35, 81, 23, 45, 24) |
| 227 | +x3 <- c(52, 12, 41, 35, 17, 16) |
| 228 | + |
| 229 | +pmax(x1, x2, x3) |
| 230 | + |
| 231 | +# 输出:52 35 81 35 61 56 |
| 232 | +``` |
| 233 | + |
| 234 | +返回的第一个值是 52,因为它是 45、15 和 52 之间的最大值;返回的第二个值是 35,因为它是 12、35 和 12 之间的最大值,以此类推。 |
| 235 | + |
| 236 | +如果向量的长度不一致,pmax 和 pmin 函数会自动将短向量扩展到与最长向量的长度一致。 |
| 237 | + |
| 238 | +```R |
| 239 | +x1 <- c(45, 12, 12, 15, 30, 56) |
| 240 | +x2 <- c(15, 35, 81) |
| 241 | +x3 <- c(52, 12) |
| 242 | + |
| 243 | +pmax(x1, x2, x3) |
| 244 | + |
| 245 | +# 输出:52 35 81 15 52 81 |
| 246 | +``` |
| 247 | + |
| 248 | +扩展的方式是循环补齐 |
| 249 | + |
| 250 | +x2 补齐后:15 35 81 15 35 81 |
| 251 | + |
| 252 | +x3 补齐后:52 12 52 12 52 12 |
| 253 | + |
| 254 | +最后输出的 81 是在 12、81、52 中最大的值;35 是在 15、15、12 中的最大值;52 是在 30、35、52 中的最大值... |
| 255 | + |
| 256 | +这种“循环补齐 + 逐元素比较”的设计,优势可以一句话概括为:用最少的代码,让不同长度、成组比较的向量运算既简洁又符合向量化思维,同时保持与 R 其它运算一致的回收(recycling)语义。 |
| 257 | + |
| 258 | +## 平方根 |
| 259 | + |
| 260 | +一个数的平方根是指一个数乘以自身等于该数的数。例如,4 的平方根是 2,因为 $$2 * 2 = 4$$ |
| 261 | + |
| 262 | +### sqrt 函数 |
| 263 | + |
| 264 | +在 R 中,`sqrt` 函数用于计算一个数的平方根。例如: |
| 265 | + |
| 266 | +```R |
| 267 | +sqrt(4) |
| 268 | + |
| 269 | +# 输出 2 |
| 270 | +``` |
| 271 | + |
| 272 | +同时,还可以输入数字向量,因此该函数将返回该向量每个元素的平方根。 |
| 273 | + |
| 274 | +```R |
| 275 | +sqrt(c(1, 4, 9)) |
| 276 | + |
| 277 | +# 输出 1 2 3 |
| 278 | +``` |
| 279 | + |
| 280 | +如果想计算 N 次方根,可以使用 `^` 运算符来手动计算,比如 8 的三次根: |
| 281 | + |
| 282 | +```R |
| 283 | +8^(1/3) |
| 284 | + |
| 285 | +# 输出 2 |
| 286 | +``` |
| 287 | + |
| 288 | +## 指数和对数 |
| 289 | + |
| 290 | +可以利用 R 提供的函数来计算对数和指数: log 函数用于计算自然对数,而 exp 函数用于计算指数。 |
| 291 | + |
| 292 | +### log 函数 |
| 293 | + |
| 294 | +log 函数用于计算自然对数,`exp(1)` 返回 e 的值(约等于 2.71828),`log(x)` 默认返回 x 的自然对数。 |
| 295 | + |
| 296 | +```R |
| 297 | +log(1) # 输出 0 |
| 298 | +log(exp(1)) # 输出 1 |
| 299 | +``` |
| 300 | + |
| 301 | +同时可以自定义底数,例如: |
| 302 | + |
| 303 | +```R |
| 304 | +log(9, 3) # 输出 9 的 3 的对数 |
| 305 | +log(8, 2) # 输出 8 的 2 的对数 |
| 306 | + |
| 307 | +# 输出 2 3 |
| 308 | +``` |
| 309 | + |
| 310 | +### exp 函数 |
| 311 | + |
| 312 | +exp 函数用于计算 e 的幂次方,`exp(x)` 返回 e 的 x 次方。 |
| 313 | + |
| 314 | +```R |
| 315 | +exp(10) |
| 316 | +exp(0) |
| 317 | +exp(-5) |
| 318 | +exp(4) |
| 319 | + |
| 320 | +# 输出 22026.47 1 0.006737947 54.59815 |
| 321 | +``` |
| 322 | + |
| 323 | +### plot 绘图函数 |
| 324 | + |
| 325 | +plot 函数可以用来绘制函数图像,下面是绘制自然对数的 log 和 exp 函数的示例: |
| 326 | + |
| 327 | +```R |
| 328 | +plot(log, 0, 1, col = 4, main = "log(x)") |
| 329 | +plot(exp, -10, 10, col = 4, main = "exp(x)") |
| 330 | +``` |
| 331 | + |
| 332 | +<Image |
| 333 | + src="https://cdn.qladgk.com/images/20250721210335800.png" |
| 334 | + alt="log(x)" |
| 335 | + width={333} |
| 336 | + height={527} |
| 337 | + isArticleImage={true} |
| 338 | +/> |
| 339 | + |
| 340 | +<Image |
| 341 | + src="https://cdn.qladgk.com/images/20250721210350292.png" |
| 342 | + alt="exp(x)" |
| 343 | + width={333} |
| 344 | + height={527} |
| 345 | + isArticleImage={true} |
| 346 | +/> |
| 347 | + |
| 348 | +## 三角函数 |
| 349 | + |
| 350 | +R 提供了几个计算三角函数的函数,例如 cos()、sin()、tan()、acos()、asin() 和 atan() 函数,用于计算正弦、余弦、正切、反余弦、反正弦和反正切。 |
| 351 | + |
| 352 | +### cos、sin 和 tan 函数 |
| 353 | + |
| 354 | +```R |
| 355 | +cos(pi/3) # 输出 0.5 |
| 356 | +sin(pi/6) # 输出 0.5 |
| 357 | +tan(pi/4) # 输出 1 |
| 358 | +``` |
| 359 | + |
| 360 | +可以使用 `plot` 函数绘制这些函数的图像: |
| 361 | + |
| 362 | +```R |
| 363 | +plot(cos, 0, 2 * pi, col = 4, main = "cos(x)") |
| 364 | +plot(sin, 0, 2 * pi, col = 4, main = "sin(x)") |
| 365 | +plot(tan, -2 * pi, 2 * pi, col = 4, main = "tan(x)") |
| 366 | +``` |
| 367 | + |
| 368 | +### 反三角函数 |
| 369 | + |
| 370 | +```R |
| 371 | +acos(0.5) # 输出 1.0472 |
| 372 | +asin(0.5) # 输出 0.5236 |
| 373 | +atan(1) # 输出 0.7854 |
| 374 | +``` |
| 375 | + |
| 376 | +可以使用 `plot` 函数绘制这些函数的图像: |
| 377 | + |
| 378 | +```R |
| 379 | +plot(acos, -1, 1, col = 4, main = "acos(x)") |
| 380 | +plot(asin, -1, 1, col = 4, main = "asin(x)") |
| 381 | +plot(atan, -10, 10, col = 4, main = "atan(x)") |
| 382 | +``` |
| 383 | + |
| 384 | +## 矩阵运算 |
| 385 | + |
| 386 | +R 中可以执行多种矩阵运算,包括:加法、减法、乘法、计算幂、秩、行列式、对角线、特征值和特征向量、转置以及使用不同方法分解矩阵 |
| 387 | + |
| 388 | +由于篇幅太长,请期待下一篇文章 |
0 commit comments