R语言入门运行样例

原则1:不全,逐渐补充

原则2:够用就行

命令行界面

如果使用RStudio软件,有一个“Console窗格”相当于命令行界面。 在RStudio中,可以用New File–Script file功能建立一个源程序文件(脚本文件),在脚本文件中写程序,然后用Run图标或者Ctrl+Enter键运行当前行或者选定的部分。

运行例子

注:在命令行定义的变量称为全局变量。

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
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
# R里面真假是TRUE/FALSE,缺失时为NA
# 为了判断向量每个元素是否NA, 用is.na()函数,如
c(1, NA, 3) > 2
## [1] FALSE NA TRUE
NA == NA
## [1] NA

# 用is.finite()判断向量每个元素是否Inf值。
# a %in% b为集合运算,即a是否在b中

# 函数match(x, y)起到和x %in% y运算类似的作用, 但是其返回结果不是找到与否, 而是对x的每个元素, 找到其在y中首次出现的下标,找不到时取缺失值,如
match(c(1, 3), c(2,3,4,3))
## [1] NA 2

# 逻辑运算符: &, |, !, xor(x, y)(注意,这些不是位运算!)
# &&和||分别为短路的标量逻辑与和短路的标量逻辑或, 仅对两个标量进行运算,如果有向量也仅使用第一个元素。
# 一般用在if语句、while语句中, 且只要第一个比较已经决定最终结果就不计算第二个比较。

# 逻辑运算函数

# all 全成立
# any 一个成立
c(1, NA, 3) > 2
## [1] FALSE NA TRUE
all(c(1, NA, 3) > 2)
## [1] FALSE
any(c(1, NA, 3) > 2)
## [1] TRUE
all(NA)
## [1] NA
any(NA)
## [1] NA

# 函数which()返回真值对应的所有下标,如
which(c(FALSE, TRUE, TRUE, FALSE, NA))
## [1] 2 3
which((11:15) > 12)
## [1] 3 4 5

# 函数identical(x,y)比较两个R对象x与y的内容是否完全相同, 结果只会取标量TRUE与FALSE两种。 如
identical(c(1,2,3), c(1,2,NA))
## [1] FALSE
identical(c(1L,2L,3L), c(1,2,3))
## [1] FALSE

# 函数all.equal()与identical()类似, 但是在比较数值型时不区分整数型与实数型, 而且相同时返回标量TRUE, 但是不同时会返回一个说明有何不同的字符串。如
all.equal(c(1,2,3), c(1,2,NA))
## [1] "'is.NA' value mismatch: 1 in current 0 in target"
all.equal(c(1L,2L,3L), c(1,2,3))
## [1] TRUE

# 函数duplicated()返回每个元素是否为重复值的结果,如:
duplicated(c(1,2,1,3,NA,4,NA))
## [1] FALSE FALSE TRUE FALSE FALSE FALSE TRUE

# 用函数unique()可以返回去掉重复值的结果。

# 加减乘除
5 ^ 2 + (2.3 - 1.125) * 3.2 / 1.1 + 1.23E3

# 整除
5 %/% 5

# 求余
1 %% 6

# 开方
sqrt(6.25)

# 指数
exp(1)

# 对数
log10(10000)

# 取整
## 四舍五入
round(1.1234, 2)
round(-1.9876, 2)

## 下取整
floor(1.1234)
floor(-1.1234)

## 上取整
ceiling(1.1234)
ceiling(-1.1234)

# 三角函数
pi
sin(pi/6)
cos(pi/6)
tan(pi/6)

# 反三角函数
pi/6
asin(0.5)
acos(sqrt(3)/2)
atan(sqrt(3)/3)

# 逻辑型是R的基本数据类型之一,只有两个值TRUE和FALSE, 缺失时为NA。逻辑值一般产生自比较,如

sele <- (log10(15) < 2); print(sele)
## [1] TRUE
# 向量比较结果为逻辑型向量。如

c(1, 3, 5) > 2
## [1] FALSE TRUE TRUE
(1:4) >= (4:1)
## [1] FALSE FALSE TRUE TRUE
# 从例子可以看出,向量比较也遵从R的向量间运算的一般规则: 向量与标量的运算是向量每个元素与标量都分别运算一次, 等长向量的运算时对应元素的运算, 不等长但长度为倍数关系的向量运算是把短的从头重复利用。

# 与NA比较产生NA,如

c(1, NA, 3) > 2
## [1] FALSE NA TRUE
NA == NA
## [1] NA
# 为了判断向量每个元素是否NA, 用is.na()函数,如

is.na(c(1, NA, 3) > 2)
## [1] FALSE TRUE FALSE
# 用is.finite()判断向量每个元素是否Inf值。

# 比较运算符包括
< <= > >= == != %in%
# 分别表示小于、小于等于、大于、大于等于、等于、不等于、属于。 要注意等于比较用了两个等号。

# %in%是比较特殊的比较, x %in% y的运算把向量y看成集合, 运算结果是一个逻辑型向量, 第个元素的值为x的第元素是否属于y的逻辑型值。 如

c(1,3) %in% c(2,3,4)
## [1] FALSE TRUE
c(NA,3) %in% c(2,3,4)
## [1] FALSE TRUE
c(1,3) %in% c(NA, 3, 4)
## [1] FALSE TRUE
c(NA,3) %in% c(NA, 3, 4)
## [1] TRUE TRUE
# 函数match(x, y)起到和x %in% y运算类似的作用, 但是其返回结果不是找到与否, 而是对x的每个元素, 找到其在y中首次出现的下标,找不到时取缺失值,如

# match(c(1, 3), c(2,3,4,3))
## [1] NA 2

# 为了表达如“而且”, “或者”之类的复合比较, 需要使用逻辑运算把两个比较连接起来。 逻辑运算符为&, |和!, 分别表示“同时成立”、“两者至少其一成立”、“条件的反面”。 比如,设age<=3表示婴儿,sex=='女'表示女性,则 age<=3 & sex=='女'表示女婴, age<=3 | sex=='女'表示婴儿或妇女, !(age<=3 | sex=='女')表示既非婴儿也非妇女。 为了确定运算的先后次序可以用圆括号()指定。
# 用xor(x, y)表示x与y的异或运算, 即值不相等时为真值,相等时为假值, 有缺失值参加运算时为缺失值。

# 逻辑向量与逻辑标量之间的逻辑运算, 两个逻辑向量之间的逻辑运算规则遵从一般R向量间运算规则。

# 在右运算符是缺失值时, 如果左运算符能够确定结果真假, 可以得到非缺失的结果。 例如,TRUE | NA为TRUE, FALSE & NA为FALSE。 不能确定结果时返回NA, 比如, TRUE & NA为NA, FALSE | NA为NA。

# &&和||分别为短路的标量逻辑与和短路的标量逻辑或, 仅对两个标量进行运算,如果有向量也仅使用第一个元素。 一般用在if语句、while语句中, 且只要第一个比较已经决定最终结果就不计算第二个比较。 例如

# if(TRUE || sqrt(-1)>0) next
# 其中的sqrt(-1)部分不会执行。 其中条件的结果为TRUE, 第二部分没有参加计算, 否则第二部分的计算会发生函数自变量范围错误。

# 因为R中比较与逻辑运算都支持向量之间、向量与标量之间的运算, 所以在需要一个标量结果时要特别注意, 后面讲到的if结构、while结构都需要逻辑标量而且不能是缺失值。 这时,应该对缺失值结果单独考虑。

# 若cond是逻辑向量, 用all(cond)测试cond的所有元素为真; 用any(cond)测试cond至少一个元素为真。 cond中允许有缺失值,结果可能为缺失值。 如

c(1, NA, 3) > 2
## [1] FALSE NA TRUE
all(c(1, NA, 3) > 2)
## [1] FALSE
any(c(1, NA, 3) > 2)
## [1] TRUE
all(NA)
## [1] NA
any(NA)
## [1] NA
# 函数which()返回真值对应的所有下标,如

which(c(FALSE, TRUE, TRUE, FALSE, NA))
## [1] 2 3
which((11:15) > 12)
## [1] 3 4 5
# 函数identical(x,y)比较两个R对象x与y的内容是否完全相同, 结果只会取标量TRUE与FALSE两种。 如

identical(c(1,2,3), c(1,2,NA))
## [1] FALSE
identical(c(1L,2L,3L), c(1,2,3))
## [1] FALSE
# 其中第二个结果假值是因为前一向量是整数型, 后一向量是实数型。

# 函数all.equal()与identical()类似, 但是在比较数值型时不区分整数型与实数型, 而且相同时返回标量TRUE, 但是不同时会返回一个说明有何不同的字符串。如

all.equal(c(1,2,3), c(1,2,NA))
## [1] "'is.NA' value mismatch: 1 in current 0 in target"
all.equal(c(1L,2L,3L), c(1,2,3))
## [1] TRUE
# 函数duplicated()返回每个元素是否为重复值的结果,如:

duplicated(c(1,2,1,3,NA,4,NA))
## [1] FALSE FALSE TRUE FALSE FALSE FALSE TRUE
# 用函数unique()可以返回去掉重复值的结果。

# 管道运算符 |>
exp(1.0) |> log() ## 等价于log(exp(1.0))

# 对向量x, 在后面加方括号和下标可以访问向量的元素和子集。

# 设x <- c(1, 4, 6.25)。 x[2]取出第二个元素; x[2] <- 99修改第二个元素。 x[c(1,3)]取出第1、3号元素; x[c(1,3)] <- c(11, 13)修改第1、3号元素。 下标可重复。 例如
x <- c(1, 4, 6.25)
x[2]
## [1] 4
x[2] <- 99; x
## [1] 1.00 99.00 6.25
x[c(1,3)]
## [1] 1.00 6.25
x[c(1,3)] <- c(11, 13); x
## [1] 11 99 13
x[c(1,3,1)]
## [1] 11 13 11

# 负下标表示扣除相应的元素后的子集,如
x <- c(1,4,6.25)
x[-2]
## [1] 1.00 6.25
x[-c(1,3)]
## [1] 4
# 负整数下标不能与正整数下标同时用来从某一向量中取子集, 比如,x[c(1,-2)]没有意义。

# x[]表示取x的全部元素作为子集。 这与x本身不同,比如
x <- c(1,4,6.25)
x[] <- 999
x
## [1] 999 999 999
x <- c(1,4,6.25)
x <- 999
x
## [1] 999
# x[0]是一种少见的做法, 结果返回类型相同、长度为零的向量, 如numeric(0)。 相当于空集。
# 当0与正整数下标一起使用时会被忽略。 当0与负整数下标一起使用时也会被忽略。

# 设向量x长度为, 则使用正整数下标时下标应在中取值。 如果使用大于的下标, 读取时返回缺失值,并不出错。 给超出的下标元素赋值, 则向量自动变长, 中间没有赋值的元素为缺失值。 例如

x <- c(1,4,6.25)
x[5]
## [1] NA
x
## [1] 1.00 4.00 6.25
x[5] <- 9
x
## [1] 1.00 4.00 6.25 NA 9.00
# 虽然R的语法对下标超界不视作错误, 但是这样的做法往往来自不良的程序思路, 而且对程序效率有影响, 所以实际编程中应避免下标超界。

# 下标可以是与向量等长的逻辑表达式, 一般是关于本向量或者与本向量等长的其它向量的比较结果,如

x <- c(1,4,6.25)
x[x > 3]
## [1] 4.00 6.25
# 取出x的大于3的元素组成的子集。

# 逻辑下标除了用来对向量取子集, 还经常用来对数据框取取子集, 也用在向量化的运算中。 例如,对如下示性函数
# 输入向量x,结果y需要也是一个向量,程序可以写成

f <- function(x){
y <- numeric(length(x))
y[x >= 0] <- 1
y[x < 0] <- 0 # 此语句多余

y
}
# 事实上,向量化的逻辑选择有一个ifelse()函数, 比如,对上面的示性函数, 如果x是一个向量, 输出y向量可以写成y <- ifelse(x>=0, 1, 0)。
# 要注意的是,如果逻辑下标中有缺失值, 对应结果也是缺失值。 所以,在用逻辑下标作子集选择时, 一定要考虑到缺失值问题。正确的做法是加上!is.na前提, 如

x <- c(1, 4, 6.25, NA)
x[x > 2]
## [1] 4.00 6.25 NA
x[!is.na(x) & x > 2]
## [1] 4.00 6.25

# 函数which()可以用来找到满足条件的下标, 如
x <- c(3, 4, 3, 5, 7, 5, 9)
which(x > 5)
## [1] 5 7
seq(along=x)[x > 5]
## [1] 5 7
# 这里seq(along=x)会生成由x的下标组成的向量。 用which.min()、which.max求最小值的下标和最大值的下标, 不唯一时只取第一个。如

which.min(x)
## [1] 1
which.max(x)
## [1] 7

# 向量可以为每个元素命名。如
ages <- c("李明"=30, "张聪"=25, "刘颖"=28)
# 或
ages <- c(30, 25, 28)
names(ages) <- c("李明", "张聪", "刘颖")
# 或
ages <- setNames(c(30, 25, 28), c("李明", "张聪", "刘颖"))
# 这时可以用元素名或元素名向量作为向量的下标,如
ages["张聪"]
## 张聪
## 25
ages[c("李明", "刘颖")]
## 李明 刘颖
## 30 28
ages["张聪"] <- 26
# 这实际上建立了字符串到数值的映射表。
# 用字符串作为下标时, 如果该字符串不在向量的元素名中, 读取时返回缺失值结果, 赋值时该向量会增加一个元素并以该字符串为元素名。

# 带有元素名的向量也可以是字符型或其它基本类型,如
sex <- c("李明"="男", "张聪"="男", "刘颖"="女")
# 除了给向量元素命名外, 在矩阵和数据框中还可以给行、列命名, 这会使得程序的扩展更为容易和安全。
# R允许仅给部分元素命名, 这时其它元素名字为空字符串。 不同元素的元素名一般应该是不同的, 否则在使用元素作为下标时会发生误读, 但是R语法允许存在重名。
# 用unname(x)返回去掉了元素名的x的副本, 用names(x) <- NULL可以去掉x的元素名。

# R在使用整数作为向量下标时,允许使用重复下标, 这样可以把数组x看成一个的整数到 x[1], x[2], , x[n]的一个映射表, 其中是x的长度。 比如,某商店有三种礼品,编号为1,2,3, 价格分别为68, 88和168。令
price_map <- c(68, 88, 168)
# 设某个收银员在一天内分别售出礼品编号为3,2,1,1,2,2,3, 可以用如下的映射方式获得售出的这些礼品对应的价格:

items <- c(3,2,1,1,2,2,3)
y <- price_map[items]; print(y)
## [1] 168 88 68 68 88 88 168
# R向量可以用字符型向量作下标, 字符型下标也允许重复, 所以可以把带有元素名的R向量看成是元素名到元素值的映射表。 比如,设sex为10个学生的性别(男、女)

sex <- c("男", "男", "女", "女", "男", "女", "女", "女", "女", "男")
# 希望把每个学生按照性别分别对应到蓝色和红色。 首先建立一个R向量当作映射

sex_color <- c("男"="blue", "女"="red")
# 用R向量sex.color当作映射,可以获得每个学生对应的颜色

cols <- sex_color[sex]; print(cols)
## 男 男 女 女 男 女 女 女 女 男
## "blue" "blue" "red" "red" "blue" "red" "red" "red" "red" "blue"
# 这样的映射结果中带有不必要的元素名, 用unname()函数可以去掉元素名,如

unname(cols)
## [1] "blue" "blue" "red" "red" "blue" "red" "red" "red" "red" "blue"

# 可以把向量x看成一个集合,但是其中的元素允许有重复。 用unique(x)可以获得x的所有不同值。如
unique(c(1, 5, 2, 5))
## [1] 1 5 2
# 用a %in% x判断a的每个元素是否属于向量x,如

5 %in% c(1,5,2)
## [1] TRUE
c(5,6) %in% c(1,5,2)
## [1] TRUE FALSE
# 与%in运算符类似, 函数match(x, table)对向量x的每个元素, 从向量table中查找其首次出现位置并返回这些位置。 没有匹配到的元素位置返回NA_integer_(整数型缺失值)。 如

match(5, c(1,5,2))
## [1] 2
match(5, c(1,5,2,5))
## [1] 2
match(c(2,5), c(1,5,2,5))
## [1] 3 2
match(c(2,5,0), c(1,5,2,5))
## [1] 3 2 NA
# 用intersect(x,y)求交集,结果中不含重复元素,如

intersect(c(5, 7), c(1, 5, 2, 5))
## [1] 5
# 用union(x,y)求并集,结果中不含重复元素,如

union(c(5, 7), c(1, 5, 2, 5))
## [1] 5 7 1 2
# 用setdiff(x,y)求差集,即x的元素中不属于y的元素组成的集合, 结果中不含重复元素,如

setdiff(c(5, 7), c(1, 5, 2, 5))
## [1] 7
# 用setequal(x,y)判断两个集合是否相等, 不受次序与重复元素的影响,如

setequal(c(1,5,2), c(2,5,1))
## [1] TRUE
setequal(c(1,5,2), c(2,5,1,5))
## [1] TRUE

# 可以用typeof()函数来返回一个变量或表达式的类型

# 可以用as.xxx()类的函数在不同类型之间进行强制转换。 如
as.numeric(c(FALSE, TRUE))
## [1] 0 1
as.character(sqrt(1:4))
## [1] "1" "1.4142135623731" "1.73205080756888" "2"

# 除了NULL以外, R的变量都可以看成是对象, 都可以有属性。 在R语言中, 属性是把变量看成对象后, 除了其存储内容(如元素)之外的其它附加信息, 如维数、类属等。 R对象一般都有length和mode两个属性。
# 常用属性有names, dim,class等。

# 对象x的所有属性可以用attributes()读取, 如
x <- table(c(1,2,1,3,2,1)); print(x)
##
## 1 2 3
## 3 2 1
attributes(x)
## $dim
## [1] 3
##
## $dimnames
## $dimnames[[1]]
## [1] "1" "2" "3"
##
##
## $class
## [1] "table"
# table()函数用了输出其自变量中每个不同值的出现次数,称为频数。 从上例可以看出, table()函数的结果有三个属性,前两个是dim和dimnames, 这是数组(array)具有的属性; 另一个是class属性,值为"table"。 因为x是数组,可以访问如

x[1]
## 1
## 3
x["3"]
## 3
## 1
# 也可以用attributes()函数修改属性, 如

attributes(x) <- NULL
x
## [1] 3 2 1
# 如上修改后x不再是数组,也不是table。

# 可以用attr(x, "属性名")的格式读取或定义x的属性。 如:

x <- c(1,3,5)
attr(x, "theta") <- c(0, 1)
print(x)
## [1] 1 3 5
## attr(,"theta")
## [1] 0 1
# 可以让向量x额外地保存一个theta属性, 这样的属性常常成为“元数据”(meta data), 比如, 用来保存数据的说明、模拟数据的真实模型参数,等等。

# 有元素名的向量、列表、数据框等都有names属性, 许多R函数的输出本质上也是列表, 所以也有names属性。 用names(x)的格式读取或设定。 如:
x <- 1:5
y <- x^2
lmr <- lm(y ~ x)
print(names(lmr))
## [1] "coefficients" "residuals" "effects" "rank"
## [5] "fitted.values" "assign" "qr" "df.residual"
## [9] "xlevels" "call" "terms" "model"
# 对于没有元素名的向量x,names(x)的返回值是NULL。

# dim属性的存在表明对象是矩阵或一维、多维数组。 如:
x <- matrix(1:12, nrow=3, ncol=4)
attr(x, "dim") # 等同于dim(x)
## [1] 3 4
# 修改dim属性就将向量转换成矩阵(数组), 或修改了矩阵的性质, 元素按列次序重排填入新的矩阵。如:
x <- 1:4
dim(x) <- c(2,2)
x
## [,1] [,2]
## [1,] 1 3
## [2,] 2 4
# R允许dim仅有一个元素, 这对应于一维向量, 与普通的没有dim属性的向量有区别。 另外要注意, 取矩阵子集时如果结果仅有一列或一行, 除非用了drop=FALSE选项, 结果不再有dim属性, 退化成了普通向量。

# R具有一定的面向对象语言特征, 其数据类型有一个class属性, 函数class()可以返回变量类型的类属, 比如
typeof(factor(c('F', 'M', 'M', 'F')))
## [1] "integer"
mode(factor(c('F', 'M', 'M', 'F')))
## [1] "numeric"
storage.mode(factor(c('F', 'M', 'M', 'F')))
## [1] "integer"
class(factor(c('F', 'M', 'M', 'F')))
## [1] "factor"
class(as.numeric(factor(c('F', 'M', 'M', 'F'))))
## [1] "numeric"
# class属性是特殊的。 如果一个对象具有class属性, 某些所谓“通用函数(generic functions)”会针对这样的对象进行专门的操作, 比如, print()函数在显示向量和回归结果时采用完全不同的格式。 这在其它程序设计语言中称为“重载”(overloading)。
# class属性用来支持R的S3风格的类, 常用的有factor, 日期,日期时间, 数据框,tibble。 R还有S4、R6等风格的类。

# 用print()函数可以显示对象内容。 如果内容很多, 显示行数可能也很多。 用str()函数可以显示对象的类型和主要结构及典型内容。例如
s <- 101:200
attr(s,'author') <- '李小明'
attr(s,'date') <- '2016-09-12'
str(s)
## int [1:100] 101 102 103 104 105 106 107 108 109 110 ...
## - attr(*, "author")= chr "李小明"
## - attr(*, "date")= chr "2016-09-12"

# R日期可以保存为Date类型

# R中用因子代表数据中分类变量, 如性别、省份、职业。 有序因子代表有序量度,如打分结果,疾病严重程度等。
# 用factor()函数把字符型向量转换成因子,如
x <- c("男", "女", "男", "男", "女")
sex <- factor(x)
sex
## [1] 男 女 男 男 女
## Levels: 男 女
attributes(sex)
## $levels
## [1] "男" "女"
##
## $class
## [1] "factor"
# 因子有class属性,取值为"factor", 还有一个levels(水平值)属性, 此属性可以用levels()函数访问,如
levels(sex)
## [1] "男" "女"
# 因子的levels属性可以看成是一个映射, 把整数值1,2,映射成这些水平值, 因子在保存时会保存成整数值1,2,等与水平值对应的编号。 这样可以节省存储空间, 在建模计算的程序中也比较有利于进行数学运算。
# 事实上, read.csv()函数的默认操作会把输入文件的字符型列自动转换成因子, 这对于性别、职业、地名这样的列是合适的, 但是对于姓名、日期、详细地址这样的列则不合适。 所以,在read.csv()调用中经常加选项stringsAsFactors=FALSE选项禁止这样的自动转换,还可以用colClasses选项逐个指定每列的类型。 建议改用readr包的read_csv()函数, 这个函数读入CSV时不自动转换因子, 生成data.frame的替代类型tibble。
# 用as.numeric()可以把因子转换为纯粹的整数值,如

as.numeric(sex)
## [1] 1 2 1 1 2
# 因为因子实际保存为整数值, 所以对因子进行一些字符型操作可能导致错误。 用as.character()可以把因子转换成原来的字符型,如

as.character(sex)
## [1] "男" "女" "男" "男" "女"
# 为了对因子执行字符型操作(如取子串), 保险的做法是先用as.character()函数强制转换为字符型。

factor()函数的一般形式为
factor(x, levels = sort(unique(x), na.last = TRUE),
labels, exclude = NA, ordered = FALSE)
# 可以用选项levels自行指定各水平值, 不指定时由x的不同值来求得。 可以用选项labels指定各水平的标签, 不指定时用各水平值的对应字符串。 可以用exclude选项指定要转换为缺失值(NA)的元素值集合。 如果指定了levels, 则当自变量x的某个元素等于第个水平值时输出的因子对应元素值取整数, 如果该元素值没有出现在levels中则输出的因子对应元素值取NA。 ordered取真值时表示因子水平是有次序的(按编码次序)。
# 在使用factor()函数定义因子时, 如果知道自变量元素的所有可能取值, 应尽可能使用levels=参数指定这些不同可能取值, 这样, 即使某个取值没有出现, 此变量代表的含义和频数信息也是完整的。 自己指定levels=的另一好处是可以按正确的次序显示因子的分类统计值。
# 因为一个因子的levels属性是该因子独有的, 所以用c()或者rbind()合并两个因子有可能造成错误, 保险的做法是在定义两个因子时用levels参数指定相同的水平值集合。 较新版本的R软件已经解决了这个问题。

# 连续取值的变量,可以用cut()函数将其分段, 转换成因子。 使用breaks()参数指定分点, 最小分点要小于数据的最小值, 最大分点要大于等于数据的最大值, 默认使用左开右闭区间分组, 如:
cut(1:10, breaks=c(0, 5, 10))
## [1] (0,5] (0,5] (0,5] (0,5] (0,5] (5,10] (5,10] (5,10] (5,10] (5,10]
## Levels: (0,5] (5,10]
# 可以指定breaks为一个正整数, 表示将数据范围略扩大后进行等间距分组,如:

set.seed(1)
x <- sort(round(rnorm(20), 2))
f <- cut(x, breaks=4); f
## [1] (-2.21,-1.26] (-1.26,-0.305] (-1.26,-0.305] (-1.26,-0.305] (-1.26,-0.305]
## [6] (-1.26,-0.305] (-0.305,0.647] (-0.305,0.647] (-0.305,0.647] (-0.305,0.647]
## [11] (-0.305,0.647] (-0.305,0.647] (-0.305,0.647] (-0.305,0.647] (0.647,1.6]
## [16] (0.647,1.6] (0.647,1.6] (0.647,1.6] (0.647,1.6] (0.647,1.6]
## Levels: (-2.21,-1.26] (-1.26,-0.305] (-0.305,0.647] (0.647,1.6]
# 可以修改水平标记, 如:
levels(f) <- c("a", "b", "c", "d"); f
## [1] a b b b b b c c c c c c c c d d d d d d
## Levels: a b c d
# 为了实现各组个数比较平均的分组, 可以利用quantile()函数计算分位数作为分组, 如:
cu <- quantile(x, c(0, 1/4, 1/2, 3/4, 1))
cu[1] <- cu[1] - 0.01*(cu[5] - cu[1])
f2 <- cut(x, breaks=cu, oredered_result=TRUE)
levels(f2) <- c("a", "b", "c", "d"); f2
## [1] a a a a a b b b b b c c c c c d d d d d
## Levels: a b c d
# 参数oredered_result=TRUE表示生成有序因子。

# 用table()函数统计因子各水平的出现次数(称为频数或频率)。 也可以对一般的向量统计每个不同元素的出现次数。 如
table(sex)
## sex
## 男 女
## 3 2
# 对一个变量用table函数计数的结果是一个特殊的有元素名的向量, 元素名是自变量的不同取值, 结果的元素值是对应的频数。 单个因子或单个向量的频数结果可以用向量的下标访问方法取出单个频数或若干个频数的子集。

# 可以按照因子分组然后每组计算另一变量的概括统计。 如
h <- c(165, 170, 168, 172, 159)
tapply(h, sex, mean)
## 男 女
## 168.3333 164.5000
# 这里第一自变量h与与第二自变量sex是等长的, 对应元素分别为同一人的身高和性别, tapply()函数分男女两组计算了身高平均值。

library(forcats)
# 在分类变量类数较多时,往往需要对因子水平另外排序、合并等, forcats包提供了一些针对因子的方便函数。
# forcats::fct_reorder()可以根据不同因子水平分成的组中另一数值型变量的统计量值排序。 如:
set.seed(1)
fac <- sample(c("red", "green", "blue"), 30, replace=TRUE)
fac <- factor(fac, levels=c("red", "green", "blue"))
x <- round(100*(10+rt(30,2)))
res1 <- tapply(x, fac, sd); res1
## red green blue
## 370.9222 138.3185 1129.2587
barplot(res1)


# 如果希望按照统计量次序对因子排序, 可以用forcats::fct_reorder()函数, 如
fac2 <- fct_reorder(fac, x, sd)
res2 <- tapply(x, fac2, sd)
barplot(res2)

# 新的因子fac2的因子水平次序已经按照变量x的标准差从小到大排列。
# 有时在因子水平数较多时仅想将特定的一个或几个水平次序放到因子水平最前面, 可以用forcats::fct_relevel()函数, 如:

levels(fac)
## [1] "red" "green" "blue"
fac3 <- fct_relevel(fac, "blue"); levels(fac3)
## [1] "blue" "red" "green"
# fct_relevel()第一个参数是要修改次序的因子, 后续可以有多个字符型参数表示要提前的水平。
# forcats::fct_reorder2(f, x, y)也调整因子f的水平的次序, 但是根据与每组中最大的x值相对应的y值大小调整次序, 这样在作多个因子水平对应的曲线图时可以比较容易地区分多条曲线。
# forcats::fct_recode()可以修改每个水平的名称, 如:

fac4 <- fct_recode(
fac,
"红"="red", "绿"="green", "蓝"="blue")
table(fac4)
## fac4
## 红 绿 蓝
## 13 10 7
# fct_recode()在修改水平名时允许多个旧水平对应到一个新水平, 从而合并原来的水平。 如果合并很多, 可以用fct_collapse()函数, 如

compf <- fct_collapse(
comp,
"其它"=c("", "无名", "无应答"),
"联想"=c("联想", "联想集团"),
"百度"=c("百度", "百度集团")
)
# 如果某个因子频数少的水平很多, 在统计时有过多水平不易展示主要的类别, 可以用forcats::fct_lump(f)合并, 缺省地从最少的类合并一直到“其它”类超过其它最小的类之前, 可以用n=参数指定要保留多少个类。



# 1. 命令行的计算结果直接显示在命令的后面
# 2. 在用source()运行程序文件时, 需要用print()函数显示一个表达式的结果,如:
print(sin(pi/2))
# 3. 用cat显示多项内容
cat("sin(pi/2)=", sin(pi/2), "\n")

# 用print()函数显示向量或在命令行中显示向量时, 每行显示的行首会有方括号和数字序号, 代表该行显示的第一个向量元素的下标。如
12345678901:12345678920
## [1] 12345678901 12345678902 12345678903 12345678904 12345678905
## [6] 12345678906 12345678907 12345678908 12345678909 12345678910
## [11] 12345678911 12345678912 12345678913 12345678914 12345678915
## [16] 12345678916 12345678917 12345678918 12345678919 12345678920

# 用sink做函数记录
## R使用经常是在命令行逐行输入命令(程序), 结果紧接着显示在命令后面
## 如何保存这些命令和显示结果? 在R命令行中运行过的命令会被保存在运行的工作文件夹中的一个名为.Rhistory的文件中
## 用sink()函数打开一个文本文件开始记录文本型输出结果
## 结束记录时用空的sink()即可关闭文件不再记录
sink("tmpres01.txt", split=TRUE)
print(sin(pi/6))
print(cos(pi/6))
cat("t(10)的双侧0.05分位数(临界值)=", qt(1 - 0.05/2, 10), "\n")
sink()

# 向量
# 注:start:end表示[start, end]
# 注2:下标从1开始
x1 <- 1:10
x1
## [1] 1 2 3 4 5 6 7 8 9 10

# 也可以这么生成
marks <- c(3, 5, 10, 5, 6)
x <- c(1:3, 10:13)

# 向量可以和一个标量作四则运算, 结果是每个元素都和这个标量作四则运算,如
x1 + 200
2*x1
2520/x1

# 两个等长的向量可以进行四则运算, 相当于对应元素进行四则运算,如
x2 <- x1 * 3
x2 - x1

# 两个不等长向量的四则运算, 如果其长度为倍数关系,规则是每次从头重复利用短的一个。 如
x1 <- c(10, 20)
x2 <- c(1, 3, 5, 7)
x1 + x2
## [1] 11 23 15 27

# sort(x)返回排序结果。 rev(x)返回把各元素排列次序反转后的结果。 order(x)返回排序用的下标。如
x <- c(33, 55, 11)
sort(x)
## [1] 11 33 55
rev(sort(x))
## [1] 55 33 11
order(x)
## [1] 3 1 2
x[order(x)]
## [1] 11 33 55

# R的许多函数都可以用向量作为自变量, 结果是自变量的每个元素各自的函数值。 如
sqrt(x1)

# 复数向量
# 用函数complex()生成复数向量, 指定实部和虚部。 如
complex(real = c(1,0,-1,0), imaginary = c(0,1,0,-1))
## 相当于c(1+0i, 1i, -1+0i, -1i)。

# 正整数下标代表拿元素
x <- c(1, 4, 6.25)
x[2]
## [1] 4
x[2] <- 99; x
## [1] 1.00 99.00 6.25
x[c(1,3)]
## [1] 1.00 6.25
x[c(1,3)] <- c(11, 13); x
## [1] 11 99 13
x[c(1,3,1)]
## [1] 11 13 11

# 负整数下标代表扣除相应的元素后的子集,如
x <- c(1,4,6.25)
x[-2]
## [1] 1.00 6.25
x[-c(1,3)]
## [1] 4

# x[]表示取x的全部元素作为子集。 这与x本身不同,比如
x <- c(1,4,6.25)
x[] <- 999
x
## [1] 999 999 999
x <- c(1,4,6.25)
x <- 999
x
## [1] 999

# x[0]是一种少见的做法, 结果返回类型相同、长度为零的向量, 如numeric(0)。 相当于空集。

# 设向量x长度为, 则使用正整数下标时下标应在中取值。
# 如果使用大于的下标, 读取时返回缺失值,并不出错。
# 给超出的下标元素赋值, 则向量自动变长, 中间没有赋值的元素为缺失值。 例如
x <- c(1,4,6.25)
x[5]
## [1] NA
x
## [1] 1.00 4.00 6.25
x[5] <- 9
x
## [1] 1.00 4.00 6.25 NA 9.00

# 下标可以是与向量等长的逻辑表达式, 一般是关于本向量或者与本向量等长的其它向量的比较结果,如取出x的大于3的元素组成的子集。
x <- c(1,4,6.25)
x[x > 3]
## [1] 4.00 6.25
# 对于f(x)= 1 if x >= 0 else 0
f <- function(x){
y <- numeric(length(x))
y[x >= 0] <- 1
y[x < 0] <- 0 # 此语句多余

y
}

# 要注意的是,如果逻辑下标中有缺失值, 对应结果也是缺失值。
# 所以,在用逻辑下标作子集选择时, 一定要考虑到缺失值问题。正确的做法是加上!is.na前提, 如
x <- c(1, 4, 6.25, NA)
x[x > 2]
## [1] 4.00 6.25 NA
x[!is.na(x) & x > 2]
## [1] 4.00 6.25

# 函数which()可以用来找到满足条件的下标, 如
x <- c(3, 4, 3, 5, 7, 5, 9)
which(x > 5)
## [1] 5 7
seq(along=x)[x > 5]
## [1] 5 7
# 这里seq(along=x)会生成由x的下标组成的向量。 用which.min()、which.max求最小值的下标和最大值的下标, 不唯一时只取第一个。如
which.min(x)
## [1] 1
which.max(x)
## [1] 7

# 向量可以为每个元素命名。如
ages <- c("李明"=30, "张聪"=25, "刘颖"=28)
# 或
ages <- c(30, 25, 28)
names(ages) <- c("李明", "张聪", "刘颖")
# 或
ages <- setNames(c(30, 25, 28), c("李明", "张聪", "刘颖"))
# 这时可以用元素名或元素名向量作为向量的下标,如
ages["张聪"]
## 张聪
## 25
ages[c("李明", "刘颖")]
## 李明 刘颖
## 30 28
ages["张聪"] <- 26
# 用unname(x)返回去掉了元素名的x的副本, 用names(x) <- NULL可以去掉x的元素名。

# 用intersect(x,y)求交集,结果中不含重复元素,如
intersect(c(5, 7), c(1, 5, 2, 5))
## [1] 5

# 用union(x,y)求并集,结果中不含重复元素,如
union(c(5, 7), c(1, 5, 2, 5))
## [1] 5 7 1 2

# 用setdiff(x,y)求差集,即x的元素中不属于y的元素组成的集合, 结果中不含重复元素,如
setdiff(c(5, 7), c(1, 5, 2, 5))
## [1] 7

# 用setequal(x,y)判断两个集合是否相等, 不受次序与重复元素的影响,如
setequal(c(1,5,2), c(2,5,1))
## [1] TRUE
setequal(c(1,5,2), c(2,5,1,5))
## [1] TRUE

# paste用来连接两个向量,如paste(c("ab", "cd"), c("ef", "gh"))相当于c("ab ef", "cd gh")
# paste可以一对多,比如paste("x", 1:3)结果相当于c("x 1", "x 2", "x 3")。
# paste可以用sep=指定分隔符, 如paste("x", 1:3, sep="")结果相当于c("x1", "x2", "x3")。
# 使用collapse=参数可以把字符型向量的各个元素连接成一个单一的字符串, 如paste(c("a", "b", "c"), collapse="")结果相当于"abc"。

# toupper()函数把字符型向量内容转为大写
# tolower()函数转为小写

# 用nchar(x, type='bytes')计算字符型向量x中每个字符串的以字节为单位的长度
# 这一点对中英文是有差别的, 中文通常一个汉字占两个字节,英文字母、数字、标点占一个字节。
# 用nchar(x, type='chars')计算字符型向量x中每个字符串的以字符个数为单位的长度,这时一个汉字算一个单位。

# 在画图时可以用strwidth()函数计算某个字符串或表达式占用的空间大小。

# substr(x, start, stop)从字符串x中取出从第start个到第stop个的子串, 如
substr('JAN07', 1, 3)
## [1] "JAN"
# 如果x是一个字符型向量,substr将对每个元素取子串。如
substr(c('JAN07', 'MAR66'), 1, 3)
## [1] "JAN" "MAR"
# 用substring(x, start)可以从字符串x中取出从第start个到末尾的子串。如
substring(c('JAN07', 'MAR66'), 4)
## [1] "07" "66"

# 用as.numeric()把内容是数字的字符型值转换为数值,如
substr('JAN07', 4, 5)
## [1] "07"
substr('JAN07', 4, 5) + 2000
## Error in substr("JAN07", 4, 5) + 2000 :
## non-numeric argument to binary operator
as.numeric(substr('JAN07', 4, 5)) + 2000
## [1] 2007
as.numeric(substr(c('JAN07', 'MAR66'), 4, 5))
## [1] 7 66
# as.numeric()是向量化的, 可以转换一个向量的每个元素为数值型。

# 用as.character()函数把数值型转换为字符型,如
as.character((1:5)*5)
## [1] "5" "10" "15" "20" "25"
# 如果自变量本来已经是字符型则结果不变。

# 为了用指定的格式数值型转换成字符型, 可以使用sprintf()函数, 其用法与C语言的sprintf()函数相似, 只不过是向量化的。例如
sprintf('file%03d.txt', c(1, 99, 100))
## [1] "file001.txt" "file099.txt" "file100.txt"

# 用gsub()可以替换字符串中的子串, 这样的功能经常用在数据清理中。 比如,把数据中的中文标点改为英文标点, 去掉空格,等等。 如
x <- '1, 3; 5'
gsub(';', ',', x, fixed=TRUE)
## [1] "1, 3, 5"
# 字符串x中分隔符既有逗号又有分号, 上面的程序用gsub()把分号都换成逗号。

# gsub('[[:space:]]+', ' ',
'a cat in a box', perl=TRUE)
## [1] "a cat in a box"



# 读入表格
tax.tab <- read.csv("taxsamp.csv", header=TRUE, as.is=TRUE)
print(head(tax.tab))
## 技巧:read.csv()的一个改进版本是readr扩展包的read_csv()函数, 此函数读入较大表格速度要快得多, 而且读入的转换设置更倾向于不做不必要的转换。 但是, 这两种输入方法的默认中文编码可能不一样。

# 表格频数统计
table(tax.tab[["征收方式"]])

# 交叉频数统计
table(tax.tab[["征收方式"]], tax.tab[["申报渠道"]])

# 数值型变量的统计:最小值、最大值、中位数、四分之一分位数、四分之三分位数和平均值
summary(tax.tab[["营业额"]])
## 单独计算可以使用包括sum(求和), mean(平均值), var(样本方差), sd(样本标准差), min(最小值), max(最大值), range(最大值和最小值)几个函数

# 当前工作路径
getwd()

# 设置工作路径
setwd("/ubuntu/...")

函数

定义格式为

1
2
3
function_name <- function(arg_1, arg_2, ...) {
// 函数体
}

比如

1
2
3
frat <- function(x){
(1 + x + 2*x^2)/(1 + 3*x + 2*x^2 + x^3)
}

工作空间

大概是会保存已经定义的R变量与函数。

RStudio中的“Environment”窗格会显示当前已定义的R变量与函数。

绘图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 函数曲线图
# curve(f(x), start_x, end_x) 绘制关于f(x)的函数,变量范围[start_x, end_x]
curve(x^2, -2, 2)

# 参考线
abline(h=0)

# 柱状图
barplot(c("男生"=10, "女生"=7), main="男女生人数")

# 散点图
plot(1:10, sqrt(1:10))

# 自带的图形示例
demo("graphics")
demo("image")

源文件(模块?)

用source()函数可以运行保存在一个文本文件中的源程序。 比如,如下内容保存在文件ssq.r中:

1
2
3
sum.of.squares <- function(x){
sum(x^2)
}

用如下source()命令运行:

1
2
3
source("ssq.r")

# 可以在source中添加encoding=

其他

  1. 为了查看这些基础的数学函数的列表,运行命令help.start(), 点击链接“Search Engine and Keywords”, 找到“Mathematics”栏目, 浏览其中的“arith”和“math”链接中的说明。
  2. 常用的数学函数有:
    1. 舍入:ceiling, floor, round, signif, trunc, zapsmall
    2. 符号函数 sign
    3. 绝对值 abs
    4. 平方根 sqrt
    5. 对数与指数函数 log, exp, log10, log2
    6. 三角函数 sin, cos, tan
    7. 反三角函数 asin, acos, atan, atan2
    8. 双曲函数 sinh, cosh, tanh
    9. 反双曲函数 asinh, acosh, atanh
  3. 如果自己编写的函数没有考虑向量化问题, 可以用Vectorize()函数将其转换成向量化版本。