写在前面
2024.1.15
近期被几位朋友问对R语言有什么了解,也看到puq有同学分享R语言的学习,社会科学、自然科学的都有。
感觉这应该是挺热门、挺实用的工具,遂决定利用寒假自学R语言,开篇博客记录下学习笔记。
2.12
忙完别的,才想起来还有这个flag,重新开始学习。
先做准备工作,从这里下载R语言的环境并安装,同时在Visual Studio Code里安装相应的模块进行操作,笔者使用的是4.3.2版本。
跟着菜鸟编程一步一步学。
看简介,R语言主要是用来做数学分析,用途和MATLAB差不多。
基础语法
变量
有效变量名称由字母,数字,'.'(点号),'_'(下换线)组成,以字母或点开头。
._.
e.e
这些都是合法变量名,好鬼畜。
变量赋值
<-、=、->都可以赋值,箭头方向是赋值方向。
ls()可以查看所有已命名的变量名。
rm(a)可以把变量a删掉。
a=1
b<-2
3->c #三种基本赋值方式
print(ls()) #输出为"a" "b" "c"
rm(a) #删掉变量a
print(ls()) #输出为"b" "c"
交互式编程
mac在命令行执行'R'可以直接进入交互式编程窗口,windows的cmd不行。
输入q()函数可以退出。
文件脚本
R语言文件后缀是.R
输入输出
print()
print("print") #输出"print"
print(12.30) #输出12.3,自动去末尾的0
print(3.2e2) #输出320,科学计数法
cat()
cat(S,file='D:\\test.txt',append=TRUE)
#可以将S输出到文件中,此处为文件的绝对路径,append参数控制追加还是覆盖,默认是覆盖
sink()
sink("D://test.txt") #控制台输出至目标文件,控制台不显示输出
sink("D://test.txt",split=TRUE) #split参数可以让控制台依然显示输出
sink() #取消文件输出
文字输入
R语言没有专门再从控制台读取的函数,文字输入在 R 的使用中一直在进行。
从文件读入文字
readLines("路径/文件名") #从文件读入,每行一个字符串,最后一行必须有换行
其他方式
CSV、Excel等,挖个坑,以后学。
工作目录
getwd() #get working directory,获取当前工作目录,以字符串形式输出
setwd("路径") #set working directory,设置当前工作目录
注释
#这是一种注释方式
if(FALSE){
"这是另一种注释方式"
}
#Visual Studio Code 可以用ctrl+/注释
数据类型
数字
一般表示法和科学计数法,如2.5,25e-1,25E-1。
逻辑
TRUE和FALSE,严格区分大小写。
文本
字符型数据,单引号或双引号表示。
基础运算
数学运算符
符号 | 含义 | 示例 | 结果 | 优先级 |
() | 括号 | (5) | 3 | 1 |
^ | 乘方 | 5^2 | 25 | 2 |
%% | 取余 | 5%%2 | 1 | 3 |
%/% | 整除 | 5%/%2 | 2 | 3 |
* | 乘 | 5*2 | 10 | 4 |
/ | 除 | 5/2 | 2.5 | 4 |
+ | 加 | 5+2 | 7 | 5 |
- | 减 | 5-2 | 3 | 5 |
关系运算符
比较向量中的元素,返回TRUE或者FALSE。
运算符 | 描述 | 示例 | 结果 |
> | 依次判断两个向量中的元素是否满足大于关系 | c(1,2,3)>c(0,2,4) | TRUE FALSE FALSE |
< | 依次判断两个向量中的元素是否满足小于关系 | c(1,2,3)<c(0,2,4) | FALSE FALSE TRUE |
== | 依次判断两个向量中的元素是否满足等于关系 | c(1,2,3)==c(0,2,4) | FALSE TRUE FALSE |
!= | 依次判断两个向量中的元素是否满足不等于关系 | c(1,2,3)!=c(0,2,4) | TRUE FALSE TRUE |
>= | 依次判断两个向量中的元素是否满足大于等于关系 | c(1,2,3)>=c(0,2,4) | TRUE TRUE FALSE |
<= | 依次判断两个向量中的元素是否满足小于等于关系 | c(1,2,3)<=c(0,2,4) | FALSE TRUE TRUE |
逻辑运算符
逻辑运算,非0即TRUE。
&&和||在4.2.1之后不再适用于向量。
运算符 | 描述 | 示例 | 结果 |
& | 与,都TRUE即TRUE | c(0,2)&c(1,-1) | FALSE TRUE |
| | 或,有TRUE则TRUE | c(0,2)|c(1,-1) | TRUE TRUE |
! | 非,取反 | !c(0,2) | TRUE FALSE |
&& | 与,只对向量第一个元素运算 | c(0,2)&&c(1,-1) | FALSE |
|| | 或,只对向量第一个元素运算 | c(0,2)||c(1,-1) | TRUE |
赋值运算符
除=、<-、->外,还有<<-与->>,后两个可以在函数里对全局变量赋值,但容易撞变量名,慎用。
其它运算符
> v=c(1:10) # a:b 创建一个向量,[a,a+1,...,b-1,b]
> v
[1] 1 2 3 4 5 6 7 8 9 10
> 6 %in% v # %in% 判断元素是否在向量内
[1] TRUE
> 0 %in% v
[1] FALSE
判断语句
if语句
用法
if(表达式){
若表达式为TRUE,则要执行的语句
}
实例
if(3>2){
print("3>2")
}
# 输出"3>2"
if...else语句
用法
if(表达式){
...
}else{
若表达式为FALSE,则要执行的语句
}
if(表达式1){ #多个条件判断的if...else用法
...
}else #若表达式1位FALSE,则继续下面的判断
if(表达式2){
...
}else #前面表达式都为FALSE,则继续下面的判断
if(表达式3){
...
}
实例
GPA=4
if(GPA>4.5){ #不满足,跳到else
print("great")
}else
if(GPA>3.8){ #满足,执行语句
print("good") #输出good
}else #后面都不用判断
if(GPA>3){
print("just so so")
}else{
print("not well")
}
switch语句
用法
#第一个参数是整数的情况
switch(值,值为1对应的结果,值为2对应的结果,...,值为n对应的结果)
#第一个参数是字符串的情况
switch(字符串,变量名1=结果1,变量名2=结果2,...,变量名n=结果n)
实例
> switch(3,"a","b","c","d") #返回第三个
[1] "c"
> switch("c",a=1,b=2,c=3,c=4) #返回变量c对应的值,若有重复返回第一个
[1] 3
循环语句
循环类型
repeat循环
用法
repeat{
...
if(要退出循环的条件){
break
}
}
实例
cnt=1
repeat{
print(cnt)
cnt=cnt+1
if(cnt>5){
break
}
}
#输出五行,每行一个整数,从1到5
while循环
用法
while(循环条件){
...
}
实例
cnt=1
while(cnt<=5){
print(cnt)
cnt=cnt+1
}
#输出五行,每行一个整数,从1到5
for循环
用法
for(循环变量 in 集合){
循环体
}
实例
for(i in 1:5){
print(i)
}
#输出五行,每行一个整数,从1到5
循环控制
break
功能
退出当前最内层循环。
实例
for(i in 1:5){
if(i>3) break #一旦i>3就结束循环
print(i)
}
#输出三行,每行一个整数,从1到3
next
功能
跳过当次循环。
实例
for(i in 1:5){
if(i%%2==1) next #如果i是奇数就跳过
print(i)
}
#只输出2和4
函数
函数定义
形式
函数名<-function(参数){
函数体
return(返回值)
}
实例
gcd=function(x,y){ #输出x与y的最大公约数的函数
if(y) return(gcd(y,x%%y))
else return(x)
}
qsm=function(a,b){ #输出a的b次幂的函数
c=1
while(b){
if(b%%2==1) c=c*a
a=a*a
b=b%/%2
}
return(c)
}
prime=function(x){ #判断x是否是质数的函数
if(x<2){
return(FALSE)
}
if(x<4){
return(TRUE)
}
for(i in 2:floor(sqrt(x))){
if(x%%i==0){
return(FALSE)
}
}
return(TRUE)
}
函数调用
没有参数的函数
f=function(){ #函数中没有用到x
return(114514)
}
print(f())
#执行函数体,输出一个数字
带参数的函数
#以上一个版块的qsm函数为例,有两个参数a和b,输出a的b次幂
> qsm(3,5) #按顺序输入3,5,会默认a=3,b=5,输出3的5次幂
[1] 243
> qsm(b=5,a=3) #也可以带参数名调用函数,顺序任意
[1] 243
缺省值
可以在定义函数的时候就设置缺省值,就是在不填参数时的默认值。
qsm=function(a=2,b){ #缺省值,a=2
c=1
while(b){
if(b%%2==1) c=c*a
a=a*a
b=b%/%2
}
return(c)
}
print(qsm(,2)) #可以不填a的值,a默认就是2
#输出4
懒惰计算
函数中如果有不调用的参数,可以不填入。
f=function(x){ #有参数x,但函数中没有用到
return(114514)
}
print(f()) #调用时不填入参数x的值也可以运行
向量vector
相当于C语言中的一维数组。
向量创建
> a=c(1,2) #函数c()创建一个向量
> b=c(10,20,30,40)
向量加减
> a+b #只有较长向量是较短向量长度的整数倍时,才能相加减
[1] 11 22 31 42 #较短向量重复若干次,元素逐个相加
向量元素取出
> a[1] #取出向量中的单个元素
[1] 1 #注意!与其它语言不同,R的下标从1开始
> b[2:4] #取出向量中连续的元素
[1] 20 30 40
> b[c(1,3,4)] #也可以用向量取出向量的多个元素
[1] 10 30 40 #取出了第1,3,4项
向量排序
函数 | 描述 |
sort() | 排序 |
rev() | 翻转 |
order() | 位次 |
> a=c(1,1,4,5,1,4)
> sort(a) #函数sort()可以对向量排序,默认从小到大
[1] 1 1 1 4 4 5
> a
[1] 1 1 4 5 1 4 #但是sort不改变原来的向量
> rev(a) #rev()翻转向量
[1] 4 1 5 4 1 1
> a #同样不改变原向量
[1] 1 1 4 5 1 4
> order(a) #order()返回一个向量,表示每一个元素排序过后的位置,相同元素按照原顺序
[1] 1 2 5 3 6 4
> a[order(a)] #利用order()的排序方法
[1] 1 1 1 4 4 5
向量统计
函数 | 描述 |
sum | 求和 |
mean | 平均值 |
var | 方差 |
sd | 标准差 |
min | 最小值 |
max | 最大值 |
range | 取值范围 |
> a=c(1,1,4,5,1,4)
> sum(a) #和
[1] 16
> mean(a) #平均值
[1] 2.666667
> var(a) #方差
[1] 3.466667
> sd(a) #标准差
[1] 1.861899
> min(a) #最小值
[1] 1
> max(a) #最大值
[1] 5
> range(a) #范围,返回一个二维向量,最小值和最大值
[1] 1 5
其它向量操作
函数 | 描述 |
which | 筛选 |
all | 判断是否全真 |
any | 判断是否有真 |
> a=c(1,1,4,5,1,4)
> which(a>2 & a<5) #which加上对向量元素的筛选条件
[1] 3 6 #返回向量中满足条件的元素的下标
> a[c(which(a>2 & a<5))] #这样操作可以返回满足条件的元素
[1] 4 4
> a>2 #向量和元素进行逻辑运算,返回一个逻辑向量
[1] FALSE FALSE TRUE TRUE FALSE TRUE
> all(a>2) #是否全是TRUE
[1] FALSE
> any(a<5) #是否存在TRUE
[1] TRUE
字符串string
字符串创建
用单引号或者双引号创建。
单引号内可以有双引号,不能有不带转义字符的单引号。
双引号同理。
> 'abc'
[1] "abc"
> "123\'abc"
[1] "123'abc"
字符串函数
函数 | 描述 | ||||||||||||
toupper | 转大写 | ||||||||||||
tolower | 转小写 | ||||||||||||
nchar | 统计字符 | ||||||||||||
substr(s,begin,end) | 截取字符串s中从begin到end的子串 | ||||||||||||
substring(s,begin[,end]) | 截取字符串s中从begin到end的子串,若没有end参数,默认截取到末尾 | ||||||||||||
as.numeric | 将字符串转换为数字 | ||||||||||||
as.character | 将数字转换为字符串 | ||||||||||||
strsplit(s,c) | 用c分割s | ||||||||||||
gsub(a,b,s) | 将s中所有a换成b | ||||||||||||
paste | 连接对象,并以字符串形式输出
| ||||||||||||
format | 格式化字符串或数字,以字符串形式输出
|
> toupper("123Abc")
[1] "123ABC"
> tolower("123Abc")
[1] "123abc"
> nchar("中文") #统计有几个字符
[1] 2
> nchar("中文",type="byte") #统计占几位,一个汉字占3位
[1] 6
> substr("123Abc",2,4)
[1] "23A"
> substring("123Abc",4)
[1] "Abc"
> as.numeric("114514")
[1] 114514
> as.character(114514)
[1] "114514"
> strsplit("11:45:14",":") #根据冒号分隔字符串,返回一个list,list包含一个向量
[[1]]
[1] "11" "45" "14"
> gsub(":"," ","11:45:14") #将:替换成空格
[1] "11 45 14"
> paste("123","abc",sep=",") #对象是字符串,以sep为分隔符直接连接
[1] "123,abc"
> paste(1:3,11:15,sep=" ",collapse=",") #对象是向量,先以sep连接字符串,再以collapse分隔
[1] "1 11,2 12,3 13,1 14,2 15" #长度不一致,较短的会循环
> format(1.23,digits=2)
[1] "1.2"
> format(1.23,digits=9)
[1] "1.23"
> format(1.23,scientific=TRUE)
[1] "1.23e+00"
> format(1.23,width=9)
[1] " 1.23"
> format("123456789",width=13,justify='c')
[1] " 123456789 "
> format(123456789,width=13,justify='c') #如果对象是数字,fustufy无效,依然右对齐
[1] " 123456789"
矩阵matrix
类似于其它语言中的二维数组,支持线性代数中的矩阵运算。
笔者在写这一部分,还没有系统学习线性代数,可能会有所疏漏,请读者见谅。
矩阵创建
格式
matrix(data=NA,nrow=1,ncol=1,byrow=FALSE,dimnames=NULL)
参数 | 意义 |
data | 一个列表,矩阵中所有元素 |
nrow | 矩阵行数,默认为1 |
ncol | 矩阵列数,默认为1 |
byrow | 如果为TRUE,表示数据按列行填。默认按列填 |
dimnames | 一个包含两个向量的列表,每个向量表示更改后行/列的名称 |
实例
> matrix(1:6,3,2) #3行2列的矩阵,元素是1到6。可以看出,默认是按列填
[,1] [,2]
[1,] 1 4
[2,] 2 5
[3,] 3 6
> matrix(1:6,3,2,byrow=TRUE) #设置byrow参数之后按行填
[,1] [,2]
[1,] 1 2
[2,] 3 4
[3,] 5 6
> matrix(1:6,3,2,dimnames=list(c("第一行","第二行","第三行"),c("第一列","第二列")))
第一列 第二列
第一行 1 4
第二行 2 5
第三行 3 6 #修改每行每列的名称
其它创建方法
> matrix(1,3,4) #data可以只填一个值,创建出的矩阵所有元素都是这个值
[,1] [,2] [,3] [,4]
[1,] 1 1 1 1
[2,] 1 1 1 1
[3,] 1 1 1 1
矩阵切片
> t=matrix(1:12,4,3) #创建一个3行4列的矩阵,元素是1到12
> t[3,] #提取第3行的元素
[1] 3 7 11
> t[,2] #提取第2列的元素
[1] 5 6 7 8
> t[3,2] #提取第3行第2列的元素
[1] 7
> t[2,-3] #提取第2行除第3列之外的元素
[1] 2 6
> t[-1,1] #提取第1列除第1列之外的元素
[1] 2 3 4
> t[-2,-2] #提取除第2行和第2列之外的元素
[,1] [,2]
[1,] 1 9
[2,] 3 11
[3,] 4 12
矩阵运算
总体来说,R语言中矩阵运算的规则符合数学中的矩阵运算。
矩阵加减
行数、列数、元素类型相同的矩阵可以相加减。
> A=matrix(1:12,4,3) #4行3列,从1到12的矩阵
> B=matrix(13:24,4,3) #4行3列,从13到24的矩阵
> A+B #矩阵相加
[,1] [,2] [,3]
[1,] 14 22 30
[2,] 16 24 32
[3,] 18 26 34
[4,] 20 28 36
> A-B #矩阵相减
[,1] [,2] [,3]
[1,] -12 -12 -12
[2,] -12 -12 -12
[3,] -12 -12 -12
[4,] -12 -12 -12
矩阵数乘
矩阵乘以一个常数,生成一个新矩阵,每个元素为原矩阵该位置的数乘常数。
> A=matrix(1:3,1,3)
> A*3 #乘法
[,1] [,2] [,3]
[1,] 3 6 9
> A/2 #除法同理
[,1] [,2] [,3]
[1,] 0.5 1 1.5
矩阵乘除
当且仅当第一个矩阵的列数等于第二个矩阵的行数时,这两个矩阵可以相乘。
在R语言中,矩阵乘法的符号是%*%。
矩阵乘法不满足交换律。
> A=matrix(1:3,nrow=1,3) #矩阵A1行3列
> A
[,1] [,2] [,3]
[1,] 1 2 3
> B=matrix(1:3,3,1) #矩阵B3行1列
> B
[,1]
[1,] 1
[2,] 2
[3,] 3
> A%*%B
[,1]
[1,] 14
矩阵其它操作
矩阵转置
> m=matrix(1:6,3,2)
> t(m) # t()可以输出矩阵的转置矩阵
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6