高级R编程-第3章:子集选取(上) R 有一套强大而又快速的子集选取运算符但又不容易学习上手本章内容涵盖3 个子集选取运算符比如[、[[、$6 种选取子集的方法不同对象原子向量、列表、因子、矩阵、数据框选取子集的方法差异赋值与子集选取结合实现修改对象子集3.1 数据类型3.1.1 原子向量[]运算符中正整数向量返回指定位置从左往右的元素# 创建向量并取第3个和第1个元素 x - c(5.1, 3.2, 4.3, 1.4, 2.5) x[c(3,1)][1] 4.3 5.1# order返回升序排列后的位置排列向量 # 比如排序后第1个数值是1.4在原序列中是第4位 # 第2个数值是2.5, 在原序列中是第5位 # 也即order返回经排序后元素在原向量中的索引位置 order(x)[1] 4 5 2 3 1# order(x)元素在原索引中的位置按排序后的顺序依次排列 # x[]排序后的元素值 x[order(x)][1] 1.4 2.5 3.2 4.3 5.1# 重复索引会重复取子集 x[c(2,2,2)][1] 3.2 3.2 3.2# 小数索引会被截断为整数索引 x[c(1.9, 2.1)][1] 5.1 3.2负整数指排除该位置上的元素# 排除第3个和第1个元素 x[-c(3, 1)][1] 3.2 1.4 2.5# 不能同时使用正数和负数 try(x[c(-3, 1)])Error in x[c(-3, 1)] : only 0’s may be mixed with negative subscripts逻辑向量只选取 TRUE 位置上的元素这是常用的选取方法# 逻辑向量选取子集 x[c(T,F,T,F,T)][1] 5.1 4.3 2.5# x3会生成向量TRUE TRUE TRUE FALSE FALSE # 结果就是取第1、2、3个元素 x[x3][1] 5.1 3.2 4.3如果逻辑向量比母集短则逻辑向量会被循环使用直到长度与母集相同这是一项设计特性但有时也会造成困惑# 逻辑向量被循环为T F F T(从头再来) F(长度结束) x[c(T,F,F)][1] 5.1 1.4对比下面两种缺失值索引返回结果差异# 返回5个NA x[NA][1] NA NA NA NA NANA 索引是逻辑值逻辑值包括 TRUE/FALSE/NA子集选取遇到逻辑索引时若索引长度不够会将索引自动循环至与向量长度相同故该例子等同于x[c(NA,NA,NA,NA,NA)]返回 5 个结果# 只返回一个NA x[NA_integer_][1] NA该例子中的 Na_integer_是数值型子集选取采用的是数字索引规则代表的是筛选出第 NA_integer_个位置的值该位置不存在故返回一个 NA索引长度是 1 个返回结果也是 1 个索引出现缺失值 NA子集相同位置也会产生缺失值# 索引中的NA子集对应位置也会是NA x[c(T,F,F,NA,T)][1] 5.1 NA 2.5空索引返回原始向量这对矩阵、数据框、数组很有用# 空索引返回原始向量 x[][1] 5.1 3.2 4.3 1.4 2.5索引 0, 返回长度为 0 的同类型向量有时在测试时用得着# 索引为0 x[0]numeric(0)元素名字作为索引# 创建带名称的元素 (y - setNames(x, letters[1:5]))a b c d e5.1 3.2 4.3 1.4 2.5# 用名字元素取子集名字必须完全匹配不能部分匹配 y[c(a,a,d)]a a d5.1 5.1 1.43.1.2 列表列表用[]选取子集的方式与原子向量相同但列表总是返回列表类型的子集# 用[]对列表取子集总是返回一个列表 z - list(a1:2, bletters[1:3], clist(hello)) z[1]$a[1] 1 2若需剥离外层的列表只返回里面的元素内容更为常见的需求可使用[[]]或$# 使用[[]]对列表取子集 z[[1]][1] 1 2# 也可用元素名称取子集 z$b[1] “a” “b” “c”3.1.3 矩阵和数组有三种方法可从高维数据结构中选取子集默认情况下[]会将结果简化到尽量低的维度常见场景后文会介绍如何避免这种情况第一种多组向量筛选行和列# 先创建一个矩阵 myMatrix - matrix(1:9, nrow3) colnames(myMatrix) - c(A,B,C) myMatrixA B C[1,] 1 4 7[2,] 2 5 8[3,] 3 6 9# 逗号“,”左边代表行右边代表列选取逻辑是笛卡尔积 # 下面是指取第1、第2行与第2、第3列相交叉的元素 # 也即第1行第2列、第1行第3列、第2行第2列、第2行第3列 myMatrix[c(1,2), c(2,3)]B C[1,] 4 7[2,] 5 8同样可以使用逻辑值和列名选取子集# 选取第1、第2行不要第3行与B列、C列相交叉的元素 myMatrix[c(T,T,F), c(B,C)]B C[1,] 4 7[2,] 5 8空代表选取全部# 选取第3行所有列 myMatrix[3,]A B C3 6 9# 选取第3列所有行 myMatrix[,3][1] 7 8 9# 选取全部行、全部列 myMatrix[,]A B C[1,] 1 4 7[2,] 2 5 8[3,] 3 6 9同样可以选取 0 行或 0 列# 选取0行空行并排除第2列B列 myMatrix[0, -2]A C第二种单个向量筛选列这种情况下子集像向量# 选取第3行、第1列 myMatrix[c(3,1)][1] 3 1第三种整数矩阵或字符矩阵若元素已命名筛选元素# outer将前两个向量的所有组合迪卡尔积效果类似于坐标对应用于FUN函数 (myMatrix2 - outer(1:5, 1:5, FUNpaste, sep,))[,1] [,2] [,3] [,4] [,5][1,] “1,1” “1,2” “1,3” “1,4” “1,5”[2,] “2,1” “2,2” “2,3” “2,4” “2,5”[3,] “3,1” “3,2” “3,3” “3,4” “3,5”[4,] “4,1” “4,2” “4,3” “4,4” “4,5”[5,] “5,1” “5,2” “5,3” “5,4” “5,5”进行矩阵选取矩阵的列数不同选取的方式也不同注意n 维数组的索引矩阵要么是 n 列要么是 1 列不可以是其它列数数组类型索引矩阵列数含义矩阵二维数组1 列将矩阵按列拉直成向量索引后取第几个元素矩阵二维数组2 列索引矩阵每一行代表着行列索引更高维数组n 维1 列将矩阵按列拉直成向量索引后取第几个元素更高维数组n 维n 列索引矩阵每一行代表着1 维2 维…n 维索引数组中较常用的是矩阵二维故索引矩阵是 2 列的情况较为常见返回的结果是向量# 索引矩阵是2列代表着取第1行第1列、第3行第5列、第2行第4列的元素 (index - matrix(c(1,1, 3,5, 2,4), ncol2, byrowT))[,1] [,2][1,] 1 1[2,] 3 5[3,] 2 4# 矩阵筛选用的是2列的索引矩阵 myMatrix2[index][1] “1,1” “3,5” “2,4”索引矩阵是 1 列每行代表着元素位置返回的结果还是向量# 索引矩阵是1列代表着按列优先顺序选取第1、3、5、7个元素 (index2 - matrix(c(1,3,5,7), ncol1))[,1][1,] 1[2,] 3[3,] 5[4,] 7# 矩阵筛选索引是1列的矩阵 myMatrix2[index2][1] “1,1” “3,1” “5,1” “2,2”取矩阵的上三角/下三角上/下三角矩阵在运算中较为常见# 返回上三角矩阵的逻辑矩阵 (index.upper - upper.tri(myMatrix2))[,1] [,2] [,3] [,4] [,5][1,] FALSE TRUE TRUE TRUE TRUE[2,] FALSE FALSE TRUE TRUE TRUE[3,] FALSE FALSE FALSE TRUE TRUE[4,] FALSE FALSE FALSE FALSE TRUE[5,] FALSE FALSE FALSE FALSE FALSE# 筛选出上三角元素会按列优先被简化为向量 myMatrix2[index.upper][1] “1,2” “1,3” “2,3” “1,4” “2,4” “3,4” “1,5” “2,5” “3,5” “4,5”# 下三角矩阵同理 (index.lower - lower.tri(myMatrix2))[,1] [,2] [,3] [,4] [,5][1,] FALSE FALSE FALSE FALSE FALSE[2,] TRUE FALSE FALSE FALSE FALSE[3,] TRUE TRUE FALSE FALSE FALSE[4,] TRUE TRUE TRUE FALSE FALSE[5,] TRUE TRUE TRUE TRUE FALSE# 索引矩阵进行筛选 myMatrix2[index.lower][1] “2,1” “3,1” “4,1” “5,1” “3,2” “4,2” “5,2” “4,3” “5,3” “5,4”当然也可以用 2 列的索引矩阵来筛选上/下三角矩阵元素# 上三角矩阵为例按列优先的次序构建索引矩阵 # 行数和列数相同都是5 n - 5 # 列索引结果是2 3 3 4 4 4 5 5 5 5 # 比如2第2列有1行、3 3第3列有2行、4 4 4第4列有3行 j - rep(2:n, times1:(n-1)) # 行索引结果是1 1 2 1 2 3 1 2 3 4 # 比如1第2列只有第1行、1 2第3列有第1和2行、1 2 3第4列有第1、2和3行 i - sequence(1:(n-1)) # 组合成索引矩阵 index2.up - cbind(i,j) # 再筛选子集可以看出结果与使用upper.tri()是一样的 myMatrix2[index2.up][1] “1,2” “1,3” “2,3” “1,4” “2,4” “3,4” “1,5” “2,5” “3,5” “4,5”矩阵对角元素常用函数是 diag()# 主对角线上的元素 diag(myMatrix2)[1] “1,1” “2,2” “3,3” “4,4” “5,5”也可以用一列的索引矩阵来提取对角元素# 矩阵的行与列数量都是5 n - 5 # 构建只有1列的索引矩阵实质只使用了单个向量 # d的结果是1 7 13 19 25恰好是对角线元素的位置 d - seq(from1, ton*n, byn) d - d 0:(n-1) # 筛选子集结果与使用diag()是一致的 myMatrix2[d][1] “1,1” “2,2” “3,3” “4,4” “5,5”3.1.4 数据框兼具列表和矩阵的特点参数个数说明单一向量类似列表两个向量类似矩阵# 先创建一个数据框 (myFrame - data.frame(x1:3, y10:8, zletters[1:3]))x y z1 1 10 a2 2 9 b3 3 8 c两个向量进行选取行为模式类似于矩阵筛选出某个元素# 第1个向量代表行第2个向量代表列, 结果会尽量简化 # 选取第1行、第3行分别与第2列交叉的元素 myFrame[c(1,3), 2][1] 10 8# 选取x等于2的全部行与所有列交叉的元素 # 结果无法进一步简化还是返回数据框 # 因为各列的数据类型可能不同 myFrame[myFrame$x2, ]x y z2 2 9 b# 筛选出所有行的x和z列 myFrame[ ,c(x,z)]x z1 1 a2 2 b3 3 c如果只筛选出一列返回结果会尽量简化为一个向量# 结果被简化成一个向量 # 同一列的数据类型肯定相同 str(myFrame[ , y])int [1:3] 10 9 8一个向量进行选取行为模式类似于列表筛选出某一列# 单个向量代表列 myFrame[x]x1 12 23 3返回结果总是数据框不会简化# 返回结果不会简化 str(myFrame[1])‘data.frame’: 3 obs. of 1 variable:$ x: int 1 2 3子集筛选叠加赋值可实现对部分元素的更新# 构造包含NA值的数据框 (myFrame2 - data.frame(Ac(1,2,NA,4), Bc(甲,NA,丙,丁),Cc(A,B,NA,NA)))A B C1 1 甲 A2 2 B3 NA 丙4 4 丁 NA# 筛选出NA的元素 (index.na - is.na(myFrame2))A B C[1,] FALSE FALSE FALSE[2,] FALSE TRUE FALSE[3,] TRUE FALSE TRUE[4,] FALSE FALSE TRUE# NA替换为0 myFrame2[index.na] - 0 myFrame2A B C1 1 甲 A2 2 0 B3 0 丙 04 4 丁 03.1.5 S3 和 S4 对象类别对象说明S3 对象原子向量、列表、数组含矩阵可通过上述方法选取子集S4 对象将在 7.3 节介绍还需要通过 等价于$和 slot()等价于[[]]选取子集3.2 子集选取运算符还有另外两个选取子集的运算符[[和$用于列表并返回一个值一个元素运算符 1运算符 2对比[[ ]][ ]应用于列表时* [ ]返回一个列表* [[ ]]返回列表里面的内容* 如果将列表 x 比喻成一列火车则 x[4]返回第 4 节车厢含车厢本身而 x[[4]]返回车厢里面的货物不含车厢[[ ]]$$ 可以理解为[[ ]]的缩写列表子集的选取# 构建列表 (myList - list(a1:3, bc(a,b), clist(d你好)))$a[1] 1 2 3$b[1] “a” “b”$c$c$d[1] “你好”# 通过元素索引选取子集比如选取第2个元素的内容 myList[[2]][1] “a” “b”# 作为对比[]仍返回一个列表 str(myList[2])List of 1$ b: chr [1:2] “a” “b”# $可视为[[]]的简写但需引用字符串名称 myList$b[1] “a” “b”对于层层嵌套的列表有简易方式选取子集# 构建嵌套列表 (myList2 - list(alist(blist(clist(d10)))))$a$a$b$a$b$c$a$b$c$d[1] 10# 选取最内层的内容 myList2[[c(a,b,c,d)]][1] 10# 等同于 myList2$a$b$c$d[1] 10# 也等同于原始表达方式 myList2[[a]][[b]][[c]][[d]][1] 10数据框本质是由各列组成的列表同样可以使用[[ ]]提取列# 提取数据框第2列内容 myFrame2[[2]][1] “甲” “0” “丙” “丁”注意S3 和 S4 对象可以重写[ ]和[[ ]]的行为不同对象在子集选取行为上略有差异主要区别体现在如何简化输出结果或默认行为上3.2.1 简化与保留选取子集时要特别关注返回的结果是否保持原来的数据结构还是被简化过了简化子集交互分析时很有用更人性化保留原有结构有利于编程不同数据类型在选取子集时简化或保留数据结构的方法有所不同如下所示数据类型简化例子保留例子向量* x[[1]]* [[ ]]只能选取单个元素若多个选取参数则会报错* [[ ]]的返回值不会保留任何属性包括 names* R 最小的数据结构是向量R 没有标量简化后返回的还是向量* x[1]* 返回的仍然是向量列表* x[[1]]* 返回元素内容* x[1]* 返回列表内含元素内容因子* x[1, dropT]* drop 参数用于删除维度但因子是一维结构无法降维故返回的仍然是列表但水平标签会被缩减* x[1]* 返回列表且水平标签维持原样* drop 参数默认为 F也即不降维数组* x[1, ] 或 x[ ,1]* 数组是二维以上的数据结构drop 可删除维度也即降维* 返回第 1 行或第 1 列* drop 参数默认为 T* x[1, , dropF] 或 x[ , 1, dropF]* dropF 代表不降维数据框* x[ , 1] 或 x[[1]]* 只有选择 1 列才会降维而选择 1 行是不会降维的* drop 参数默认为 T* x[ , 1, dropF] 或 x[1]* 不降维drop 是[ ]运算符的通用参数其取 TRUE 时当提取的结果只有一个维度则删除该维度也即降维对于一维向量原子向量、列表、因子drop 参数会被忽略以下是向量选取的例子# [[ ]]向量的简化例子返回的仍是向量但属性被删除 setNames(1:10, letters[1:10])[[1]][1] 1# [[ ]]用于剥离容器层级并取出里面的内容故只能选取单个元素否则会报错 # 唯一的例外是列表层层嵌套子元素时允许传入多个向量参数以选取内层子元素 try(c(1:10)[[1:2]])Error in c(1:10)[[1:2]] :attempt to select more than one element in vectorIndex# [ ]向量保留原始数据结构含属性且对长度无限制 setNames(1:10, letters[1:10])[1:2]a b1 2以下是列表选取的例子# 列表的简化选取剥离了外部容器且只能选出单个元素 str(myList[[1]])int [1:3] 1 2 3# 列表的保留选取维持原有数据结构 str(myList[1])List of 1$ a: int [1:3] 1 2 3以下是因子选取的例子# 因子的简化选取扔掉不使用的水平返回列表 str(factor(letters)[1:3, dropT])Factor w/ 3 levels “a”,”b”,”c”: 1 2 3# 因子的保留选取保留所有水平返回列表 str(factor(letters)[1:3])Factor w/ 26 levels “a”,”b”,”c”,”d”,..: 1 2 3以下是数组和矩阵选取的例子# 矩阵的简化例子只剩一行一个维度时删除该维度 str(matrix(1:12,nrow3)[1, ])int [1:4] 1 4 7 10# 只剩一列一个维度时删除该维度 str(matrix(1:12,nrow3)[ , 1])int [1:3] 1 2 3# 矩阵保留的例子维持原矩阵格式输出结果是3行1列 str(matrix(1:12,nrow3)[ , 1, dropF])int [1:3, 1] 1 2 3以下是数据框选取的例子# 数据框简化的例子当输出只有1列会简化成向量 # 注意若输出只有1行也不会简化的该行各元素类型可能不同无法简化 str(myFrame[[1]])int [1:3] 1 2 3# 当输出只有1列会简化成向量 str(myFrame[ ,1])int [1:3] 1 2 3# 数据框保留的例子 str(myFrame[1])‘data.frame’: 3 obs. of 1 variable:$ x: int 1 2 3# 明确保留数据框结构 str(myFrame[ , x, dropF])‘data.frame’: 3 obs. of 1 variable:$ x: int 1 2 33.2.2 运算符$“$”是简写运算符x$y 相当于 x[[‘y’, exactF]]其中 exactF 代表列名部分匹配 y而不是完全匹配假如列名存储在变量中则无法使用”$“引用该变量如下例子# $无法引用变量中的内容 yName - y myFrame$yNameNULL# 需要使用[[]] myFrame[[yName]][1] 10 9 8“$”与[[ ]]的重要区别是“$”部分匹配列名而[[ ]]需完全匹配列名# 完整的列名是cyl$能部分匹配列名只要该部分无重叠列名 mtcars$cy[1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4# 而[[ ]]必须匹配完整列名否则会返回空 mtcars[[cy]]NULL3.2.3 缺失及越界引用原子向量或列表的子集选取若是越界引用比如向量长度 4但却引用第 5 个元素或者用 NA 或 NULL 为索引进行子集选取时[和[[的行为有所不同需注意的是NA 与 NULL 内涵不同NA这里有一个值类型已知只是不知道这个值是什么。其长度是 1NULL这里完全是空的什么也没有自然也不存在什么数据类型。其长度是 0另外还要注意[和[[内涵也是有区别的[子集构建和选取会创建一个新的容器新向量/新列表把返回值填入该容器中。当索引无效时它可以在新容器里塞入一个占位符NA 或 NULL。其会保持容器原状[[其语义是“提取”而非“构建”。它要求直接取出内存中已存在的那个对象不会创建任何新容器。因此它无法凭空“制造”一个 NA 或 NULL 来充当返回值。其会剥离容器只返回元素的内容另一方面原子向量与列表在内存中存储的方式是不同的原子向量在内存中是连续的同质数据块访问必须依赖确切的整数偏移量比如第 3 个位置列表在内存中是指向元素对象的数组指针。初始化指向元素的指针时会先初始化为空指针NULL。若元素存在再将指针指向元素若元素不存在则维持空指针R 取子集的过程有两步检查判断先检查索引类型是否合法索引必须为整数、字符串或逻辑值。若无法通过检测则直接报错再判断取值逻辑是否正确基于上述差异向量与列表面对异常索引的行为存在差异具体如下运算符索引原子向量列表[越界引用NAlist(NULL)[NA_integer_NAlist(NULL)[NULLtype(0)list()[[越界引用报错报错[[NA_integer_报错NULL[[NULL报错报错补充若存在元素名字则越界、NA 或 NULL 引用的元素名称为[ ]的越界引用示例# 构建只有3个元素的向量 (myVector - setNames(11:13, c(a,b,c)))a b c11 12 13# 引用第4个不存在的元素返回NA # 元素名称为NA代表这里有一个名称但我们不知道它是什么 myVector[4]NANA上例解释向量要求每个元素的类型相同 而 NA 本质上是一个有类型默认是逻辑类型但也可以是整型/浮点/字符的占位符 用在向量返回值中是恰好合适的既与其它元素保持类型一致向量的要求 又能占用一个元素位置选取了一个元素的子集如果返回 NULL 反而不合适NULL 代表着什么都没有既无法与其它元素保持类型一致又无法表示选取了一个子元素# 列表只有3个元素但却引用第4个返回list(NULL) myList[4]$NANULL上例解释列表的元素类型可以各不相同若是返回 NA 则代表有确定的类型默认是逻辑值但这并不符合事实也容易让人做出错误判断。返回 NULL 则是合适的代表着元素内容和类型都不存在而列表的返回元素外面包着容器 list足以代表着选取了一个子元素[ ]的 NA_integer_引用示例# 向量的索引取整型的NA myVector[NA_integer_]NANA# 列表的索引取整型的NA myList[NA_integer_]$NANULL上例解释NA_integer_是 NA 的整数形式代表着有一个索引但不知道具体值是多少由于位置不确定能选取的元素也就无法确定但由于存在一个索引子集肯定是一个元素但不知道值是多少而向量与列表分别返回 NA 与 NULL 的原因与上述越界索引相同[ ]的 NULL 引用示例# 向量的空索引 myVector[NULL]named integer(0)# 列表的空索引 myList[NULL]named list()上例解释NULL 代表什么都没有既然索引不存在那么子集也就完全是空的长度为 0向量由于必须维持元素类型相同故返回的子集的数据类型与母集相同此例都是整数但长度是 0列表由于子集不存在而返回结果外部会包裹一层 list 容器故返回结果是 list()长度为 0 的列表[[ ]]的越界选取示例# 向量的越界选取报错 try(myVector[[4]])Error in myVector[[4]] : subscript out of bounds# 列表的越界选取同样报错 try(myList[[4]])Error in myList[[4]] : subscript out of bounds为什么 myVector[4]返回 NA而 myVector[[4]]却报错了这是因为[是子集选取R 会构造一个新向量数据类型与原向量相同作为返回结果然后往新向量填充原向量第 4 个元素的值找不到则用 NA 填充[[是元素提取其语义是把原向量第 4 个元素原样已存在于内存中的值输出但由于位置 4 根本不存在R 不知道该去哪找这个内部值于是就报错了myList 同理[[ ]]的 NA_integer_引用示例# 向量的缺失值索引 try(myVector[[NA_integer_]])Error in myVector[[NA_integer_]] : subscript out of bounds# 列表的缺失值索引 myList[[NA_integer_]]NULL上例解释NA_integer_意味着不知道索引是多少自然也就不知道需返回的元素在哪里对于原子向量无法返回 NA[[只是提取已存在于内存中的元素而不会构建新的返回值没有内存空间填充 NA 值不合适返回 NULL向量要求所有元素也包含子集的元素类型相同而 NULL 不存在元素类型自然也就不相同只能报错报错是唯一的选择。而且向量是内存中的连续块索引错误会引发无法预知的后果就像 C 语言故报错是合适的行为对于列表本来应该报错但设计人员故意让其返回 NULL列表是指向元素对象的数组指针且指针在初始化时是空值 NULL若元素存在则再指向元素当索引无效时直接返回这个空指针NULL更为高效且语义明确代表着不存在子集。列表常用来做映射或字典查询返回 NULL 便于使用若报错则还需额外捕获较为麻烦[[ ]]的 NULL 引用示例# 向量的空值引用 try(myVector[[NULL]])Error in myVector[[NULL]] :attempt to select less than one element in get1index# 列表的空值引用 try(myList[[NULL]])Error in myList[[NULL]] :attempt to select less than one element in get1index上例解释NULL 代表什么都没有既不存在内容也无类型、无长度对于向量来说索引 NULL 不是整数、字符或逻辑值无法通过索引类型检查直接报错根本没机会进入第二步取值逻辑检查对于列表来说索引 NULL 无法通过索引类型检查直接报错根本没机会进入第二步取值逻辑检查而上面例子 myList[[NA_integer_]]中的 NA_integer_是整型是可以通过索引类型检查的故未报错出现异常的是在第二步取值逻辑检查查无此值故能返回 NULL3.3 子集选取与赋值所有子集选取预算符都可以与赋值结合使用实现对指定元素的更新# 直接修改第2、3个元素 myVector[2:3] - c(-12,-13) myVectora b c11 -12 -13# 修改除第1个元素外的其它元素 myVector[-1] - c(-120,-130) myVectora b c11 -120 -130# 甚至索引可以重复后值会覆盖前值 myVector[c(1,1)] - 1:2 myVectora b c2 -120 -130整数索引中夹带 NA 则不能赋值此时 NA 作为整数类型不知道赋值到哪个位置的元素只能报错# 整型索引中有NA try(myVector[c(1,NA)] - 1:2)Error in myVector[c(1, NA)] - 1:2 :NAs are not allowed in subscripted assignments逻辑索引中夹带 NA 却是可以赋值的此时 NA 作为逻辑类型视作 FALSE# NA作为逻辑值视同FALSE myVector[c(T,NA,F)] - 22 myVectora b c22 -120 -130这个特性使得比较更新时不会更新到 NA 值# 只更新第1个元素原数值5而不会更新到第3个元素NA myFrame3 - data.frame(zc(5,10,NA,20)) myFrame3$z[myFrame3$z10] - 0 myFrame3z1 02 103 NA4 20保留原有对象类型但调整每列数据类型如下是一个巧妙的例子# lapply迭代函数将mtcars每一列应用as.integer()函数并返回新列组成的列表 # mtcars[]核心在于[]意味着保留mtcars的所有结构数据框、行/列数、行名等 # 赋值时会把右侧产生的列表的每个元素按顺序填入左侧数据框的每一列 mtcars[] - lapply(mtcars, as.integer) head(mtcars)mpg cyl disp hp drat wt qsec vs am gear carbMazda RX4 21 6 160 110 3 2 16 0 1 4 4Mazda RX4 Wag 21 6 160 110 3 2 17 0 1 4 4Datsun 710 22 4 108 93 3 2 18 1 1 4 1Hornet 4 Drive 21 6 258 110 3 3 19 1 0 3 1Hornet Sportabout 18 8 360 175 3 3 17 0 0 3 2Valiant 18 6 225 105 2 3 20 1 0 3 1作为对比若不加[]则结果是一个列表# 左侧不加[]则将右边产生的列表直接赋值给变量mtcars结果是个列表 mtcars - lapply(mtcars, as.integer) str(mtcars)List of 11$ mpg : int [1:32] 21 21 22 21 18 18 14 24 22 19 …$ cyl : int [1:32] 6 6 4 6 8 6 8 4 4 6 …$ disp: int [1:32] 160 160 108 258 360 225 360 146 140 167 …$ hp : int [1:32] 110 110 93 110 175 105 245 62 95 123 …$ drat: int [1:32] 3 3 3 3 3 2 3 3 3 3 …$ wt : int [1:32] 2 2 2 3 3 3 3 3 3 3 …$ qsec: int [1:32] 16 17 18 19 17 20 15 20 22 18 …$ vs : int [1:32] 0 0 1 1 0 1 0 1 1 1 …$ am : int [1:32] 1 1 1 0 0 0 0 0 0 0 …$ gear: int [1:32] 4 4 4 3 3 3 3 4 4 4 …$ carb: int [1:32] 4 4 1 1 2 1 4 2 2 4 …对于列表可以利用[[ ]]元素选取 赋 NULL 值来删除元素如下# myList原有3个元素 myList$a[1] 1 2 3$b[1] “a” “b”$c$c$d[1] “你好”# 删除第3个元素 myList[[3]] - NULL myList$a[1] 1 2 3$b[1] “a” “b”另外可以利用[ ]子集选取 赋 NULL 值来添加空值子元素如下# 将NULL分别添加到元素c和第4个元素中 myList[c] - list(NULL) myList[4] - list(NULL) myList$a[1] 1 2 3$b[1] “a” “b”$cNULL[[4]]NULL本文是我阅读和学习《高级R语言编程指南》作者Hadley Wickham机械工业出版社出版后的读书笔记大部分内容与例子引用原书并加上自己的一部分理解与补充。推荐关注我的个人博客R数据分析不定期发布R语言经典书籍的读书笔记、数据分析案例欢迎交流~