R是用于统计分析、绘图的语言和操作环境。R是属于GNU系统的一个自由、免费、源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具。在学习R数据科学之前,我们首先要对R语言的基础语法有一个良好的了解,方便我们理解以后的数据科学算法。本次语法精讲分三次讲完,每次负责讲解其中一部分!本次的R语言语法精讲(一)主要介绍了 R语言的数据结构,R语言的运算以及R语言的编程结构。学完本文后,您将可以具备初步的R语言编程技巧,并能编写大部分程序以及算法。
本文引用:
《R语言实战--第2版》---------Robert I.Kabacoff 《统计计算与模拟》课程课件-------深圳大学林炳清老师
本文内容:
R拥有许多用于存储数据的对象类型,包括标量、向量、矩阵、数组、数据框和列表。它们在存储数据的类型、创建方式、结构复杂度,以及用于定位和访问其中个别元素的标记等方面均有所不同。
我们可以把vector想象:vector是一串糖葫芦,把山楂都串在一起。vector包含的是一串数据,要求这一串的数据类型是一样的。在R中,常见的数据类型有3种:
(1) 创建向量:
我们可以使用 c() 创造一个vector, c是英文单词cancatenate的缩写,意思是连结,连锁。所以c()可以把括号里的数字或者其他的数据类型的元素串成一个vector. 例如:(<-代表R语言中的赋值符号,绝大多数也可以用=代替;相当于python的“=”)
a
这里,a是数值型向量,b是字符型向量,而c是逻辑型向量。 注意,单个向量中的数据必须拥有相同的类型或模式(数值型、字符型或逻辑型) 。同一向量中无法混杂不同模式的数据。
(2) 向量vector的索引
vector索引指的是R会给vector的每个元素一个位置坐标。R的位置坐标从1开始,从左到右依次给予vector的每个元素。例如:
a <- c("k", "j", "h", "a", "c", "m")
a[3]
a[c(1, 3, 5)]
a[2:6]
此外,我们还可以很方便的输出vector除去某些位置的对应元素后的vector, 例如:
x <- c(1, 3, 6, 4)
x[-c(3, 4)]
我们还可以用names()函数给vector的每一个元素赋予一个名字,例如:
score <- c(98, 100, 60, 20) # score 表示一次考试的成绩
names(score) <- c("Lin", "Wang", "Chen", "Sun") # score 每一个成绩对应的人名
score
score[2]
score["Wang"] # 可以通过vector元素的名字得到第二个同学的成绩
(3) 产生常用vector的方法::, seq(), rep()
1:50
6:2
-5:-10
seq(from = 3, to = 10)
seq(from = 1, to = 10, by = 2) # seq()可以自定义递增或者递减的步长
rep(10, 5) # 产生一个vector, 该vector包含5个10
rep(c(2:4), 3) # 产生一个vector, 该vecotr包含3个 `c(2:4)`
rep("I Love R!", 3)
矩阵是一个二维数组,只是每个元素都拥有相同的模式(数值型、字符型或逻辑型)。可通过函数matrix()创建矩阵。一般使用格式为:
myymatrix <- matrix(vector, nrow=number_of_rows, ncol=number_of_columns,byrow=logical_value, dimnames=list(char_vector_rownames, char_vector_colnames))
其中vector包含了矩阵的元素,nrow和ncol用以指定行和列的维数,dimnames包含了可选的、以字符型向量表示的行名和列名。选项byrow则表明矩阵应当按行填充(byrow=TRUE)还是按列填充(byrow=FALSE) ,默认情况下按列填充。代码清单2-1中的代码演示了matrix函数的用法。
(1) 创建矩阵
我们首先创建了一个5×4的矩阵, 接着创建了一个2×2的含列名标签的矩阵, 并按行进行填 充,最后创建了一个2×2的矩阵并按列进行了填充。
y <- matrix(1:20, nrow=5, ncol=4) # 创建一个5×4的矩阵
y
cells <- c(1,26,24,68)
rnames <- c("R1", "R2")
cnames <- c("C1", "C2")
mymatrix <- matrix(cells, nrow=2, ncol=2, byrow=TRUE, # 按行填充的2×2矩阵
dimnames=list(rnames, cnames))
mymatrix
mymatrix <- matrix(cells, nrow=2, ncol=2, byrow=FALSE, # 按列填充的2×2矩阵
dimnames=list(rnames, cnames))
mymatrix
(2) 矩阵的索引
x <- matrix(1:10, nrow=2)
x
x[2,]
x[,2]
x[1,4]
x[1, c(4,5)]
(3) 删除矩阵的某些行,列
x <- c(3, 1, 5, 2, 3, 8, 5, 8, 9, 4, 2, 3)
x <- matrix(x, nrow = 3, ncol = 4, byrow = T)
x
y <- x[-2, ]
y
z <- x[, -c(2:3)]
z
(4) 添加一行或一列:cbind或者rbind合并两个矩阵
y <- cbind(x, c(3, 4, 5)) # 添加一列c(3,4,5)到x矩阵最后
y
z <- rbind(c(7, 8, 9, 10), x) # 添加X到c(7,8,9,10)的行上
z
(5) 给matrix的行和列加上名字
rownames()和colnames()给matrix的行和列添加或者修改名字:
x <- c(3, 1, 5, 2, 3, 8, 5, 8, 9, 4, 2, 3)
x <- matrix(x, nrow = 3, ncol = 4, byrow = T)
x
rownames(x) <- c("a", "b", "c") # 添加行名
colnames(x) <- c("w", "x", "y", "z") # 添加列名
x
数组(array)与矩阵类似,但是维度可以大于2。数组可通过array函数创建,形式如下:
myarray <- array(vector, dimensions, dimnames)
其中vector包含了数组中的数据, dimensions是一个数值型向量, 给出了各个维度下标的最大值,而dimnames是可选的、各维度名称标签的列表。
(1) 数组的创建
dim1 <- c("A1", "A2")
dim2 <- c("B1", "B2", "B3")
dim3 <- c("C1", "C2", "C3", "C4")
z <- array(1:24, c(2, 3, 4), dimnames=list(dim1, dim2, dim3))
z
如你所见,数组是矩阵的一个自然推广。它们在编写新的统计方法时可能很有用。像矩阵一样,数组中的数据也只能拥有一种模式。
(2) 数组的索引
从数组中选取元素的方式与矩阵相同。
z[1,2,3]
data frame可以看成是一个excel表格。dataframe是数据分析中非常常用的一种储存数据的方式。dataframe也是一个2维的表格,和matrix一样不一样的地方是data frame的每一列的数据类型可以不一样,但是要求每一列内部数据类型是一样的。数据框可通过函数data.frame()创建:
mydata <- data.frame(col1, col2, col3,...)
其中的列向量col1、col2、col3等可为任何类型(如字符型、数值型或逻辑型) 。每一列的名称可由函数names指定。
(1) 数据框的创建
patientID <- c(1, 2, 3, 4)
age <- c(25, 34, 28, 52)
diabetes <- c("Type1", "Type2", "Type1", "Type1")
status <- c("Poor", "Improved", "Excellent", "Poor")
patientdata <- data.frame(patientID, age, diabetes, status)
patientdata
每一列数据的模式必须唯一,不过你却可以将多个模式的不同列放到一起组成数据框。由于数据框与分析人员通常设想的数据集的形态较为接近,我们在讨论数据框时将交替使用术语 列和 变量。
如果想指定index,那么:
patientdata <- data.frame(patientID, age, diabetes,
status, row.names=patientID)
patientdata
(2) 数据框的索引
patientdata <- data.frame(patientID, age, diabetes, status)
patientdata
patientdata[1:2]
patientdata[c("diabetes", "status")]
patientdata$age # 表示patientdata数据框中的变量age
(3) 粘结两个dataframe:用cbind和’rbind’结合两个data frame.
x <- data.frame(Name = c("Jone","Lily"), Grade = c(80,90))
x
x <- cbind(x, data.frame(Asia = c(F, F)) )
x
x <- rbind(x, data.frame(Name = "Wang", Grade = 100, Asia = T))
x
如你所见,变量可归结为名义型、有序型或连续型变量。名义型变量是没有顺序之分的类别变量。糖尿病类型Diabetes(Type1、Type2)是名义型变量的一例。即使在数据中Type1编码为1而Type2编码为2,这也并不意味着二者是有序的。有序型变量表示一种顺序关系,而非数量关系。病情Status(poor、improved、excellent)是顺序型变量的一个上佳示例。我们明白,病情为poor(较差)病人的状态不如improved(病情好转)的病人,但并不知道相差多少。连续型变量可以呈现为某个范围内的任意值,并同时表示了顺序和数量。年龄Age就是一个连续型变量,它能够表示像14.5或22.8这样的值以及其间的其他任意值。很清楚,15岁的人比14岁的人年长一岁。
类别(名义型)变量和有序类别(有序型)变量在R中称为因子(factor) 。因子在R中非常重要,因为它决定了数据的分析方式以及如何进行视觉呈现。
函数factor()以一个整数向量的形式存储类别值,整数的取值范围是[1...k](其中k是名义型变量中唯一值的个数),同时一个由字符串(原始值)组成的内部向量将映射到这些整数上。要表示有序型变量,需要为函数factor()指定参数ordered=TRUE。通过指定levels选项来覆盖默认排序。
(1) 因子类型的使用
patientID <- c(1, 2, 3, 4)
age <- c(25, 34, 28, 52)
diabetes <- c("Type1", "Type2", "Type1", "Type1")
status <- c("Poor", "Improved", "Excellent", "Poor")
diabetes <- factor(diabetes)
status <- factor(status, order=TRUE) # 有序型变量
patientdata <- data.frame(patientID, age, diabetes, status)
str(patientdata)
summary(patientdata)
列表(list)是R的数据类型中最为复杂的一种。一般来说,列表就是一些对象(或成分,component)的有序集合。列表允许你整合若干(可能无关的)对象到单个对象名下。例如,某个列表中可能是若干向量、矩阵、数据框,甚至其他列表的组合。
可以使用函数list()创建列表:
mylist <- list(object1, object2, ...)
其中的对象可以是目前为止讲到的任何结构。
你还可以为列表中的对象命名:
mylist <- list(name1=object1, name2=object2, ...)
(1) 列表的创建
本例创建了一个列表,其中有四个成分:一个字符串、一个数值型向量、一个矩阵及一个字符型向量。可以组合任意多的对象,并将它们保存为一个列表。
g <- "My First List"
h <- c(25, 26, 18, 39)
j <- matrix(1:10, nrow=5)
k <- c("one", "two", "three")
mylist <- list(title=g, ages=h, j, k)
mylist
(2) 列表的索引
可以通过在双重方括号中指明代表某个成分的数字或名称来访问列表中的元素。
mylist[[2]]
mylist[["ages"]]
R数字的四则运算+,-,*,/和算数中的四则运算时一致的:
2 + 3
2 - 3
2 * 3
2 / 3
我们需要注意R的vector和matrix的运算。在R中,vector和matrix的+,-,*,/ 指的是相同位置元素之间的 +,-,*,/。
(1) 向量的四则运算法则:
x <- c(1, 2, 3)
y <- c(4, 5, 6)
x + y
x - y
x * y
x / y
(2) 矩阵的四则运算法则:
x <- matrix(1:6, nrow = 3, ncol = 2)
y <- matrix(3:8, nrow = 3, ncol = 2)
x+y
x-y
x*y
x/y
(3) 矩阵与矩阵的乘法:
矩阵相乘的函数是%*%,同样的,我们要求第1个矩阵的列数(column)和第2个矩阵的行数(row)相同 。
x <- matrix(1:6, nrow = 2, byrow = T)
y <- matrix(7:12, nrow = 3, byrow = T)
x %*% y
矩阵乘法中,需要注意,当矩阵和向量相乘时,把向量当成一个列数为1的矩阵即可。
x <- matrix(1:6, nrow = 2, byrow = T)
x %*% c(1, 2, 3)
(4) 矩阵的转置:t()
x <- matrix(1:6, nrow = 2)
t(x)
manager <- c(1, 2, 3, 4, 5)
date <- c("10/24/08", "10/28/08", "10/1/08", "10/12/08", "5/1/09")
country <- c("US", "US", "UK", "UK", "UK")
gender <- c("M", "F", "F", "M", "F")
age <- c(32, 45, 25, 39, 99)
q1 <- c(5, 3, 3, 3, 2)
q2 <- c(4, 5, 5, 3, 2)
q3 <- c(5, 2, 5, 4, 1)
leadership <- data.frame(manager, date, country, gender, age,
q1, q2, q3, stringsAsFactors=FALSE)
leadership
leadership$agecat[leadership$age > 75] <- "Elder"
leadership$agecat[leadership$age >= 55 &
leadership$age <= 75] <- "Middle Aged"
leadership$agecat[leadership$age < 55] <- "Young"
leadership
在探索数据的阶段,常常会先探索数据分布的一些统计量,如求和,均值,标准差,方差,中值,分位数等。对vector,R有函数可以直接得到这些统计量,sum()(求和), mean()(均值), sd()(标准差), var()(方差), median()(中值), quantile()(分位数)。
x <- 1:10
sum(x)
mean(x)
sd(x)
var(x)
median(x)
quantile(x)
对matrix, R有函数rowMeans(), colMeans()可以得到每一行或者每一列的平均值(注意:M要大写哦),而rowSums,colSums可以得到每一行或者每一列的和(注意:S要大写哦)
x <- matrix(1:6, 3, 2)
rowMeans(x)
colMeans(x)
rowSums(x)
colSums(x)
R的基本函数库里没有函数可以直接计算,方差,标准差等其他信息,我们可以用apply()函数。apply(X,MARGIN,FUN)的参数主要有3个,X通常是一个matrix, MARGIN通常的取值有两个,1或者2,1表示按照行计算,2表示按照列计算,FUN指的是一个函数。
x <- matrix(1:6, 3, 2)
apply(x, 1, sd) # 计算x每一行的标准差
apply(x, 2, quantile) # 计算x每一列的分位数
apply(x, 1, mean) # 计算x每一行的均值
函数length()可以输出vector的长度,dim()可以输出matrix的2个维度
x <- rep(2, 8)
length(x)
y <- matrix(1:10, 5, 2)
dim(y)
函数rnorm()可以产生服从正态分布的随机数
x <- rnorm(50) # 产生50个服从标准正态分布的随机数
x
hist(x, breaks = 10, cex.lab = 1.5, cex.axis = 1.5)
abline(v = 0, col = "red", lty = 2, lwd = 2)
y <- rnorm(50, mean = 50, sd = 0.2) # 产生50个服从均值是50,标准差是0.2的正态分布随机数
y
hist(y, cex.lab = 1.5, cex.axis = 1.5)
abline(v = 50, col = "red", lty = 2, lwd = 2)
有时候我们需要重复我们的计算或者实验,这时我们需要用到set.seed()函数固定一个产生随机数的种子。下面的形式可以保证我们每次运行产生一样的随机数
set.seed(123)
rnorm(5)
函数cor()可以计算两个vector的相关关系
x <- rnorm(100)
y <- x + rnorm(100, 0, 0.2)
cor(x, y)
plot(x, y, col = "blue", pch = 20, cex.lab = 1.5, cex.axis = 1.5)
函数summary()可以得到matrix或者data frame的每一列的基本信息,包括最大值,最小值,中间值,25%和75%分位数,均值。
x <- matrix(rnorm(100*3), 100, 3)
summary(x)
(1) 在R中,if-else语句的形式通常如下:
a <- 3
if (a == 4) {
x <- 2
y <- 3
} else {
x <- 3
y <- 4
}
x
y
需要根据不同条件执行不同代码时,使用函数if(), 在括号里写入判断的语句,在上面的例子中,我们根据a == 4是TRUE, 还是FALSE执行不同的语句。
如果a=4, 那么a == 4是TRUE, 执行if()后面大括号{ }内的代码;
如果a!=4, 那么a == 4是FALSE, 执行else后面大括号{ }内的代码。
(2) if()也可以单独使用,例如:
if (a == 4) {
x <- 2
y <- 3
}
(3) 多个if-else可以一起使用,例如:
if (a == 4) {
x <- 2
y <- 3
} else if (a == 5){
x <- 3
y <- 4
} else {
x <- 5
y <- 6
}
(4) if-else还可以有如下的使用方式:
# v = if(cond) expression1 else expression2 # v可能取expression1或者expression2的结果,这取决于cond是否为真。
x = 2
y = if(x==2) x else x+1
y
(1) For循环
# 我们如果要计算1到10的平均值
s <- 0
for (i in 1:10) {
s <- s + i
}
s / 10
(2) while循环(一)
s <- 0
i <- 1
while(i<=10) {
s <- s + i
i <- i + 1
}
s / 10
(3) while循环(二)
s <- 0
i <- 1
while(TRUE) {
s <- s + i
i <- i + 1
if(i > 10) break
}
s / 10
(4) repeat循环
s <- 0
i <- 1
repeat {
s <- s + i
i <- i + 1
if(i > 10) break
}
s / 10
在R中,函数可以通过如下形式定义:
# 自定义函数求一个向量中所有偶数的和
sumEvenNum = function(v){
even_num = v[(v %% 2)==0]
sum_even_num = sum(even_num)
return(sum_even_num)
}
x = 1:10
sumEvenNum(x)
赋值号(=或者<-)左边是自定义函数的函数名
赋值号右边是定义函数的函数function()
函数function()括号内是我们要传到自定义函数的参数
大括号内写函数的代码
最后使用函数return()返回结果
本次的R语言语法精讲(一)主要介绍了 R语言的数据结构,R语言的运算以及R语言的编程结构。学完本文后,您将可以具备初步的R语言编程技巧,并能编写大部分程序以及算法。