-
Notifications
You must be signed in to change notification settings - Fork 218
/
baseR_subsetting.Rmd
335 lines (231 loc) · 6.67 KB
/
baseR_subsetting.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# 子集选取 {#baseR-subsetting}
子集选取单独作一章,说明它确实很重要。
<!-- 上一章讲对象、数据类型和数据结构等概念。为了方便理解,我这里打个比方, -->
<!-- **对象**就是我们在计算机里新建了存储空间,好比一个盒子, -->
<!-- 我们可以往盒子里面装东西,比如鞋子、袜子、糖果东西。**数据类型**就是指我们装的东西的类型,比如是吃的还是用的呢, -->
<!-- 只不过计算机用的是机器语言,称之为,数值型、字符串型、因子型等等。 -->
<!-- **数据结构**就是盒子里东西的摆放次序,是相同的(同质)放一起,还是不同的(异质)放一起, -->
<!-- 相同的放一起就是向量、矩阵;不同的放一起可能是列表和数据框。 -->
上一章讲对象、数据类型和数据结构等概念。为了方便理解,我这里打个比方,
**对象**就是我们在计算机里新建了存储空间,好比一个盒子,
我们可以往盒子里面装东西(**赋值**),可以查看里面的内容或者对里面的内容做计算(**函数**),也可以从盒子里取出**部分**东西(**子集选取**)。
**子集选取**,就是从盒子里取东西出来[^1]。
[^1]: 操控盒子里的东西,比如把糖果变大,这个过程叫函数.
## 向量
对于原子型向量,我们有至少四种选取子集的方法
```{r subsetting-1}
x <- c(1.1, 2.2, 3.3, 4.4, 5.5)
```
- 正整数: 指定向量元素中的位置
```{r subsetting-2}
x[1]
```
```{r subsetting-3}
x[c(1, 3)]
```
```{r subsetting-4}
x[c(3, 1)]
```
- 负整数:删除指定位置的元素
```{r subsetting-5}
x[-2]
```
```{r subsetting-6}
x[c(-3, -4)]
```
- 逻辑向量:将`TRUE`对应位置的元素提取出来
```{r, out.width = '80%', echo = FALSE}
knitr::include_graphics("images/vector-subset.png")
```
```{r subsetting-7}
x[c(TRUE, FALSE, TRUE, FALSE, TRUE)]
```
常用的一种情形;筛选出大于某个值的所有元素
```{r subsetting-8}
x > 3
```
```{r subsetting-9}
x[x > 3]
```
- 如果是命名向量
```{r subsetting-10}
y <- c("a" = 11, "b" = 12, "c" = 13, "d" = 14)
y
```
我们可以用命名向量,返回其对应位置的向量
```{r subsetting-11}
y[c("d", "c", "a")]
```
## 列表
对列表取子集,和向量的方法一样。向量的子集仍然是向量,使用`[`提取列表的子集,总是返回列表
```{r subsetting-12}
l <- list(
"one" = c("a", "b", "c"),
"two" = c(1:5),
"three" = c(TRUE, FALSE)
)
l
```
使用位置索引
```{r subsetting-13}
l[1]
```
也可以使用元素名
```{r}
l["one"]
```
如果想提取列表某个元素的值,需要使用 `[[`
```{r subsetting-14}
l[[1]]
```
也可以使用其中的元素名,比如`[["one"]]`,
```{r subsetting-15}
l[["one"]]
```
取出`one`位置上的元素,需要写`[["one"]]`,程序员觉得要写太多的字符了,太麻烦了,所以用`$`来简写
```{r subsetting-16}
l$one
```
所以请记住
- `[` 和`[[`的区别
- `x$y` 是 `x[["y"]]`的简写
## 矩阵
```{r subsetting-17}
a <- matrix(1:9, nrow = 3)
a
```
我们取第1行到第2行的2-3列,`[1:2, 2:3]`,中间以逗号分隔,于是得到一个新的矩阵
```{r subsetting-18}
a[1:2, 2:3]
```
默认情况下, `[` 会将获取的数据,以尽可能低的维度形式呈现。比如
```{r subsetting-19}
a[1, 1:2]
```
表示第1行的第1、2列,此时不是$1 \times 2$矩阵,而是包含了两个元素的向量。
**以尽可能低的维度形式呈现**,换句话说,这个`r a[1, 1:2]`长的像个矩阵,又有点像向量,向量的维度比矩阵低,那就是向量吧。
有些时候,我们想保留所有的行或者列,比如
- 行方向,只选取第 1 行到第 2 行
- 列方向,选取所有列
可以这样简写
```{r subsetting-20}
a[1:2, ]
```
对于下面这种情况,想想,会输出什么
```{r subsetting-21}
a[, ]
```
可以再简化点?
```{r subsetting-22}
a[]
```
是不是可以再简化点?
```{r subsetting-23}
a
```
## 数据框
数据框具有list和matrix的双重属性,因此
- 当选取数据框的某几列的时候,可以和list一样,指定元素位置索引,比如`df[1:2]`选取前两列
- 也可以像矩阵一样,按照行和列的标识选取,比如`df[1:3, ]`选取前三行的所有列
```{r subsetting-24}
df <- data.frame(
x = 1:4,
y = 4:1,
z = c("a", "b", "c", "d")
)
df
```
### Like a list
```{r}
df[1:2]
```
```{r subsetting-25}
df[c("x", "z")]
```
```{r}
df[["x"]]
```
```{r}
df$x
```
### Like a matrix
```{r subsetting-26}
df[, c("x", "z")]
```
也可以通过行和列的位置
```{r subsetting-28}
df[1:3, ]
```
当遇到单行或单列的时候,也和矩阵一样,数据会降维
```{r subsetting-29}
df[, "x"]
```
如果想避免降维,需要多写一句话
```{r subsetting-30}
df[, "x", drop = FALSE]
```
这样输出的还是矩阵形式,但程序员总是偷懒的,有时候我们也容易忘记写`drop = FALSE`,
所以我比较喜欢下面的`tibble`.
## 增强型数据框
tibble是增强型的data.frame,选取tibble的行或者列,即使遇到单行或者单列的时候,数据也不会降维,总是返回tibble,即仍然是数据框的形式。
```{r subsetting-31}
tb <- tibble::tibble(
x = 1:4,
y = 4:1,
z = c("a", "b", "c", "d")
)
tb
```
```{r subsetting-32}
tb["x"]
```
```{r subsetting-33}
tb[, "x"]
```
除此以外,`tibble`还有很多优良的[特性](https://tibble.tidyverse.org/),我们会在第 \@ref(tidyverse-tibble) 章专门讲
## 作业
1. 如何获取`matrix(1:9, nrow = 3)`上对角元? 对角元?
```{r subsetting-34, include=FALSE}
m <- matrix(1:9, nrow = 3)
m
```
```{r subsetting-35, include=FALSE}
diag(m)
upper.tri(m, diag = FALSE)
```
```{r subsetting-36, include=FALSE}
m[upper.tri(m, diag = FALSE)]
```
2. 对数据框,思考`df["x"]`, `df[["x"]]`, `df$x`三者的区别?
3. 如果`x`是一个矩阵,请问 `x[] <- 0` 和`x <- 0` 有什么区别?
4. 不添加参数`na.rm = TRUE`的前提下,用`sum()`计算向量`x`的元素之和
```{r, eval=FALSE}
x <- c(3, 5, NA, 2, NA)
```
提示:
- 使用`is.na(x)` 检查向量元素是否为缺失值,并保存为新的对象x_missing
- 将所有缺失值赋值为0
- 然后 `sum()` 计算
```{r, include=FALSE}
x <- c(3, 5, NA, 2, NA)
x_missing <- is.na(x)
x_missing
x[x_missing] <- 0
x
sum(x)
```
5. 找出`x`向量中的偶数
```{r}
x <- 1:10
x
```
```{r, include=FALSE}
x[x %% 2 == 0]
```
```{r, include=FALSE}
# remove the objects
rm(a, df, l, tb, x, y)
```
```{r subsetting-38, echo = F, message = F, warning = F, results = "hide"}
pacman::p_unload(pacman::p_loaded(), character.only = TRUE)
```