向量
library(tidyverse)
1.1.1向量介绍
向量,vector,是R中最重要的一个概念,它是构成其他数据结构的基础
用还函数c来创建向量,c代表concatenate连接欸,也可以理解为收集collect,或者合并combine
打印向量x
R中的字符串要加引号,单引号,双引号都可以
逻辑型变量可以不加引号
用冒号:可以构建等差数列
调整等差数列的起始和终止值seq(from=2,to=34)
调整等差数列的起始和终止值seq(from=2,to=34,by=2)
控制输出的个数length.out
rep()函数,重复出现的次数,重复5次2 ,重复5次x,必须是同一类型,因为同一类型方便计算
每个重复5次,用each
rep(x,each=5,times=2) #times是遍数
显示变量的类型用mode()函数
如果变量中只有一个值,可以不使用c来赋值,此时称为标量
向量化编程
向量化运算时要保证x,y的长度一致(重新定义了x<-(1,2,3,4,5))
x[x>3]输出向量x中大于3的
控制x中每个向量出现的次数
1.1.2 向量的索引
length(x)返回向量x的长度
R中索引是从1开始,不是从0开始,x[1]这个是访问x中的第一个向量
x[-19]不输出x中的第19个元素,负号的意思相当于抛去
x[c(4:18)]输出x中第4到第18个向量
x[c(1,23,45,67,89)]输出x中索引值为1,23,45,67,89的元素,当然可以重复索引
中括号中不可以既有负数又有正数,因为这样会逻辑不通顺,此时可以曹勇逻辑值解决
若定义的逻辑值超过元素数,则会产生缺失值NA
还可以有复杂的逻辑表达式
对于字符型
可以判断某字符是否在其中 %in%
嵌套使用
关于z的逻辑嵌套使用,访问
使用names()函数给变量y中的每个元素取名字
可以通过名称属性访问
如何修改向量,比如添加,删除等操作
对向量x进行添加 x[101]<-101
先定义一个向量v,其值为1到3,通过索引4,5,6位置,对其进行批量赋值
若对其赋值中间没有,则会出现缺失值NA
在第5个和第0个位置后面添加元素99,append(x=v,values = 99,after=5)
append(x=v,values = 99,after=0)
删除整个向量用rm()函数
删除某些元素用负号 -
修改指定位置上的元素,用索引y["four"]<-100,把4位置上的元素修改为100
1.1.3向量运算
定义两个向量,分别为x,y,此时两个向量元素个数相等
**这是幂运算
%%取余运算
%/%整除运算
若定义了一个比较短的向量,必须是整数倍才能运算
向量之间的逻辑运算
比较x和y是否相等,要用两个等于号==,一个等于号是赋值
%in%包含运算符
向量中的函数
返回不大于x的最大整数 floor(),不小于x的最大整数ceiling()
对向量x的一些函数操作
trunc()函数返回整数部分
round()函数四舍五入,digits代表保留的小数位数
signif()函数与round()函数类似,保留小数部分有效数字
可以对向量进行三角函数的操作
一些统计函数
定义一个1到100的向量
sum()函数求和,max()函数求最大值,min()函数求求最小值,mean()函数求平均值,range()函数求最大和最小值,var()函数求方差,sd()函数求标准差,round()函数四舍五入,prod()函数返回连乘的积,median()函数求中位数,quantile()函数求分位数
计算vec的4分位数,5分位数,8分位数
返回最大(小)元素值位置的索引值,返回元素值为7(1)的索引值
which(t==7) #返回向量中元素7所在位置处的索引 which(t>5) #返回元素值大于5的索引值
方差var() 标准差 sd()
和 sum()
均值 mean()
最值 最大max() 最小 min()
连乘 prod()
函数seq(),按照指定的规律来产生向量
产生字母序列 letters()
函数which(),返回下标
函数rev(),sort(),一个是颠倒,一个是排序
函数matrix(),生成矩阵,
函数t(),矩阵的转置,
矩阵相乘 a%*%b ,函数diag(),返回矩阵的对角线
产生单位矩阵diag(标量),例如diag(4)
矩阵求逆,函数rnorm()正太分布产生随机数,函数solve()求逆矩阵
解线性方程组solve(a,b),a是一个矩阵,b是一个向量,这样构成方程组
0.201 x1 + 1.427 x2 - 0.282 x3 + 0.930 x4 = 1
0.135 x1 - 1.389 x2 - 0.055 x3 - 0.026 x4= 2
1.2 向量基础
向量的类型主要有两种。
• 原子向量,其共有 6 种类型:逻辑型、整型、双精度型、字符型、复数型和原始型。整
型和双精度型向量又统称为数值型向量。
• 列表,有时又称为递归向量,因为列表中也可以包含其他列表。
原子向量与列表之间的主要区别是,原子向量中的各个值都是同种类型的,而列表中的各
个值可以是不同类型的。
每个向量都有两个关键属性:
• 类型。你可以使用 typeof() 函数来确定向量的类型:
typeof(letters)
typeof(1:10)
• 长度。你可以使用 length() 函数来确定向量的长度:
x <- list("a", "b", 1:10) length(x)
1.3 重要的原子向量
4 种最重要的原子向量类型是逻辑型、整型、双精度型和字符型。
1.3.1 逻辑型
逻辑型向量是最简单的一种原子向量,因为它们只有 3 个可能的取值:FALSE、TRUE 和 NA。
1:10 %% 3 == 0
c(TRUE, TRUE, FALSE, NA)
1.3.2 数值型
整型与双精度型向量统称为数值型向量。R 中默认数值是双精度型的。如果想要创建整型
数值,可以在数字后面加一个 L:
typeof(1)
typeof(1L)
• 双精度型是近似值。双精度型表示的是浮点数,不能由固定数量的内存精确表示。
x <- sqrt(2) ^ 2 x
x - 2
在比较浮点数时,不能使用 ==,而应该使用 dplyr::near(),后者可以容忍一些数据误差。
• 整型数据有 1 个特殊值 NA,而双精度型数据则有 4 个特殊值:NA、NaN、Inf 和 -Inf。
其他 3 个特殊值都可以由除法产生。
c(-1, 0, 1) / 0
不要使用 == 来检查这些特殊值,而应该使用辅助函数 is.finite()、is.infinite() 和is.nan()。
1.3.3 字符型
字符向量是最复杂的一种原子向量,因为其每个元素都是一个字符串,而字符串可以包含任意数量的数据。
R 使用的是全局字符串池。这意味着每个唯一的字符串在内存中只保存一次,每次对这个字符串的使用都指向这段内存,这样可以减少复制字符串所需的内存空间。可以使用 pryr::object_size() 函数来查看这种处理的效果:
x <- "This is a reasonably long string." pryr::object_size(x)
y <- rep(x, 1000) pryr::object_size(y)
y 所占用的内存不是 x 的 1000 倍,因为 y 中的每个元素都只是指向一个字符串的指针。因为一个指针占 8 个字节,所以 1000 个指针以及一个 136 字节的字符串所占用的内存空间是 8 * 1000 + 136 = 8.13KB。
1.3.4 缺失值
注意,每种类型的原子向量都有自己的缺失值:
NA # 逻辑型
NA_integer_ # 整型
NA_real_ # 双精度型
NA_character_ # 字符型
1.4 使用原子向量
1.4.1 强制转换
• 显式强制转换:当调用 as.logical()、as.integer()、as.double() 或 as.character()
这样的函数进行转换时,使用的就是显式强制转换。
• 隐式强制转换:当在特殊的上下文环境中使用向量,而这个环境又要求使用特定类型的
向量时,就会发生隐式强制转换。
在数值环境中使用逻辑向量,TRUE 转换为 1,FALSE 转换为 0。这意味着对逻辑向量求和的结果就是其中真值的个数,逻辑向量的均值就是其中真值的比例:
x <- sample(20, 100, replace = TRUE) y <- x > 10
sum(y) # 大于10的数有多少个?
mean(y) # 大于10的数的比例是多少?
1.4.2 检验函数
有时我们需要根据向量的类型进行不同的操作,R 基础包中提供了很多这样的函数,如 is.vector() 和 is.atomic()。更可靠的方法是使用 purrr 包提供的 is_* 函数族,以下表格总结了它们的使用方式。
以上每个函数都配有一个“标量”版本,比如 is_scalar_atomic(),它们可以检验长度为1 的向量。
1.4.3 标量与循环规则
正因为没有标量,所以 R 的多数内置函数都是向量化的,即可以在数值的一个向量上进行操作。
sample(10) + 100
runif(10) > 0.5
如果两个长度不同的向量相加,那么会出现什么情况呢?此时 R 会扩展较短的向量,使其与较长的向量一样长,这个过程就称作向量循环。
1:10 + 1:2
如果确实想要执行向量循环,那么你需要使用 rep() 函数手工完成:
tibble(x = 1:4, y = 1:2)
tibble(x = 1:4, y = rep(1:2, 2))
tibble(x = 1:4, y = rep(1:2, each = 2))
1.4.4 向量命名
所有类型的向量都是可以命名的。你可以在使用 c() 函数创建向量时进行命名:
c(x = 1, y = 2, z = 4)
也可以在向量创建完成后,使用 purrr::set_names() 函数来命名:
set_names(1:3, c("a", "b", "c"))
1.4.5 向量取子集
我们可以使用 dplyr::filter() 函数在 tibble 中筛选行。但 filter() 函数只能筛选 tibble,因此要想筛选向量,我们需要使用一个新工具:[。[ 就是取子集函数,调用形式是 x[a]。
可以使用以下 4 种形式来完成向量取子集操作:
• 使用仅包含整数的数值向量。整数要么全部为正数,要么全部为负数,或者为 0。
x <- c("one", "two", "three", "four", "five") x[c(3, 2, 5)]
位置可以重复,这样可以生成比输入更长的输出结果:
x[c(1, 1, 5, 5, 5, 2)]
使用负整数取子集时,会丢弃相应位置的元素:
x[c(-1, -3, -5)]
正数与负数混合使用则会引发一个错误:
x[c(1, -1)]
这条错误消息中提到了使用 0 来取子集,这样不会返回任何值:
x[0]
• 使用逻辑向量取子集。这种方式可以提取出 TRUE 值对应的所有元素,一般与比较函数结合起来使用效果最佳:
x <- c(10, 3, NA, 5, 8, 1, NA)
# x中的所有非缺失值
x[!is.na(x)]
# x中的所有偶数值(或缺失值)
x[x %% 2 == 0]
• 如果是命名向量,那么可以使用字符向量来取子集:
x <- c(abc = 1, def = 2, xyz = 5) x[c("xyz", "def")]
• 取子集的最简方式就是什么都不写:x[],这样就会返回 x 中的全部元素。如果 x 是
二维的,那么 x[1, ] 可以选取出第 1 行和所有列,x[, -1] 则可以选取出所有行和除第
1 列外的所有列。
1.5 递归向量(列表)
列表是建立在原子向量基础上的一种复杂形式,因为列表中可以包含其他列表。可以使用 list() 函数创建列表:
x <- list(1, 2, 3) x
在处理列表时,str() 函数是一个非常有用的工具,因为其重点关注列表结构,而不是列
表内容:
str(x)
x_named <- list(a = 1, b = 2, c = 3) str(x_named)
与原子向量不同,list() 中可以包含不同类型的对象:
y <- list("a", 1L, 1.5, TRUE) str(y)
列表甚至可以包含其他列表:
z <- list(list(1, 2), list(3, 4)) str(z)
1.5.1 列表可视化
x1 <- list(c(1, 2), c(3, 4)) x2 <- list(list(1, 2), list(3, 4)) x3 <- list(1, list(2, list(3)))
这种可视化表示遵循以下 3 个原则:
• 列表用圆角矩形表示,原子向量用直角矩形表示。
• 子向量绘制在父向量中,而且背景要比父向量深一些,这样更容易表示出层次结构。
• 子向量的方向(也就是其行和列)并不重要,我们只在示例中表示出一行或一列,有时是为了节省空间,有时是为了说明一个重要的属性。
1.5.2 列表取子集
列表取子集有 3 种方式:
a <- list(a = 1:3, b = "a string", c = pi, d = list(-1, -5))
• 使用 [ 提取子列表。这种方式的结果总是一个列表:
str(a[1:2])
str(a[4])
• 使用 [[ 从列表中提取单个元素。这种方式会从列表中删除一个层次等级:
str(a[[1]])
str(a[[4]])
• $ 是提取列表命名元素的简单方式,其作用与 [[ 相同,只是不需要使用括号:
a$a
a[["a"]]
对于列表来说,[ 和 [[ 之间的区别是非常重要的,因为 [[ 会使列表降低一个层级,而[ 则会返回一个新的、更小的列表。
1.6 特性
可以使用 attr() 函数来读取和设置单个特性值,也可以使用attributes() 函数同时查看所有特性值:
x <- 1:10 attr(x, "greeting")
attr(x, "greeting") <- "Hi!" attr(x, "farewell") <- "Bye!" attributes(x)
3 种特别重要的特性可以用来实现 R 中的基础功能:
• 名称:用于命名向量元素。
• 维度:使得向量可以像矩阵或数组那样操作。
• 类:用于实现面向对象的 S3 系统。
泛型函数是 R 中实现面向对象编程的关键,因为它允许函数根据不同类型的输入而进行不同的操作。
可以使用 methods()函数列举出一个泛型函数的所有方法:
methods("as.Date")
1.7 扩展向量
4 种重要的扩展向量。
• 因子
• 日期
• 日期时间
• tibble
1.7.1 因子
因子是设计用来表示分类数据的,只能在固定集合中取值。因子是在整型向量的基础上构
建的,添加了水平特性:
x <- factor(c("ab", "cd", "ab"), levels = c("ab", "cd", "ef")) typeof(x)
attributes(x)
1.7.2 日期和日期时间
R 中的日期是一种数值型向量,表示从 1970 年 1 月 1 日开始的天数:
x <- as.Date("1971-01-01") unclass(x)
typeof(x)
attributes(x)
日期时间是带有 POSIXct 类的数值型向量,表示从 1970 年 1 月 1 日开始的秒数:
x <- lubridate::ymd_hm("1970-01-01 01:00") unclass(x)
typeof(x)
attributes(x)
tzone 特性是可选的。它控制的是时间的输出方式,不是时间的值:
attr(x, "tzone") <- "US/Pacific" x
attr(x, "tzone") <- "US/Eastern" x
另一种日期时间类型称为 POSIXlt,它是基于命名列表构建的:
y <- as.POSIXlt(x) typeof(y)
attributes(y)
1.7.3 tibble
tibble 是扩展的列表,有 3 个类:tbl_df、tbl 和 data.frame。它的特性有 2 个:(列)
names 和 row.names。
tb <- tibble::tibble(x = 1:5, y = 5:1) typeof(tb)
attributes(tb)
传统 data.frames 具有非常相似的结构:
df <- data.frame(x = 1:5, y = 5:1) typeof(df)
attributes(df)