数据科学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 <- 0while(count < 5) {print(count)count <- count + 1}[1] 0[1] 1[1] 2[1] 3[1] 4
4.repeat,执行无限循环
x0<-1tol <- 1e-8repeat {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.9131906sd(x = mydata)[] 0.9131906sd(x = mydata, na.rm = FALSE)[] 0.9131906sd(na.rm = FALSE, x = mydata)[] 0.9131906sd(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,但只使用了一个参数af(2)[1] 4f <- function(a, b) {print(a)print(b)}f(45)[1] 45Error 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)[] 0unclass(as.Date("1970-01-02"))[] 1unclass(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-yError in x - y : 二进列运算符中有非数值参数此外: Warning message:不可兼容的方法("-.Date", "-.POSIXt")和"-"x <- as.POSIXlt(x)x-yTime difference of 356.3 days
日期和时间能计算不易理清的时间,例如闰年、闰秒、夏令时以及时区。
x <- as.Date("2012-03-01")y <- as.Date("2012-02-28")x-yTime difference of 2 daysx <- as.POSIXct("2012-10-25 01:00:00")y <- as.POSIXct("2012-10-25 06:00:00", tz = "GMT")y-xTime difference of 13 hours
对日期和时间都通用的泛型函数:
・weekdays() 函数:给定的日期或时间是星期几 ・months() 函数:给定的日期或时间是在几月 ・quarters() 函数:给定的日期或时间处于第几季度
