R语言学习笔记2
R语言教程-R数据类型与运算1
3. 常亮与变量
3.1 常量
R语言基本的数据类型有数值型, 逻辑型(TRUE, FALSE),文本(字符串)。 支持缺失值,有专门的复数类型。
数值型常量包括整型、单精度、双精度等,一般不需要区分。写法如123
, 123.45
, -123.45
, -0.012
, 1.23E2
, -1.2E-2
等。 为了表示123
是整型,可以写成123L
。
字符型常量用两个双撇号或两个单撇号包围,如"Li Ming"
或'Li Ming'
。 字符型支持中文,如"李明"
或'李明'
。 国内的中文编码主要有GBK编码和UTF-8编码, 有时会遇到编码错误造成乱码的问题,MS Windows下R程序一般用GBK编码,但是RStudio软件采用UTF-8编码。 在R软件内字符串一般用UTF-8编码保存。
逻辑型常量只有TRUE和FALSE。
缺失值用NA表示。统计计算中经常会遇到缺失值,表示记录丢失、因为错误而不能用、节假日没有数据等。 除了数值型,逻辑型和字符型也可以有缺失值, 而且字符型的空白值不会自动辨识为缺失值,需要自己规定。 R支持特殊的Inf值,这是实数型值,表示正无穷大,不算缺失值。
复数常量写法如2.2 + 3.5i
, 1i
等。
3.2 变量
程序语言中的变量用来保存输入的值或者计算得到的值。 在R中,变量可以保存所有的数据类型, 比如标量、向量、矩阵、数据框、函数等。
变量都有变量名,R变量名必须以字母、数字、下划线和句点组成, 变量名的第一个字符不能取为数字。 在中文环境下,汉字也可以作为变量名的合法字符使用。 变量名是区分大小写的, y
和Y
是两个不同的变量名。
赋值: <-
或=
,一般用第一种形式
R的变量没有固定的类型, 给已有变量赋值为新的类型, 该变量就变成新的类型, 但一般应避免这样的行为。 R是“动态类型”语言, 赋值实际上是“绑定”(binding), 即将一个变量名与一个存储地址联系在一起, 同一个存储地址可以有多个变量名与其联系。
3.3 R数据类型
R语言数据结构包括向量,矩阵和数据框,多维数组, 列表,对象等。数据中元素、行、列还可以用名字访问。 最基本的是向量类型。 向量类型数据的访问方式也是其他数据类型访问方式的基础。
4. 数值型向量及其运算
4.1 数值型向量
向量是将若干个基础类型相同的值存储在一起, 各个元素可以按序号访问。 如果将若干个数值存储在一起可以用序号访问, 就叫做一个数值型向量。
用c()
函数把多个元素或向量组合成一个向量。如
x <- c(1:3, 10:13) |
10:13这样的写法表示从10到13的整数组成的向量。
显示结果中,每行显示的行首会有方括号和数字序号, 代表该行显示的第一个向量元素的下标。
length(x)
可以求x的长度。numeric(10)
会生成元素为10个零的向量。
4.2 向量运算
标量和标量运算
单个数值称为标量
, R没有单独的标量类型, 标量实际是长度为1的向量。
用%/%
表示整除,用%%
表示求余。
向量与标量的运算
一个向量乘以一个标量, 就是线性代数中的数乘运算。
四则运算时如果有缺失值,缺失元素参加的运算相应结果元素仍缺失。
等长向量运算
等长向量的运算为对应元素两两运算。
两个等长向量的加、减运算就是线性代数中两个向量的加、减运算。
不等长向量的运算
两个不等长向量的四则运算, 如果其长度为倍数关系,规则是每次从头重复利用短的一个。 如
x1 <- c(10, 20) |
不仅是四则运算,R中有两个或多个向量按照元素一一对应参与某种运算或函数调用时, 如果向量长度不同,一般都采用这样的规则。
如果两个向量的长度不是倍数关系,会给出警告信息。如
c(1,2) + c(1,2,3) |
4.3 向量函数
向量化的函数
R中的函数一般都是向量化的: 在R中, 如果普通的一元函数以向量为自变量,一般会对每个元素计算。 这样的函数包括sqrt, log10, log, exp, sin, cos, tan等许多。 如
sqrt(c(1, 4, 6.25)) |
运行命令help.start()
,可查看这些基础的数学函数的列表。
如果自己编写的函数没有考虑向量化问题, 可以用Vectorize()
函数将其转换成向量化版本。
排序函数
sort(x)返回排序结果。 rev(x)返回把各元素排列次序反转后的结果。 order(x)返回排序用的下标。如
x <- c(33, 55, 11) |
统计函数
sum
(求和), mean
(求平均值), var
(求样本方差), sd
(求样本标准差), min
(求最小值), max
(求最大值), range
(求最小值和最大值)等函数称为统计函数, 把输入向量看作样本,计算样本统计量。 prod
求所有元素的乘积。
cumsum
和cumprod
计算累加和累乘积。如
cumsum(1:5) |
在命令行界面用“?函数名”的方法查询函数的帮助文档
生成规则序列的函数
seq函数是冒号运算符的推广。 比如,seq(5)等同于1:5。 seq(2,5)等同于2:5。 seq(11, 15, by=2)产生11,13,15。 seq(0, 2*pi, length.out=100)产生从0到的等间隔序列, 序列长度指定为100。
seq(to=5, from=2)仍等同于2:5。
rep()
函数用来产生重复数值。 为了产生一个初值为零的长度为n的向量, 用x <- rep(0, n)
。 rep(c(1,3), 2)
把第一个自变量重复两次, 结果相当于c(1,3,1,3)
。
rep(c(1,3), c(2,4))
则需要利用R的一般向量化规则, 把第一自变量的第一个元素1按照第二自变量中第一个元素2的次数重复, 把第一自变量中第二个元素3按照第二自变量中第二个元素4的次数重复, 结果相当于c(1,1,3,3,3,3)
。
如果希望重复完一个元素后再重复另一元素,用each=
选项, 比如rep(c(1,3), each=2)
结果相当于c(1,1,3,3)
。
复数向量
复数常数表示如3.5+2.4i
, 1i
。 用函数complex()
生成复数向量, 指定实部和虚部。 如complex(real = c(1,0,-1,0), imaginary = c(0,1,0,-1))
相当于c(1+0i, 1i, -1+0i, -1i)
。
练习
-
示1到100的整数的平方根和立方根(提示:立方根就是三分之一次方)。
-
设有10个人的小测验成绩为:
77,60,91,73,85,82,35,100,66,75- 把这10个成绩存入变量x;
- 从小到大排序;
- 计算
order(x)
,解释order(x)
结果中第3项代表的意义。 - 计算这些成绩的平均值、标准差、最小值、最大值、中位数。
-
生成区间上等间隔的100个格子点存入变量x中。
5. 逻辑型向量及其运算
5.1 逻辑型向量与比较运算
逻辑型是R的基本数据类型之一,只有两个值TRUE和FALSE, 缺失时为NA。逻辑值一般产生自比较
向量比较结果为逻辑型向量。
c(1, 3, 5) > 2 |
从例子可以看出,向量比较也遵从R的向量间运算的一般规则: 向量与标量的运算是向量每个元素与标量都分别运算一次, 等长向量的运算时对应元素的运算, 不等长但长度为倍数关系的向量运算是把短的从头重复利用。
与NA比较产生NA,为了判断向量每个元素是否NA, 用is.na()函数,如
is.na(c(1,NA, 3) > 2) |
用is.finite()判断向量每个元素是否Inf值。
%in%是比较特殊的比较, x %in% y的运算把向量y看成集合, 运算结果是一个逻辑型向量, 第个元素的值为x的第元素是否属于y的逻辑型值。 如
c(1,3,NA) %in% c(2,3,4,5,NA) |
函数match(x, y)起到和x %in% y运算类似的作用, 但是其返回结果不是找到与否, 而是对x的每个元素, 找到其在y中首次出现的下标,找不到时取缺失值,如
match(c(1, 3), c(2,3,4,3)) |
5.2
为了表达如“而且”, “或者”之类的复合比较, 需要使用逻辑运算把两个比较连接起来。 逻辑运算符为&
, |
和!
, 分别表示“同时成立”、“两者至少其一成立”、“条件的反面”。 比如,设age<=3
表示婴儿,sex=='女'
表示女性,则 age<=3 & sex=='女'
表示女婴, age<=3 | sex=='女'
表示婴儿或妇女, !(age<=3 | sex=='女')
表示既非婴儿也非妇女。 为了确定运算的先后次序可以用圆括号()
指定。
&&
和||
分别为短路的标量逻辑与和短路的标量逻辑或, 仅对两个标量进行运算,如果有向量也仅使用第一个元素。
5.3 逻辑运算函数
函数which()返回真值对应的所有下标,如\
which(c(FALSE, TRUE, TRUE, FALSE, NA)) |
函数all.equal()与identical()类似, 但是在比较数值型时不区分整数型与实数型, 而且相同时返回标量TRUE, 但是不同时会返回一个说明有何不同的字符串。
all.equal(c(1,2,3), c(1,2,NA)) |
函数duplicated()返回每个元素是否为重复值的结果,用函数unique()可以返回去掉重复值的结果.如:
duplicated(c(1,2,1,3,NA,4,NA)) |
6. 字符型数据及其处理
字符型向量
字符型向量是元素为字符串的向量。如
s1 <- c('abc', '', 'a cat', NA, '李明') |
注意空字符串并不能自动认为是缺失值, 字符型的缺失值仍用NA表示。
一些函数
- 针对字符型数据最常用的R函数是paste()函数。 paste()用来连接两个字符型向量, 元素一一对应连接, 默认用空格连接。
# 一下两种结果相等 |
paste()
在连接两个字符型向量时采用R的一般向量间运算规则, 而且可以自动把数值型向量转换为字符型向量。 可以作一对多连接, 如paste("x", 1:3)
结果相当于c("x 1", "x 2", "x 3")
。
用sep=
指定分隔符, 如paste("x", 1:3, sep="")
结果相当于c("x1", "x2", "x3")
。
使用collapse=参数可以把字符型向量的各个元素连接成一个单一的字符串, 如paste(c(“a”, “b”, “c”), collapse=“”)结果相当于"abc"。
-
toupper()
函数把字符型向量内容转为大写,tolower()
函数转为小写。
这两个函数可以用于不区分大小写的比较, 比如,不论x的值是’JAN’, ‘Jan’还是’jan’, toupper(x)=='JAN’的结果都为TRUE。 -
用nchar(x, type=‘bytes’)计算字符型向量x中每个字符串的以字节为单位的长度,这一点对中英文是有差别的, 中文通常一个汉字占两个字节,英文字母、数字、标点占一个字节。 用nchar(x, type=‘chars’)计算字符型向量x中每个字符串的以字符个数为单位的长度,这时一个汉字算一个单位。
-
substr(x, start, stop)从字符串x中取出从第start个到第stop个的子串,不同于python(计数从0开始),R的技术从1开始。
substr('JAN07', 1, 3) |
用substring(x, start)可以从字符串x中取出从第start个到末尾的子串。
类型转换
用as.numeric()把内容是数字的字符型值转换为数值,如
substr(‘JAN07’, 4, 5) + 2000不能相加,substr取出的值时字符型,不能与数值相加,需要转换为数值
as.numeric(substr('JAN07', 4, 5)) + 2000 |
as.numeric()是向量化的, 可以转换一个向量的每个元素为数值型。
用as.character()函数把数值型转换为字符型
为了用指定的格式数值型转换成字符型, 可以使用sprintf()函数, 其用法与C语言的sprintf()函数相似, 只不过是向量化的。例如
sprintf('file%04d.txt', c(1, 99, 100)) |
字符串拆分
用strsplit()函数可以把一个字符串按照某种分隔符拆分开,例如
x <- '10,8,7' |
字符串替换功能
用gsub()可以替换字符串中的子串, 这样的功能经常用在数据清理中。 比如,把数据中的中文标点改为英文标点, 去掉空格,等等。 如
x <- '1, 3; 5' |
正则表达式
正则表达式(regular expression)是一种匹配某种字符串模式的方法。 用这样的方法,可以从字符串中查找某种模式的出现位置, 替换某种模式,等等。 这样的技术可以用于文本数据的预处理, 比如用网络爬虫下载的大量网页文本数据。 R中支持perl语言格式的正则表达式, grep()和grepl()函数从字符串中查询某个模式, sub()和gsub()替换某模式。 比如, 下面的程序把多于一个空格替换成一个空格
gsub('[[:space:]]+', ' ', 'a cat in a box', perl=TRUE) |
后面会有更加详细的介绍。
7. R向量下标和子集
变量可归结为名义型、有序型或连续型变量。
名义型变量
是没有顺序之分的类别变量。糖尿病类型Diabetes(Type1、Type2)是名义型变量的一例。即使在数据中Type1编码为1而Type2编码为2,这也并不意味着二者是有序的。有序型变量
表示一种顺序关系,而非数量关系。病情Status(poor、improved、excellent)是顺序型变量的一个上佳示例。我们明白,病情为poor(较差)病人的状态不如improved(病情好转)的病人,但并不知道相差多少。连续型变量
可以呈现为某个范围内的任意值,并同时表示了顺序和数量。年龄Age就是一个连续型变量,它能够表示像14.5或22.8这样的值以及其间的其他任意值。
类别(名义型)变量和有序类别(有序型)变量在R中称为因子(factor)
。
正整数下标
对向量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 <- c(1,4,6.25) |
负整数下标不能与正整数下标同时用来从某一向量中取子集, 比如,x[c(1,-2)]没有意义。
空下标与零下标
x[]表示取x的全部元素作为子集。 这与x本身不同
x <- c(1,4,6.25) |
下标超界
设向量x长度为n, 则使用正整数下标时下标应在1…n中取值。 如果使用大于的下标, 读取时返回缺失值,并不出错。 给超出的下标元素赋值, 则向量自动变长, 中间没有赋值的元素为缺失值。
x <- c(1,4,6.25) |
虽然R的语法对下标超界不视作错误, 但是这样的做法往往来自不良的程序思路, 而且对程序效率有影响,所以实际编程中应避免下标超界。
逻辑下标
下标可以是与向量等长的逻辑表达式, 一般是关于本向量或者与本向量等长的其它向量的比较结果
要注意的是,如果逻辑下标中有缺失值, 对应结果也是缺失值。 所以,在用逻辑下标作子集选择时, 一定要考虑到缺失值问题。正确的做法是加上!is.na前提
x <- c(1,4,6.25) |
which()、which.min()、which.max()函数
函数which()可以用来找到满足条件的下标,其他两个函数分别找最小与最大值的下标。
x <- c(3, 4, 3, 5, 7, 5, 9) |
元素名
向量可以为每个元素命名。如
ages <- c("李明"=30, "张聪"=25, "刘颖"=28) |
或
ages <- c(30, 25, 28) |
或
ages <- setNames(c(30, 25, 28), c("李明", "张聪", "刘颖")) |
这时可以用元素名或元素名向量作为向量的下标,如
ages["张聪"] |
ages[c("李明", "刘颖")] |
ages["张聪"] <- 26 |
这实际上建立了字符串到数值的映射表。
用unname(x)返回去掉了元素名的x的副本, 用names(x) <- NULL可以去掉x的元素名。
练习
设文件class.csv内容如下:
name,sex,age,height,weight |
用如下程序可以把上述文件读入为R数据框d.class, 并取出其中的name和age列到变量name和age中:
d.class <- read.csv('class.csv', header=TRUE, stringsAsFactors=FALSE) |
- 求出age中第3, 5, 7号的值;
age[c(3,5,7)] |
- 用变量age, 求出达到15岁及以上的那些值;
which(age > 15) |
- 用变量name和age, 求出Mary与James的年龄。
names(age) <- name |
- 求age中除Mary与James这两人之外的那些人的年龄值,保存到变量age1中。
|
- 假设向量x长度为n, 其元素是{1,2,…,n}的一个重排。 可以把x看成一个i到x[i]的映射(i在{1,2,…,n}中取值)。 求向量y, 保存了上述映射的逆映射,即: 如果x[i]=j, 则y[j]=i。
8. R数据类型的性质
在R语言中数值一般看作double, 如果需要明确表明某些数值是整数, 可以在数值后面附加字母L
is.double(c(1,-3)) |
在R的向量类型中, integer类型、double类型、logical类型、character类型、还有complex类型和raw类型称为原子类型(atomic types), 原子类型的向量中元素都是同一基本类型的。 比如, double型向量的元素都是double或者缺失值。 除了原子类型的向量, 在R语言的定义中, 向量还包括后面要讲到的列表(list), 列表的元素不需要属于相同的基本类型, 而且列表的元素可以不是单一基本类型元素。 用typeof()函数可以返回向量的类型, 列表返回结果为"list":
原子类型的各个元素除了基本类型相同, 还不包含任何嵌套结构,如:
c(1, c(2,3, c(4,5))) |
R有一个特殊的NULL类型, 这个类型只有唯一的一个NULL值, 表示不存在。 要把NULL与NA区分开来, NA是有类型的(integer、double、logical、character等), NA表示存在但是未知。 用is.null()函数判断某个变量是否取NULL。
在用c()函数合并若干元素时, 如果元素基本类型不同, 将统一转换成最复杂的一个,复杂程度从简单到复杂依次为: logical<integer<double<character。 如
c(FALSE, 1L, 2.5, "3.6") |
不同类型参与要求类型相同的运算时,也会统一转换为最复杂的类型, 如:
TRUE + 10 |
不同类型参与要求类型相同的运算时,也会统一转换为最复杂的类型, 如:
paste("abc", 1) |
属性
除了NULL以外, R的变量都可以看成是对象, 都可以有属性。 在R语言中, 属性是把变量看成对象后, 除了其存储内容(如元素)之外的其它附加信息, 如维数、类属等。 对象x的所有属性可以用attributes()读取, 如
x <- table(c(1,2,1,3,2,1)); |
用print()函数可以显示对象内容。 如果内容很多, 显示行数可能也很多。 用str()函数可以显示对象的类型和主要结构及典型内容。例如
s <- 101:200 |
str函数
即structure,紧凑的显示对象内部结构,即对象里有什么。
9. R日期时间
主要为lubridate()函数的使用
详细讲解:R日期时间
library(lubridate) |
lubridate包的如下函数可以取出日期型或日期时间型数据中的组成部分:
year()
取出年month()
取出月份数值mday()
取出日数值yday()
取出日期在一年中的序号,元旦为1wday()
取出日期在一个星期内的序号, 但是一个星期从星期天开始, 星期天为1,星期一为2,星期六为7。hour()
取出小时minute()
取出分钟second()
取出秒
# 取出月份 |
10 R因子类型
10.1 因子
R中用因子代表数据中分类变量, 如性别、省份、职业。 有序因子代表有序量度,如打分结果,疾病严重程度等。
用factor()函数把字符型向量转换成因子
x <- c("男", "女", "男", "男", "女") |
因子有class属性,取值为"factor", 还有一个levels(水平值)属性, 此属性可以用levels()函数访问
事实上, read.csv()
函数的默认操作会把输入文件的字符型列自动转换成因子, 这对于性别、职业、地名这样的列是合适的, 但是对于姓名、日期、详细地址这样的列则不合适。 所以,在read.csv()
调用中经常加选项stringsAsFactors=FALSE
选项禁止这样的自动转换,还可以用colClasses
选项逐个指定每列的类型。
# 把因子转换为纯粹的整数值 |
为了对因子执行字符型操作(如取子串), 保险的做法是先用as.character()函数强制转换为字符型。
factor()函数的一般形式为:
factor(x, levels = sort(unique(x), na.last = TRUE), |
levels
自行指定各水平值, 不指定时由x的不同值来求得。labels
指定各水平的标签, 不指定时用各水平值的对应字符串。exclude
选项指定要转换为缺失值(NA)的元素值集合。ordered
取真值时表示因子水平是有次序的(按编码次序)。
在使用factor()函数定义因子时, 如果知道自变量元素的所有可能取值, 应尽可能使用levels=参数指定这些不同可能取值, 这样, 即使某个取值没有出现, 此变量代表的含义和频数信息也是完整的。 自己指定levels=的另一好处是可以按正确的次序显示因子的分类统计值。
li1 <- factor(c('男', '女'), levels=c('男', '女')) |
10.2 table()
函数
用table()函数统计因子各水平的出现次数(称为频数或频率)。 也可以对一般的向量统计每个不同元素的出现次数。 如
x <- c("男", "女", "男", "男", "女") |
10.3 tapply()
函数
可以按照因子分组然后每组计算另一变量的概括统计。
sex <- factor(c("男", "女", "男", "男", "女")) |
10.4 forcats包的因子函数
- tapply()函数可以按照因子分组然后每组计算另一变量的概括统计。
- R语言中set.seed()作用是设定生成随机数的种子,种子是为了让结果具有重复性,重现结果。如果不设定种子,生成的随机数无法重现。如set.seed(1),中的1知识一个标记符号
- round函数用于舍入到最接近的整数。
library(forcats) |
如果希望按照统计量次序对因子排序, 可以用forcats::fct_reorder()函数
fac2 <- fct_reorder(fac, x, sd) |
有时在因子水平数较多时仅想将特定的一个或几个水平次序放到因子水平最前面, 可以用forcats::fct_relevel()函数
levels(fac) |
fct_relevel()第一个参数是要修改次序的因子, 后续可以有多个字符型参数表示要提前的水平。
forcats::fct_reorder2(f, x, y)也调整因子f的水平的次序, 但是根据与每组中最大的x值相对应的y值大小调整次序, 这样在作多个因子水平对应的曲线图时可以比较容易地区分多条曲线。
forcats::fct_recode()可以修改每个水平的名称
fac4 <- fct_recode( |
fct_recode()在修改水平名时允许多个旧水平对应到一个新水平, 从而合并原来的水平。 如果合并很多, 可以用fct_collapse()函数, 如
exam <- factor(c("其他","联想","百度"),levels = c("其他","联想","百度")) |
练习
设文件class.csv中包含如下内容:
name,sex,age,height,weight |
用如下程序把该文件读入为R数据框d.class, 其中的sex列已经自动转换为因子。 取出其中的sex和age列到变量sex和age中
d.class <- read.csv('class.csv', header=TRUE) |
- 统计并显示列出sex的不同值频数;
table(sex) |
- 分男女两组分别求年龄最大值;
tapply(age,sex,max) |
- 把sex变量转换为一个新的因子,F显示成“Female”,M显示成“Male”。
sex |