数据科学02 | R语言程序设计-数据结构与函数
往期回顾:
1. 准备R
➢安装R和Rstudio
➢设置工作目录
查看工作目录:
getwd()
["/Users/UserName" ]
更改工作目录:
setwd("~/Documents")
dir() #查看当前目录文件
➢在R的文本编辑器编写代码
代码标准
・通常使用文本文件/文本编辑器・缩进代码
仅靠缩进就能理解程序是按何种顺序运行的。
・限制代码的宽度
缩进可能会使代码无限制向右排,需要限制代码的宽度,一般将文本的列数限制在大约80列。
・限制函数的长度
有利于函数的易读性和调试。
2. 数据类型和结构
在R中,对象(object)是指可以赋值给变量的任何事物,包括常量、数据结构、函数,甚至图形。
➢基本数据类型
・字符型character ・数值型numeric ・整数型integer ・逻辑型logic ・复数型complex
➢数据结构
・向量vector
存储数值型、字符型或逻辑型数据的一维数组。
・矩阵matrix
二维数组,每个元素都拥有相同的类型(数值型、字符型或逻辑型)。
・数组array
与矩阵类似,但是维度可以大于2。
・数据框dataframe
用来存储表格数据,每一列数据都可以是不同的类型。
・列表list
可以是几个向量、矩阵、数据框,甚至其他列表的集合。
・因子factor
类别变量和有序类别变量,可以分类数据。
3. 控制结构
1.if, else,测试逻辑条件
if(<condition1>){
} else {
}
if(<condition1>){
} else if(<condition2>){
} else {
}
if(<condition1>){
}
if(<condition2>){
}
2.for,执行固定次数的循环
x <- c("a", "b", "c", "d")
for (i in 1:4) {
print(x[i])
}
["a" ]
["b" ]
["c" ]
["d" ]
for (i in seq_along(x)) {
print(x[i])
}
["a" ]
["b" ]
["c" ]
["d" ]
for (letter in x) {
print(letter)
}
["a" ]
["b" ]
["c" ]
["d" ]
for (i in 1:4) print(x[i])
["a" ]
["b" ]
["c" ]
["d" ]
输出结果都一样。
x <- matrix(1:6,2,3)
for(i in seq_len(nrow(x))) {
for(j in seq_len(ncol(x))) {
print(x[i, j])
}
}
[1 ]
[3 ]
[5 ]
[2 ]
[4 ]
[6 ]
for可以嵌套,但一般少于3层,否则不易解释。
3.while,条件成立时执行循环
count <- 0
while(count < 5) {
print(count)
count <- count + 1
}
[1] 0
[1] 1
[1] 2
[1] 3
[1] 4
4.repeat,执行无限循环
x0<-1
tol <- 1e-8
repeat {
x1 <- computeEstimate()
if(abs(x1 - x0) < tol) {
break
}else{
x0<-x1
}
}
repeat循环易陷入死循环,需要注意!(在数据处理中不常用)
5.break,终止并跳出repeat循环
6.next,跳过循环的当前迭代
for(i in 1:100) {
if(i <= 20) { ##跳过前20次迭代
next
}
## Do something
}
7.return,退出并返回值
4. 函数function
R语言用 function() 创建函数。
f <- function(<arguments>) {
## Do something
}
在R里函数可以作为对象处理,可以将函数作为参数传递给其它函数,也可以嵌套。
➢参数
・形式参数是函数定义包含的参数。・缺省值:参数的默认值,调用函数并不需要指定每个参数的值。
➢参数匹配规则
函数参数可以根据位置或者名字来匹配——编写和调用函数的关键。
例:函数sd() ,可以计算数据的标准差
formals(sd)
$x
$na.rm
[1] FALSE
formals()函数返回函数所有形式参数组成的列表。
sd() 读入名为 x 的向量
参数na.rm判断是否移除缺失值NA,na.rm缺省值是FALSE,即默认缺失值不参与计算
mydata <- rnorm(100)
sd(mydata)
[0.9131906 ]
sd(x = mydata)
[0.9131906 ]
sd(x = mydata, na.rm = FALSE)
[0.9131906 ]
sd(na.rm = FALSE, x = mydata)
[0.9131906 ]
sd(na.rm = FALSE, mydata)
[0.9131906 ]
不推荐改变参数的排列顺序,容易引起误解。
对参数极多的函数混合使用位置匹配和命名。
例:lm()函数,把数据拟合到线性模型
args(lm)
function (formula, data, subset, weights, na.action, method = "qr",
model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE,
contrasts = NULL, offset, ...)
NULL
args()可以查看函数的所有参数及其对应的缺省值。
前五个参数没有缺省值,使用者必须指定它们的值
参数 method、model 和 x 都有缺省值
比较两个等价的函数调用方式:
lm(data = mydata, y ~ x, model = FALSE, 1:100)
lm(y ~ x, mydata, 1:100, model = FALSE)
方式一:
将data参数按照命名来匹配,移出参数列表
y ~ x 因为没有特定的名字,将赋值给第一个尚未配对的参数,即formula
model 参数按命名匹配,移出参数列表
1:100 将会被赋值给下一个未匹配的参数subset
用这种方式调用 lm() 会让人觉得混乱。通常使用方式二调用lm()。
R中的参数匹配顺序:
首先检查完全匹配,指定一个参数名,它会检查是否有参数跟该命名完全匹配
如果找不到完全匹配的参数,它将查找是否有模糊匹配的参数
如果都没有,则再进行位置匹配
➢惰性求值 (Lazy Evaluation)仅在函数参数被调用时进行求值。
f <- function(a, b) {
a^2
} #函数定义两个参数a和b,但只使用了一个参数a
f(2)
[1] 4
f <- function(a, b) {
print(a)
print(b)
}
f(45)
[1] 45
Error in print(b) : 缺少参数"b",也没有缺省值
#没有给b赋值,参数b也没有缺省值,错误是在输出45之后出现的
➢特殊参数:...参数
可以将原函数的一些参数迅速传递给另一个函数。
运用:
・拓展一个函数,更改其中一小部分或更改一些缺省值
例:定义myplot()函数,拓展plot()函数
myplot <- function(x, y, type = "l", ...) {
plot(x, y, type = type, ...)
}
1.重复使用原 plot() 函数使用的参数,比如 x 和 y;2.type参数的缺省值可以修改;3.plot() 函数的其它参数可以用 ... 来传递,不需要在扩展函数中重新输入或者创建。
・可以用在泛型函数中
泛型函数 (generic function):函数自身不做任何运算,根据数据类型使用合适的方法,这种类型函数的设置常常要用到...参数,使得附加参数可以传递给方法。
・当传递到函数的参数数量不能事先确定的时候
例:paste() 函数paste() 函数将一组字符串连起来生成新的字符向量,无法预先注明有多少参数需要连接。
args(paste)
function (..., sep = " ", collapse = NULL)
1. ...参数 ,各种字符向量对象;2. sep参数,缺省值为空格,用分隔符连接字符;3. sep参数和collapse参数在 ... 参数之后。
任何出现在 ... 之后的参数列表需要明确地给出名称,而且不能进行模糊匹配!
paste("a", "b", sep = ":")
["a:b" ]
paste("a", "b", se = ":")
["a b :" ]
paste() 函数中模糊匹配无效,R 并不知道需要将信息传递给 ... 参数,还是其他参数。
5. 日期和时间
R 用了一种特殊的数据类型来表示日期和时间。
日期用 Date 类表示
时间由POSIXct类和POSIXlt类表示
日期不包括时间,只表示某年某月某日,日期以距离1970年1月1日的天数来存储数据
时间以距离1970年1月1日的秒数存储数据
as.Date() 函数将字符串格式的日期转换成Date类型。
x <- as.Date("1970-01-01")
x
["1970-01-01" ]
unclass(x)
[0 ]
unclass(as.Date("1970-01-02"))
[1 ]
unclass(as.Date("1969-12-31"))
[-1 ]
POSIX 规定了特定类型的计算机处理事件和数据表示的方法。POSIX 标准里有一个标准族来规定如何表示日期和时间。
POSIXct 类的时间用非常大的整数表示,常作为数据框储存的时间数据的类。
POSIXlt类实际上把时间当作列表来存储
Sys.time() 函数返回系统当前的时间。
x <- Sys.time()
x
[1] "2020-01-10 01:33:02 CST"
#以年月日的格式输出,紧接着是时分秒的格式,接着是时区
class(x)
[1] "POSIXct" "POSIXt"
#时间为POSIXct类
unclass(x)
[1] 1578591183
#对POSIXct类的对象x去除类,得到了非常大的整数,是自1970年1月1日至今的秒数
as.POSIXlt() 或 as.POSIXct() 函数可以在 POSIXlt 类和 POSIXct 类之间转换。
x <- Sys.time()
x
[1] "2020-01-10 01:20:26 CST"
p <- as.POSIXlt(x) #转换成POSIXlt类
names(unclass(p))
[1] "sec" "min" "hour" "mday" "mon" "year" "wday" "yday" "isdst"
[10]"zone" "gmtoff"
#POSIXlt实际上是一个列表,去除类之后查看元素名
p$sec #查看元素
[1] 26.97712
strptime() 函数可以把字符串格式的日期转换成日期或时间对象。
datestring <- c("January 10, 2012 10:40", "December 9, 2011 9:10")
x <- strptime(datestring, "%B %d, %Y %H:%M")
x
[1] "2012-01-10 10:40:00 CST" "2011-12-09 09:10:00 CST"
class(x)
[1] "POSIXlt" "POSIXt"
对日期或时间类的数据进行运算可以很方便。不能把不同的类混淆在一起计算。
x <- as.Date("2012-01-01")
y <- strptime("9 Jan 2011 11:34:21", "%d %b %Y %H:%M:%S")
x-y
Error in x - y : 二进列运算符中有非数值参数
此外: Warning message:
不可兼容的方法("-.Date", "-.POSIXt")和"-"
x <- as.POSIXlt(x)
x-y
Time difference of 356.3 days
日期和时间能计算不易理清的时间,例如闰年、闰秒、夏令时以及时区。
x <- as.Date("2012-03-01")
y <- as.Date("2012-02-28")
x-y
Time difference of 2 days
x <- as.POSIXct("2012-10-25 01:00:00")
y <- as.POSIXct("2012-10-25 06:00:00", tz = "GMT")
y-x
Time difference of 13 hours
对日期和时间都通用的泛型函数:
・weekdays() 函数:给定的日期或时间是星期几 ・months() 函数:给定的日期或时间是在几月 ・quarters() 函数:给定的日期或时间处于第几季度