image.png

取子集操作符

最常见的[,还有另外两个取子集操作符: [[和$。 除了只能返回单个值以外, [[与[是类似的,它还可以用于取出列表的一部分。 当通过字符进行取子集操作时, $是[[一种有用的简化写法。对列表进行操作时,需要[[。 这是因为当[应用于列表时,总是返回列表:它从来不会返回列表包含的内容。 为了获得列表的内容,需要使用[[

向量

r中的索引从1开始,而不是0

原子向量

原子向量索引支持 [ 和[[, 共有6种索引方式

  • 正整数索引

    1. a <- c(2,4,6,8)
    2. > a[1]
    3. [1] 2
    4. > a[c(1,4)]
    5. [1] 2 8
    6. > a[c(1:4)]
    7. [1] 2 4 6 8
  • 负整数索引:取删除指定位置元素后的其他元素

    1. a <- c(2,4,6,8)
    2. > a[-1]
    3. [1] 4 6 8
    4. > a[c(-1, -2)]
    5. [1] 6 8
    6. > a[c(-1:-4)]
    7. numeric(0)
    8. > a[c(-1:-2)]
    9. [1] 6 8
  • 逻辑向量索引

    1. a <- c(2,4,6,8)
    2. a[c(T,T,T,F)]
    3. [1] 2 4 6
  • 空值与0: 前者返回本身,后者返回一个空原子向量

    1. a <- c(2,4,6,8)
    2. > a[]
    3. [1] 2 4 6 8
    4. > a[0]
    5. numeric(0)
  • 字符向量,可以使用[[ 索引

    1. a <- c(2,4,6,8)
    2. names(a) <- c("a", "b", "c", "d")
    3. > a["a"]
    4. a
    5. 2
    6. > a[c("a", "b")]
    7. a b
    8. 2 4
    9. > a[["a"]]
    10. [1] 2

    列表

    索引的方式与原子向量一致,但是支持$操作符号,其中,使用[将总是返回一个列表;使用[[和$,则取出列表的一部分。

    矩阵与数组

    你可以通过三种方式对更高维的结构进行取子集操作:

  1. 使用多个向量
  2. 使用单个向量
  3. 使用矩阵

对矩阵(2 维)和数组(大于 2 维)进行取子集操作的最常见的方式,是对一维取子集操作的简单推广:你对每一个维度都提供一个一维索引,并以逗号分隔。 使用空白(blank)的方式来取子集时代表取出所有的行或者列

  1. a <- matrix(1:9, nrow = 3)
  2. > a[1,]
  3. [1] 1 4 7
  4. > a[1:2,]
  5. [,1] [,2] [,3]
  6. [1,] 1 4 7
  7. [2,] 2 5 8
  8. > a[-1:-2,]
  9. [1] 3 6 9
  10. > a[,1:2]
  11. [,1] [,2]
  12. [1,] 1 4
  13. [2,] 2 5
  14. [3,] 3 6
  15. > a[c(1,3),c(1,3)]
  16. [,1] [,2]
  17. [1,] 1 7
  18. [2,] 3 9

将矩阵命名后,同样支持字符索引

  1. colnames(a) <- c("a","b", "c")
  2. > a[,c("a", "c")]
  3. a c
  4. [1,] 1 7
  5. [2,] 2 8
  6. [3,] 3 9

数据框

数据框同时支持[, [[, $索引方式, 支持整数,bool索引

  1. df <- data.frame(x = 1:3, y = 3:1, z = letters[1:3])
  2. > df$x
  3. [1] 1 2 3
  4. > df["x"]
  5. x
  6. 1 1
  7. 2 2
  8. 3 3
  9. > df[["x"]]
  10. [1] 1 2 3
  11. > df[,df$x == 2 ]
  12. [1] 3 2 1
  13. > df[1, ]
  14. x y z
  15. 1 1 3 a

指如果对矩阵取子集得到的结果是一维的,那么会默认会转化为向量,使用 drop = FALSE 参数可以避免这一点。

  1. > df[,"x", drop = T]
  2. [1] 1 2 3
  3. > df[,"x", drop = F]
  4. x
  5. 1 1
  6. 2 2
  7. 3 3

S3对象

S3 对象是由原子向量、数组和列表组成的,所以你可以使用上面描述的技术对 S3对象进行取子集操作。 你可以通过 str()函数获得的它们的结构信息。

S4对象

对 S4 对象来说,有另外两种取子集操作符: @(相当于$)和 slot()(相当于[[)。 @比$更加严格,如果槽(slot)不存在,那么它会返回错误。

简化与保持

简化(simplifying)和保持(preserving) ,即取子集操作之后是否把结果转化为更简单的数据类型,比如取出数据框的一列,如果选择简化,则返回的是向量,如果选择保持,则返回的仍然是数据框, 在对矩阵和数据框进行取子集操作时忽略了 drop = FALSE,是编程中最常见的错误来源之一。 总之,保持(preserving)是对所有数据类型都是相同的:你得到的输出类型与输入类型是相同的。 简化(simplifying)是数据类型随着不同行为略有变化

image.png

  1. 原子向量: 移除名字
  2. 列表: 返回列表内的对象,而不是包含单个元素的列表。
  3. 因子: 丢弃所有没有用到的水平。
  4. 矩阵和数组: 如果任一维度的长度为 1,则丢弃那个维度
  5. 数据框: 如果输出是单列的,那么将用向量替代数据框返回

    $

    $是一种简化的操作符, x$y 等价于 x[[“y”, exact = FALSE]] ,试图把它与存有列名的变量联合使用是不可取的
    1. val <- "cyl"
    2. > mtcars$val
    3. NULL
    $可以部分匹配列名,如匹配mtcars数据框的am列
    1. > mtcars$a
    2. [1] 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1
    3. > mtcars$am
    4. [1] 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1 1 1 1 1 1 1

    应用

    手动匹配与合并

    手动实现left_join部分功能,
  • grades:成绩表
  • info: 不同成绩对应评分
  • df:每个成绩对应的评分表 ```r grades <- c(100, 102, 102, 100, 101) info <- data.frame( grade = 100:102, desc = c(“Excellent”, “Good”, “Poor”), fail = c(F, F, T) ) info

id <- match(grades, info$grade) df <- info[id,] rownames(df) <- c(1:nrow(df)) df

—输出 ———————————————————————————————————

grade desc fail 1 100 Excellent FALSE 2 102 Poor TRUE 3 102 Poor TRUE 4 100 Excellent FALSE 5 101 Good FALSE

  1. <a name="o1bya"></a>
  2. ### 随机取样
  3. 随机抽取行或列
  4. ```r
  5. df <- data.frame(x = rep(1:3, each = 2), y = 6:1, z = letters[1:6])
  6. df[sample(nrow(df),3),]
  7. # 有放回
  8. df[sample(nrow(df),3, rep = T),]

排序

order函数,order输出一个向量,默认返回输入向量各个元素从小到大排列的index值, decreasing = TRUE 把排序方式从升序变成降序。 默认情况下,缺失值都将排在向量的末尾;但是,你可以设置 na.last = NA 来删除缺失值,或者设置 na.last = FALSE 把缺失值排在向量的开头。

  1. x <- c("b", "c", "a")
  2. order(x)
  3. > [1] 3 1 2
  4. x[order(x)]
  5. > [1] "a" "b" "c"

展开聚合的数据

展开聚合的数据(Expanding aggregated counts):有时你得到了一个数据框, 相同的行已经合并到了一起,一个用来计数的列也已经添加进去了。 rep()函数联合整数取子集操作,使得展开这种数据变得容易,它通过重复行的索引来进行

  1. > df <- data.frame(x = c(2, 4, 1), y = c(9, 11, 6), n = c(3, 5, 1))
  2. # n为计数列
  3. > df
  4. x y n
  5. 1 2 9 3
  6. 2 4 11 5
  7. 3 1 6 1
  8. df2 <- df[rep(c(1:nrow(df)),df$n),]
  9. rownames(df2) <- c(1:nrow(df2))
  10. df2[,-ncol(df2)]
  11. x y
  12. 1 2 9
  13. 2 2 9
  14. 3 2 9
  15. 4 4 11
  16. 5 4 11
  17. 6 4 11
  18. 7 4 11
  19. 8 4 11
  20. 9 1 6

删除列

  1. df$col <- NULL
  2. df[,"col"] <- NULL
  3. df[["col"]] <- NULL