10 Basic: regular operations

R 中可以执行各式各样的操作,这些操作都是通过使用 operator 或 function 实现。常见的操作有:

  • 基本数学运算
  • 关系和逻辑
  • 筛选和排序
  • 其他

注意:绝大多数 operators 和 functions 都支持 recycling rule(详见7.2.2)。

由于 subsetting operator 进阶用法的第二步是将拆解的步骤(操作)转换成相应的代码,所以本节中将重点演示如何将部分 operator 和 function 运用在 subsetting 中。

10.1 Basic mathematical operations

10.1.1 Arithmetic operators

+ - * / ^ %% %/% %*%

c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) %% 5  # 求余数
#>  [1] 1 2 3 4 0 1 2 3 4 0
c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) %/% 5  # 整除
#>  [1] 0 0 0 0 1 1 1 1 1 2
m1 <- matrix(c(1, 2, 3, 4, 5, 6), 3, 2)
m1
#>      [,1] [,2]
#> [1,]    1    4
#> [2,]    2    5
#> [3,]    3    6
m2 <- matrix(c(1, 2, 3, 4, 5, 6), 2, 3)
m2
#>      [,1] [,2] [,3]
#> [1,]    1    3    5
#> [2,]    2    4    6
m1 %*% m2   # 矩阵乘法
#>      [,1] [,2] [,3]
#> [1,]    9   19   29
#> [2,]   12   26   40
#> [3,]   15   33   51

10.1.2 Functions

10.1.2.1 Extremum and range

  • max(x)
  • min(x)
  • range(x)
m1 <- matrix(c(1, 2, 3, 4), 2, 2)
max(m1)
#> [1] 4
min(m1)
#> [1] 1
range(m1)
#> [1] 1 4

10.1.2.2 Sum

  • sum(x),连加求和 \(\sum_{i=1}^{n}x_i\)
  • rowSums(x),行求和;
  • colSums(x),列求和。
m1 <- matrix(c(1, 2, 3, 4), 2, 2)
m1
#>      [,1] [,2]
#> [1,]    1    3
#> [2,]    2    4
sum(m1)
#> [1] 10
rowSums(m1)  
#> [1] 4 6
colSums(m1)
#> [1] 3 7

10.1.2.3 Average

  • mean(x),均值 \(\frac{\sum_{i=1}^n(x_i)}{n}\)
  • rowMeans(x),行均值;
  • colMeans(x),列均值。
m1 <- matrix(c(1, 2, 3, 4), 2, 2)
m1
#>      [,1] [,2]
#> [1,]    1    3
#> [2,]    2    4
mean(m1)
#> [1] 2.5
rowMeans(m1)
#> [1] 2 3
colMeans(m1)
#> [1] 1.5 3.5

10.1.2.4 Product

prod(x),连乘求积 \(\prod_{i=1}^nx_i=x_1x_2\cdots x_n\)

m1 <- matrix(c(1, 2, 3, 4), 2, 2)
prod(m1)
#> [1] 24

10.1.2.5 Round

  • round(x, digits = 0),取整,规则是 4 舍 6 入,逢 5 成双,即逢 5 时向最近的偶数取整,保留digits位小数,默认为 0;
  • floor(x),向下取整;
  • ceiling(x),向上取整;
  • trunc(x),保留整数部分,舍弃小数部分。
m1 <- matrix(c(-1.1, -2.5, 3.9, 4.6), 2, 2)
m1
#>      [,1] [,2]
#> [1,] -1.1  3.9
#> [2,] -2.5  4.6
round(m1)
#>      [,1] [,2]
#> [1,]   -1    4
#> [2,]   -2    5
floor(m1)  
#>      [,1] [,2]
#> [1,]   -2    3
#> [2,]   -3    4
ceiling(m1)  
#>      [,1] [,2]
#> [1,]   -1    4
#> [2,]   -2    5
trunc(m1)
#>      [,1] [,2]
#> [1,]   -1    3
#> [2,]   -2    4

10.1.2.6 Natrual exponential and logorithm

exp(x),自然指数 \(e^{x}\)

exp(0)
#> [1] 1
exp(1)
#> [1] 2.718282

log(x, base = exp(1)),对数 \(\log_{base}x\)base的默认值是exp(1)

log(1)
#> [1] 0
log(10, 10)
#> [1] 1

10.1.2.7 Others

  • Square root: sqrt(x),即\(\sqrt{x}\)
  • Trigonometric Functions: sin(x)cos(x)tan(x)
  • Absolute value: abs(x),即\(|x|\)
  • Sign:(正数输出 1,负数输出 -1)

sign(x)

sign(c(-1, 2, -sqrt(2)))
#> [1] -1  1 -1
  • Transpose

t(x),即\(x'\)\(x^T\),将x转置(沿主对角线反转,行列互换),x可以是 matrix 或 data.frame。

a <- matrix(c(1, 2, 3, 4, 5, 6), 3, 2)
a
#>      [,1] [,2]
#> [1,]    1    4
#> [2,]    2    5
#> [3,]    3    6
t(a)
#>      [,1] [,2] [,3]
#> [1,]    1    2    3
#> [2,]    4    5    6

例子:数据转换(Skewed Distribution: Definition, Examples

data$Population <- log(data$Population, base = 10)
data$Area <- log(data$Area, base = 10)

10.2 Relational and Logical operators

10.2.1 Relational operators

><>=<===!=。这些 operators 返回的结果都是 logical:

m1 <- matrix(c(-1, -2, 0, 4), 2, 2)
# 以下代码全部都受到 recycling rule 的作用
m1 > 0
#>       [,1]  [,2]
#> [1,] FALSE FALSE
#> [2,] FALSE  TRUE
m1 < 0
#>      [,1]  [,2]
#> [1,] TRUE FALSE
#> [2,] TRUE FALSE
m1 >= 0
#>       [,1] [,2]
#> [1,] FALSE TRUE
#> [2,] FALSE TRUE
m1 <= 0
#>      [,1]  [,2]
#> [1,] TRUE  TRUE
#> [2,] TRUE FALSE
m1 == 0
#>       [,1]  [,2]
#> [1,] FALSE  TRUE
#> [2,] FALSE FALSE
m1 != 0
#>      [,1]  [,2]
#> [1,] TRUE FALSE
#> [2,] TRUE  TRUE

其中,在使用==时需要注意,object == NAobject == NaNobject == NULL都是错误写法:

1 == NA
#> [1] NA
1 == NaN
#> [1] NA
1 == NULL
#> logical(0)

若想要检测某个 object 究竟是不是NANaNNULL,正确的写法应该是:

is.na(c(1, 2, NA))
#> [1] FALSE FALSE  TRUE
is.nan(c(1, 2, NaN))
#> [1] FALSE FALSE  TRUE
is.null(c(1, 2, NULL))
#> [1] FALSE

Relational operators 在 subsetting 的进阶写法中十分常用。例如,实训 3-2 第 1 题第 4 小问,剔除“Pick场数”低于 200 的英雄的所有数据:

library(openxlsx)
data_ori <- read.xlsx("F:/Nutstore backup/R/codes/RBA/data/Arena of Valor_midterm dataset.xlsx")
head(data_ori)
#>     角色名 职业 移速 攻击范围 生存能力 攻击伤害 上手难度
#> 1       曜 战士  370     近程        5        7        6
#> 2     西施 法师  360     远程        6        8        6
#> 3     嫦娥 法师  395     远程       10       10        5
#> 4     盘古 战士  380     近程       10        8        6
#> 5       瑶 辅助  360     远程       10        7        5
#> 6 上官婉儿 法师  396     远程        5        7        6
#>   Pick场数 总击杀 场均击杀 场均死亡 场均助攻 Ban场数 胜率
#> 1       11     16     1.45     2.00     3.45       1 0.45
#> 2      175    222     1.27     1.62     6.90     161 0.54
#> 3       64    168     2.58     1.86     5.11      80 0.46
#> 4       95    248     2.61     2.61     5.41      50 0.49
#> 5       53     24     0.45     2.49     7.19      66 0.40
#> 6       55    163     2.96     3.24     3.78      74 0.45
#>   Ban率 热度
#> 1  0.00 0.01
#> 2  0.20 0.42
#> 3  0.10 0.18
#> 4  0.06 0.18
#> 5  0.08 0.15
#> 6  0.09 0.16
data_200 <- data_ori[c(-7, -13, -15, -16)]
data_200 <- data_200[data_200[, 7] >= 200, ]

Basic mathematical operations 和 relational operators 的组合也是 subsetting 进阶写法中常用手段。例如,取绝对值最大的数:

a <- c(-0.1, -0.9, 0.2, 0.4)
a[abs(a) == max(abs(a))]
#> [1] -0.9

10.2.2 Logical operator

10.2.2.1 & and &&

基本结构:LHS & RHSLHS && RHS

LHS(left hand side)和RHS(right hand side)的结果是长度为 1 的 logical vector 时,&&&等价。

LHS RHS 结果
TRUE TRUE TRUE
TRUE FALSE FALSE
FALSE TRUE FALSE
FALSE FALSE FALSE
a <- 3
a > 2 & a < 4
#> [1] TRUE
a > 2 && a < 4
#> [1] TRUE

LHSRHS的结果是长度大于 1 的 logical vector 时,&&&的结果不同。&会比较左右两侧的 logical vector 中每一对 element,&&会从左往右比,直到有结果为止,本质上相当于只会比较第一个位置上的那对 elements,也正是因为如此,从 4.3.0 开始,R 强制要求&&LHSRHS的长度只能为1(因为只比第一个位置),否则就报错,这点在&&的帮助页面也有明确说明(详见?`&&`):

a <- c(1, 2, 3, 4, 5)
a >= 1
#> [1] TRUE TRUE TRUE TRUE TRUE
a <= 3
#> [1]  TRUE  TRUE  TRUE FALSE FALSE
a >= 1 & a <= 3
#> [1]  TRUE  TRUE  TRUE FALSE FALSE
a >= 1 && a <= 3
#> Error in a >= 1 && a <= 3: 'length = 5' in coercion to 'logical(1)'

10.2.2.2 | and ||

基本结构:LHS | RHSLHS || RHS

LHS(left hand side)和RHS(right hand side)的结果是长度为 1 的 logical vector 时,|||等价。

LHS RHS 结果
TRUE TRUE TRUE
TRUE FALSE TRUE
FALSE TRUE TRUE
FALSE FALSE FALSE
a <- 6
a < 2 | a > 4
#> [1] TRUE
a < 2 || a > 4
#> [1] TRUE

LHSRHS(的结果是长度大于 1 的 logical vector 时,|会比较左右两侧的 logical vector 中每一对 element,||则会报错:

a <- c(1, 2, 3, 4, 5)
a <= 2
#> [1]  TRUE  TRUE FALSE FALSE FALSE
a >= 4
#> [1] FALSE FALSE FALSE  TRUE  TRUE
a <= 2 | a >= 4
#> [1]  TRUE  TRUE FALSE  TRUE  TRUE
a >= 1 || a <= 3
#> Error in a >= 1 || a <= 3: 'length = 5' in coercion to 'logical(1)'

注意,如果&|左右两边的expr长度不一,会触发 recycling rule (详见7.2.2)。

c(T, F, T) & T
#> [1]  TRUE FALSE  TRUE
c(T, F, T) | T
#> [1] TRUE TRUE TRUE

10.2.2.3 !

基本结构:!expr。若expr的结果是TRUE,则改为FALSE;若FALSE则改为TRUE

a <- c(1, 2, 3, 4, 5)
a <= 2
#> [1]  TRUE  TRUE FALSE FALSE FALSE
!(a <= 2)
#> [1] FALSE FALSE  TRUE  TRUE  TRUE
!is.na(a)
#> [1] TRUE TRUE TRUE TRUE TRUE

Relational operator 和 logical operator 组合使用,可以非常便捷完成按照指定条件 subsetting 的任务,尤其是当需要满足的条件较多时:

m1 <- matrix(runif(25), 5, 5)
m1
#>            [,1]       [,2]       [,3]      [,4]       [,5]
#> [1,] 0.57370498 0.43489448 0.52609125 0.3554697 0.20126258
#> [2,] 0.06256437 0.11917803 0.05469695 0.2809621 0.82696419
#> [3,] 0.19686506 0.08152689 0.63271265 0.2232933 0.12183070
#> [4,] 0.94185075 0.16766296 0.13675526 0.5326987 0.06381132
#> [5,] 0.44141196 0.93798399 0.02352414 0.4560850 0.59050340
m1[m1 > 0.2 & m1 < 0.8]
#>  [1] 0.5737050 0.4414120 0.4348945 0.5260912 0.6327127
#>  [6] 0.3554697 0.2809621 0.2232933 0.5326987 0.4560850
#> [11] 0.2012626 0.5905034
m1[m1 < 0.3 | m1 > 0.7]
#>  [1] 0.06256437 0.19686506 0.94185075 0.11917803 0.08152689
#>  [6] 0.16766296 0.93798399 0.05469695 0.13675526 0.02352414
#> [11] 0.28096210 0.22329330 0.20126258 0.82696419 0.12183070
#> [16] 0.06381132
m1[!(m1 < 0.3 | m1 > 0.7)]
#> [1] 0.5737050 0.4414120 0.4348945 0.5260912 0.6327127
#> [6] 0.3554697 0.5326987 0.4560850 0.5905034

10.3 Locate, match and sort

10.3.1 Locate

which(x),输出x中所有TRUE的位置信息,x必须是一个 logical object。

a <- runif(5)
a
#> [1] 0.618697154 0.008241073 0.923343584 0.651533403
#> [5] 0.460722383
which(a == max(a))
#> [1] 3
which(a > 0.5)
#> [1] 1 3 4
which(a > 0.1 & a < 0.9)
#> [1] 1 4 5

使用which()通常不是为了将符合条件的元素取出,而是为了将这些元素的位置找出来,起个名字并保存在 Environment 里,方便后续单独处理这些元素的时候可以直接使用位置索引信息来定位。如果只是需要将符合条件的所有元素取出来,只用 relational operator 就足够了。

a <- runif(5)
a
#> [1] 0.51959313 0.25863443 0.25124994 0.08972298 0.96680015
a[which(a > 0.5)]
#> [1] 0.5195931 0.9668002
a[a > 0.5]
#> [1] 0.5195931 0.9668002

如果x是一个有dimarraymatrixwhich(x)可以通过设定arr.ind = TRUE来输出按dim标识的 index:

m1 <- matrix(1:4, 2, 2)
which(m1 == 3, arr.ind = TRUE)
#>      row col
#> [1,]   1   2

10.3.2 Match

%in%: 返回一个和逻辑向量,表示左边的值在右边的依据值中是否有匹配。

x %in% table

  • x: 被匹配的值。
  • table: 匹配时依据的值。
vec <- c(1, 2, 3)
vec_all <- c(6, 1, 5, 6, 1, 4, 4, 2, 10, 5)
vec %in% vec_all
#> [1]  TRUE  TRUE FALSE
vec_all %in% vec
#>  [1] FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE
#> [10] FALSE

%in%可以用于挑选数据的指定列,例如:

vars <- c("x", "y", "z")
df <- 
  data.frame(
    x = sample(5, 10, replace = TRUE), 
    n = sample(5, 10, replace = TRUE), 
    z = sample(5, 10, replace = TRUE), 
    m = sample(5, 10, replace = TRUE), 
    n = sample(5, 10, replace = TRUE), 
    y = sample(5, 10, replace = TRUE)
  )
df_select <- df[names(df) %in% vars]
df_select
#>    x z y
#> 1  1 5 1
#> 2  3 4 2
#> 3  3 1 5
#> 4  5 1 4
#> 5  5 2 2
#> 6  1 1 5
#> 7  3 5 3
#> 8  4 2 5
#> 9  1 5 3
#> 10 5 2 3

%in%对于匹配的定义比==考虑的更完备,对一些特殊的匹配情况做了处理,如NA,只有匹配NA时才会返回TRUE的结果,否则返回FALSE

c(1, NA, 3) %in% c(1:10)
#> [1]  TRUE FALSE  TRUE
c(1, NA, 3) %in% NA # equivalent to is.na(c(1, NA, 3))
#> [1] FALSE  TRUE FALSE

正是因为%in%考虑更加完备,故%in%可以替代==,用在 subsetting 上,

df <- data.frame(x = c(1, NA, 1, 2, 4), y = c(2, 1, 1, 3, 5))
df$x == 1
#> [1]  TRUE    NA  TRUE FALSE FALSE
df[df$x == 1 & df$y == 1, ]
#>     x  y
#> NA NA NA
#> 3   1  1
df[df$x %in% 1 & df$y %in% 1, ]
#>   x y
#> 3 1 1

10.3.3 Sort

  • sort(x, decreasing = FALSE),将x升序排列(默认),输出排列后的xdecreasing是可选 argument。decreasing = TRUE则是按照降序排序列。
a <- runif(5)
a
#> [1] 0.1706297 0.6695226 0.6012747 0.2188392 0.6463490
sort(a)
#> [1] 0.1706297 0.2188392 0.6012747 0.6463490 0.6695226
sort(a, decreasing = TRUE)
#> [1] 0.6695226 0.6463490 0.6012747 0.2188392 0.1706297
  • order(..., decreasing = FALSE)...是需一个或多个objectdecreasing是可选argumentdecreasing = TRUE表示按照降序排序列。

order()输出的其实是 object 中的元素应该各自调整到哪个位置才能实现排序(升序或降序)。所以,order()实际上给出的是位置信息。

  1. 无重复元素
a <- c(5, 1, 8, 2.5)
order(a)
#> [1] 2 4 1 3
order(a, decreasing = TRUE)
#> [1] 3 1 4 2
  1. 有重复元素

当输入的单个object有重复元素(即ties,表示一个独特的值同时有多个位置索引)时,默认是按照元素出现的先后顺序来排序,

a <- c(5, 1, 8, 1)
order(a)
#> [1] 2 4 1 3
order(a, decreasing = TRUE)
#> [1] 3 1 2 4

如果有额外的线索可以区分重复元素时,order()可以将这些重复元素按照额外线索排序,

score <- c(90, 95, 99, 95)
id <- c(4, 3, 2, 1)
order(score, id)
#> [1] 1 4 2 3
order(score, id, decreasing = TRUE)
#> [1] 3 2 4 1

总结一下,当输入 1 个 object 时,order()排序的是这个object;当输入多个object时(这些object都必须是同样长度),order()排序的依旧是第一个object,只不过该 object 中的重复元素是以第 2 个 object 中对应位置上的元素大小为依据,若这些元素依旧是重复的,则按照第 3 个 object 中对应位置上的元素大小为依据,依此类推。

order()常用于根据某一列重新排列整个数据。例如根据score_math降序排列:

data_set1 <- data.frame(name = c("小红", "小明", "小白", "小黑"), 
                        id = c(1, 4, 2, 3),
                        score_math = c(90, 95, 98, 95))
data_set1[order(data_set1$score_math, id, decreasing = TRUE), ]
#>   name id score_math
#> 3 小白  2         98
#> 2 小明  4         95
#> 4 小黑  3         95
#> 1 小红  1         90

order()对字符也有效,默认升序,数字按从小到大,英文按字母,中文按拼音顺序,三者的优先级是数字 > 英文字母 > 中文拼音:

vec_cha <- c("3", "2", "a", "b", "啊", "呀")
order(vec_cha)
#> [1] 2 1 3 4 5 6
vec_cha[order(vec_cha)]
#> [1] "2"  "3"  "a"  "b"  "啊" "呀"

10.4 Others

10.4.1 Combine

  • c(...),将多个 object 合并成一个 vector,...为要合并的 object。
  • cbind(...),将多个 objects,视作是 columns,将多个 object 横向合并成一个 object,...为要合并的 object。
  • rbind(...),将多个 objects 视作是 rows,纵向合并成一个 object,...为要合并的 object。
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(a, b)
#>   [,1] [,2] [,3]
#> a    1    2    3
#> b    4    5    6

10.4.2 Get the number of

  • length(x),返回x中 element 的个数;
  • nrow(x)NROW(x),返回x的行数,如果x没有行数的信息,返回NULL
  • ncol(x)NCOL(x),返回x的列数,如果x没有列数的信息,返回NULL
  • nchar(x),返回x各 element 的字符个数。
df <- data.frame(number = c(1, 2, 3), letter = c("a", "b", "c"))
length(df)
#> [1] 2
nrow(df)
#> [1] 3
ncol(df)
#> [1] 2
fruits <- c("banana", "apple", "pineapple", "melon")
length(fruits)
#> [1] 4
nrow(fruits)
#> NULL
ncol(fruits)
#> NULL
nchar(fruits)
#> [1] 6 5 9 5

10.4.3 Generate sequence

10.4.3.1 Operator

from:to,生成有序整数数列。from为数列的起点;to为数列的终点。

1:100
#>   [1]   1   2   3   4   5   6   7   8   9  10  11  12  13
#>  [14]  14  15  16  17  18  19  20  21  22  23  24  25  26
#>  [27]  27  28  29  30  31  32  33  34  35  36  37  38  39
#>  [40]  40  41  42  43  44  45  46  47  48  49  50  51  52
#>  [53]  53  54  55  56  57  58  59  60  61  62  63  64  65
#>  [66]  66  67  68  69  70  71  72  73  74  75  76  77  78
#>  [79]  79  80  81  82  83  84  85  86  87  88  89  90  91
#>  [92]  92  93  94  95  96  97  98  99 100

:可以用来生成行索引,在需要分半数据进行统计分析(交叉验证,复本信度等)时快速取出数据子集。以英雄联盟数据集为例:

library(openxlsx)
data_ori <- read.xlsx("F:/Nutstore backup/R/codes/RBA/data/Arena of Valor_midterm dataset.xlsx")
data_subset1 <- data_ori[1:trunc(nrow(data_ori)/2), ]
data_subset2 <- data_ori[(trunc(nrow(data_ori)/2) + 1):nrow(data_ori), ]

10.4.3.2 Functions:

seq(from = 1, to = 1, by = ((to - from)/(length.out - 1)), length.out = NULL),生成有序数列。from为数列的起点,to为数列的终点。可选 argument:

  1. by为步长,即后一个数和前一个数之差;
  2. length.out为生成数列的长度。
seq()
#> [1] 1
seq(from = 1, to = 100)  # 等价于 1:100
#>   [1]   1   2   3   4   5   6   7   8   9  10  11  12  13
#>  [14]  14  15  16  17  18  19  20  21  22  23  24  25  26
#>  [27]  27  28  29  30  31  32  33  34  35  36  37  38  39
#>  [40]  40  41  42  43  44  45  46  47  48  49  50  51  52
#>  [53]  53  54  55  56  57  58  59  60  61  62  63  64  65
#>  [66]  66  67  68  69  70  71  72  73  74  75  76  77  78
#>  [79]  79  80  81  82  83  84  85  86  87  88  89  90  91
#>  [92]  92  93  94  95  96  97  98  99 100
seq(1, 100, by = 3)
#>  [1]   1   4   7  10  13  16  19  22  25  28  31  34  37  40
#> [15]  43  46  49  52  55  58  61  64  67  70  73  76  79  82
#> [29]  85  88  91  94  97 100
seq(1, 100, length.out = 34)
#>  [1]   1   4   7  10  13  16  19  22  25  28  31  34  37  40
#> [15]  43  46  49  52  55  58  61  64  67  70  73  76  79  82
#> [29]  85  88  91  94  97 100

seq()可以用于快速奇偶分半数据。以英雄联盟数据集为例:

library(openxlsx)
data_ori <- read.xlsx("F:/Nutstore backup/R/codes/RBA/data/Arena of Valor_midterm dataset.xlsx")
data_ori <- cbind(ID = 1:nrow(data_ori), data_ori)
data_subset1 <- data_ori[seq(1, nrow(data_ori), 2), ]
data_subset2 <- data_ori[seq(2, nrow(data_ori), 2), ]

rep(x, times = 1, length.out = NA, each = 1),生成重复序列。

rep(0, 3)
#> [1] 0 0 0
rep(c(1, 2, 3), 3)
#> [1] 1 2 3 1 2 3 1 2 3
rep(c(1, 2, 3), 3, length.out = 10)
#>  [1] 1 2 3 1 2 3 1 2 3 1
rep(c(1, 2, 3), 3, length.out = 30, each = 3)
#>  [1] 1 1 1 2 2 2 3 3 3 1 1 1 2 2 2 3 3 3 1 1 1 2 2 2 3 3 3 1
#> [29] 1 1

rep()可以巧妙地和subsetting的操作相结合,来实现快速复制矩阵。例如以一个 \(2\times2\) 的矩阵为最小 element,复制出一个 \(2 \times 2\) 的大矩阵:

m1 <- matrix(1:4, 2, 2)
m1[rep(1:nrow(m1), 2), rep(1:ncol(m1), 2)]
#>      [,1] [,2] [,3] [,4]
#> [1,]    1    3    1    3
#> [2,]    2    4    2    4
#> [3,]    1    3    1    3
#> [4,]    2    4    2    4

来源:R中是否有复制平铺矩阵的函数

10.4.4 Random sampling

sample(x, size, replace = FALSE, prob = NULL),从x中随机取出size个元素。x可以是一个 vector 或 integer scalar,当x是 integer scalar 时,等价于1:xsize是 integer。可选 argument:

  1. replace = TRUE表示有放回抽样;
  2. prob是一个向量,每一个元素是x中对应元素被抽中的概率。
sample(5, 1)  # 等价于 sample(5, 1, prob = rep(1/5, 5))
#> [1] 3
sample(5, 5)
#> [1] 1 3 5 2 4
sample(5, 5, replace = TRUE)
#> [1] 5 4 5 5 1
sample(6, 6, replace = TRUE, prob = c(1/6, 1/6, 1/6, 1/6, 1/3, 1/3))
#> [1] 3 4 6 3 6 6

随机抽样的一个典型的应用场景是自助法(Bootstrap),从样本中随机取出多批指定大小的数据,当作是平行样本。以英雄联盟数据集为例:

library(openxlsx)
data_ori <- read.xlsx("F:/Nutstore backup/R/codes/RBA/data/Arena of Valor_midterm dataset.xlsx")
data_sample <- data_ori[sample(nrow(data_ori), 30), ]

10.4.5 Concatenate strings

paste(..., sep = " ", collapse = NULL),将object按照指定方式拼接成字符串。...是一个或多个待拼接的object。可选argument如下:

  1. sep = " "是拼接时用来分隔各项的字符串,默认值是一个英文空格;
  2. collapse = NULL 表示拼接好的各项最后合并成一个字符串,各项间用collapse的值来分隔,默认值是NULL,即不合并成一个字符串。
paste(1:12)  # 等价于 as.character(1:12)
#>  [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10" "11"
#> [12] "12"
paste(1:12, "month")
#>  [1] "1 month"  "2 month"  "3 month"  "4 month"  "5 month" 
#>  [6] "6 month"  "7 month"  "8 month"  "9 month"  "10 month"
#> [11] "11 month" "12 month"
paste(1:12, c("st", "nd", "rd", rep("th", 9)), "month")
#>  [1] "1 st month"  "2 nd month"  "3 rd month"  "4 th month" 
#>  [5] "5 th month"  "6 th month"  "7 th month"  "8 th month" 
#>  [9] "9 th month"  "10 th month" "11 th month" "12 th month"
paste(1:12, c("st", "nd", "rd", rep("th", 9)), "month", sep = "")
#>  [1] "1stmonth"  "2ndmonth"  "3rdmonth"  "4thmonth" 
#>  [5] "5thmonth"  "6thmonth"  "7thmonth"  "8thmonth" 
#>  [9] "9thmonth"  "10thmonth" "11thmonth" "12thmonth"
paste(1:12, c("st", "nd", "rd", rep("th", 9)), "month", sep = "", collapse = ",")
#> [1] "1stmonth,2ndmonth,3rdmonth,4thmonth,5thmonth,6thmonth,7thmonth,8thmonth,9thmonth,10thmonth,11thmonth,12thmonth"

paste()可用于自动生成符合要求的文件名:

num_subsets <- 10
filenames <- paste(1:num_subsets, 
                    ".txt",
                    sep = "")
filenames
#>  [1] "1.txt"  "2.txt"  "3.txt"  "4.txt"  "5.txt"  "6.txt" 
#>  [7] "7.txt"  "8.txt"  "9.txt"  "10.txt"
write.table(data_subset1, filenames[1])
write.table(data_subset2, filenames[2])

只要是需要按照一定的规律生成字符串,就要想到paste()

10.4.7 Head and tail

head(x, n = 6L)tail(x, n = 6L),在Console输出x的前 6 或后 6 个元素(xvector)/行(xmatrixdata.frame)。可选argument

  1. n表示输出的个/行数,默认为 6。
m1 <- matrix(1:100, 10, 10)
head(m1)
#>      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#> [1,]    1   11   21   31   41   51   61   71   81    91
#> [2,]    2   12   22   32   42   52   62   72   82    92
#> [3,]    3   13   23   33   43   53   63   73   83    93
#> [4,]    4   14   24   34   44   54   64   74   84    94
#> [5,]    5   15   25   35   45   55   65   75   85    95
#> [6,]    6   16   26   36   46   56   66   76   86    96
tail(m1)
#>       [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
#>  [5,]    5   15   25   35   45   55   65   75   85    95
#>  [6,]    6   16   26   36   46   56   66   76   86    96
#>  [7,]    7   17   27   37   47   57   67   77   87    97
#>  [8,]    8   18   28   38   48   58   68   78   88    98
#>  [9,]    9   19   29   39   49   59   69   79   89    99
#> [10,]   10   20   30   40   50   60   70   80   90   100

10.4.8 Continuous to discrete

cut(x, breaks)

  • x: a numeric vector which is to be converted to a factor by cutting.
  • breaks: either a numeric vector of two or more unique cut points or a single number (greater than or equal to 2) giving the number of intervals into which x is to be cut.
cut(1:10, breaks = c(0, 3, 6, 10))
#>  [1] (0,3]  (0,3]  (0,3]  (3,6]  (3,6]  (3,6]  (6,10] (6,10]
#>  [9] (6,10] (6,10]
#> Levels: (0,3] (3,6] (6,10]
# Simulate the demographic data reported in 
#  http://journal.psych.ac.cn/xlxb/article/2021/0439-755X/0439-755X-53-11-1215.shtml

Income <- c(sample(11999, 122), 
            sample(12000:35999, 332),
            sample(36000:100000, 219))
Income <- c(Income, NA, NA)
is_lost <- rep(1, length(Income))
is_lost[c(sample(122, 78), 
          sample(123:454, 200), 
          sample(456:673, 140))] <- 0
is_lost[c(length(Income) - 1, length(Income))] <- NA
data_xb <- data.frame(Income, is_lost)
head(data_xb)
#>   Income is_lost
#> 1  10033       1
#> 2   4546       0
#> 3   2579       0
#> 4   9784       0
#> 5   7528       0
#> 6   7513       0
data_xb$Income <- cut(data_xb$Income, c(0, 11999, 35999, 100000), 
                      labels = c("¥0-11,999", "¥12,000-35,999", 
                                 "¥36,000及以上"))
data_xb$is_lost <- factor(data_xb$is_lost, levels = c(1, 0), labels = c("保留样本", "流失样本"))
as.matrix(table(data_xb))
#>                  is_lost
#> Income            保留样本 流失样本
#>   ¥0-11,999            44       78
#>   ¥12,000-35,999      132      200
#>   ¥36,000及以上        79      140

10.4.9 Built-in constants

R 中内置有如下常量:

pi
#> [1] 3.141593
LETTERS
#>  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N"
#> [15] "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"
letters
#>  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n"
#> [15] "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
month.abb
#>  [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep"
#> [10] "Oct" "Nov" "Dec"
month.name
#>  [1] "January"   "February"  "March"     "April"    
#>  [5] "May"       "June"      "July"      "August"   
#>  [9] "September" "October"   "November"  "December"

10.5 Precedence of operators (optional)

目前学过的 operators 可以大致归为以下几类:

包括 如何查看帮助
subsetting (取子集) $ @ [[]] [] ?`$`$可替换为任意一个subsetting operator)或 ?Extract
Colon (分号) : ?`:`?Colon
Arithmetic (算术) +, -, *, /, ^, %%, %/%, %*% ?`+`+可替换为任意一个 Arithmetic operator) 或?Arithmetic?matmult
Relational (关系) >, <, <=, >=, ==, != ?`>`>可替换为任意一个 Relation operator)或 ?Comparison
Logical (逻辑) !, &, &&, |, || ?`!`!可替换为任意一个 Logical operator)或 ?Logic
Assignment (分配) <- ?`<-`?assignOps

注意:` ` 为反单引号,当某个 name 本身是非法字符(如已经定义的 operator)或者违背 name 命名规则时,就需要加反单引号来标识,否则会被当作是语句直接执行。

以上各 operator 在同一个语句中执行时是有优先顺序(precedence)的,就好比是加减乘除运算有优先顺序一样,同一个式子中先算乘除后算加减。 R 中各 operator 的优先顺序如下:

如果没有注意优先顺序,容易出现代码的执行结果和预期不一致的情况,例如:

a <- runif(10)
a
#  把最大值最小值所在位置找出来
position <- 1:length(a)[as.logical(a == max(a) + a == min(a))] 
position
#> Error: <text>:4:52: unexpected '=='
#> 3: #  把最大值最小值所在位置找出来
#> 4: position <- 1:length(a)[as.logical(a == max(a) + a ==
#>                                                       ^

如果需要保证低优先度的操作被完整执行,不受高优先度代码的影响,需要使用()把低优先度的操作包起来:

a <- runif(10)
a
#>  [1] 0.4486601 0.5677796 0.6830969 0.5054427 0.1323793
#>  [6] 0.1392210 0.1092770 0.4867837 0.0597558 0.8562954
#  把最大值最小值所在位置找出来
position <- (1:length(a))[as.logical((a == max(a)) + (a == min(a)))]
position
#> [1]  9 10

更多有关 operator 优先顺序的内容请使用?Syntax查看。

如果在实际编程过程中,如果不能准确记住各 operator 之间的优先顺序也不要紧。可以在不确定的时候,将不确定的代码单独拿出来执行一下,确保和自己预期的结果一致,如果发现不一致,就说明存在低优先度的操作但没有用()的情况,然后再去查看问题到底出在哪一个操作。

10.6 Recap

常用操作 operators 或 functions
基本数学运算 operator+ - * / ^ %% %/% %*%
极值:max() min()
求和:sum() rowSums() colSums()
均值:mean() rowMeans() colMeans()
求积:prod()
取整:round() ceiling() floor() trunc()
自然指数和对数:exp() log()
开根号:sqrt()
三角函数:sin() cos() tan()
绝对值:abs()
符号:sign()
转置:t()
关系和逻辑 关系operator> < >= <= == !=
逻辑operator& && | || !
定位、匹配和排序 定位:which()
匹配:%in%
排序:sort() order()
其他 合并:c() cbind() rbind()
个数:length() nrow()NROW() ncol()NCOL() nchar()
生成序列:: seq() rep()
随机抽样:sample()
拼接字符:paste()
输出:print() cat()
“展露头脚”:head() tail()
内置常量:pi letters LETTERS month.abb month.name
连续变离散: cut()
  1. 大多数 operators 和 functions 支持 recycling rule,(详见@ref(byrow-recycling);
  2. round()的规则是 4 舍 6 入,逢 5 成双;
  3. &|)和&&||)的区别是前者匹配所有位置上的元素对,后者只匹配第一个位置;
  4. Relational operator 和 logical operator 常搭配在一起,用于按照指定条件 subsetting;
  5. cbind()rbind()的默认输出结果是 matrix,只有拼接的 object 中有 data.frame 时,输出结果才是 data.frame;
  6. 常用:seq()rep()sample()产生位置索引,实现快速抽取和复制数据的目的;
  7. 通过 Source 执行活动脚本的全部代码时,要输出内容至 Console 需使用print()cat()
  8. operators 间在执行上有优先顺序,同时使用多种 operators 时要注意检查结果是否符合预期;
  9. 使用()包裹住低优先度的代码可以保证这部分代码被完整执行。