数据结构是为了便于存储不同类型的数据而设计的。
R中常用的数据结构包括:
同质数据类型(homogeneous data types),即所存储的一定是相同类型的元素,包括向量、矩阵、数组;
异质数据类型(heterogeneous data types),即可以存储不同类型的元素,这大大提高了存储的灵活性,但同时也降低了存储效率和运行效率,包括列表、数据框。
一、向量(一维数据)
向量是由一组相同类型的原始值构成的序列,可以是一组数值、一组逻辑值、一组字符串等。
1. 数值向量
(1) 数值向量就是由数值组成的向量,单个数值是长度为1的数值向量。
>
可以用numeric()来创建全为0的指定长度的数值向量:
>
经常用函数c()实现将多个对象合并到一起,例如,将多个数值向量合并成一个数值向量:
>
(2) 创建等差的数值向量
用 : 或函数seq()可以创建等差的数值向量。
函数seq(),基本格式为:
seq(from=...,to=...,by=...,length.out=...,along.with =...)
其中,
from设置首项(默认为1);
to设置尾项;
by设置等差值(默认为1或-1);
length.out设置序列长度;
along.with以该参数的长度作为序列长度。
>
(3)创建重复的数值向量
函数rep(),基本格式为:
rep(x,times=...,length.out=...,each=...)
其中,
x为要重复的序列;
times设置序列重复次数;
length.out设置产生的序列的长度;
each设置每个元素分别重复的次数(默认为1)。
x
注意:在R中,两个不同长度的向量做运算,短的会自动循环补齐以配合长的,例如:
>
2. 逻辑向量
逻辑向量,是一组逻辑值(TRUE或FALSE)的向量。
>
R中的比较运算符,还有“==”、“>=”“<”、“<=”,此外,用 %in% 判断元素是否属于集合:
>
注:match(v1,v2) 逐个检查向量v1中元素是否在向量v2中,若是则返回该元素,否则返回NA。
3. 字符向量
字符(串)向量,是一组字符串组成的向量,R中单引号和双引号都可以用来生成字符串向量。
>
要想字符串中出现单引号/双引号,需要用转义符 来做转义,或者单双引号错开,用函数cat() 生成字符串:
>
注:R中还有不常用的复数向量、原(raw)向量。
4. 构建向量子集
访问向量的一些特定元素或者某个子集。
(1) 使用元素的位置来访问(R中索引是从1开始的)
>
也可以放任意位置的数值向量,但是注意不能既放正数又放负数:
>
访问不存在的位置也是可以的,返回NA缺失值:
>
(2) 使用逻辑向量来访问
输入与向量相同长度的逻辑向量,以此决定每一个元素是否要被获取:
>
(3) 对向量子集进行赋值,替换相应元素
>
(4) 用逻辑条件来选择元素或赋值
>
注:R中的逻辑运算符有:&、|、!、&&、||、xor,其中&、|与&&、||的区别是:&&和||遵从“短路”原则,即遇到TRUE(FALSE)则返回TRUE(FALSE)而不继续往下计算;而&和|是向量运算符,对向量中所有元素进行运算。
另外,若对不存在的位置赋值,前面将用NA补齐:
>
5. 对向量元素命名
可以在创建向量的同时对其每个元素命名:
>
命名后,就可以通过名字来访问向量元素:
>
获取向量元素的名字:
>
更改向量元素的名字:
>
移除向量元素的名字:
>
6. [ ]与[[ ]]的区别
[ ]可以提取对象的子集,[[ ]]可以提取对象中的元素。
二者的区别:以向量为例,可以将一个向量比作10盒糖果,你可以使用[ ]获取其中的3 盒糖果,使用[[ ]]打开盒子并从中取出一颗糖果。
对于未对元素命名的向量,使用[ ]和[[ ]]取出一个元素会产生相同的结果。但已对元素命名的向量,二者会产生不同的结果:
>
由于[[ ]]只能用于提取出一个元素,因此不适用于提取多个元素的情况,所以[[ ]]不能用于负整数,因为负整数意味着提取除特定位置之外的所有元素。
使用含有不存在的位置或名称来创建向量子集时将会产生缺失值。但当使用[[ ]]提取一个位置超出范围或者对应名称不存在的元素时,该命令将会无法运行并产生错误信息。
以下三个语句都会报错:
>
7. 对向量排序
函数sort(),基本格式:
sort(x,decreasing=FALSE, na.last= FALSE,...)
其中,
x为排序对象(数值型或字符型);
decreasing默认为FALSE即升序,TURE为降序;
na.last默认为FALSE,若为TRUE,则将向量中的NA值放到序列末尾。
函数rank(),返回值是该向量中对应元素的“排名”。
函数order(),返回值是对应“排名”的元素所在向量中的位置,例如,
>
说明:默认按升序,排名第2的元素在原向量的第4个位置。
函数rev(),将序列进行反转,即1,2,3变成3,2,1
二、矩阵(二维数据)
矩阵是一个用两个维度表示和访问的向量。因此,适用于向量的性质和方法大多也适用于矩阵:矩阵也要求元素是同一类型,数值矩阵、逻辑矩阵等。
1.创建矩阵
(1)用matrix( )函数将一个向量变成矩阵,其基本格式为:
matrix(x, nrow=..., ncol=..., byrow=..., dimnames=...)
其中,
x为数据向量作为矩阵的元素;
nrow设定行数;
ncol设定列数;
byrow设置是否按行填充,默认为FALSE(按列填充);
dimnames用字符型向量表示矩阵的行名和列名。
>
也可以创建后再命名:
>
(2)特殊矩阵
>
注:函数as.vector(),可将矩阵转化为向量,元素按列读取。
2.构建矩阵子集
矩阵是用两个维度表示和访问的向量,可以用一个二维存取器 [ , ]来访问,这类似于构建向量子集时用的一维存取器[ ]。
可以为每个维度提供一个向量来确定一个矩阵的子集。方括号中的第1 个参数是行选择器,第2 个参数是列选择器。与构建向量子集一样,可以在两个维度中使用数值向量、逻辑向量和字符向量。
m1[1,2]——提取第1行,第2列的单个元素
m1[1:2, 2:4] ——提取第1至2行,第2至4列的元素
m1[c("r1", "r3"), c("c1", "c3")]——提取行名为r1和r3,列名为c1和c3的元素
若一个维度空缺,则选出该维度的所有元素:
m1[1,] ——提取第1行,所有列元素
m1[, 2:4] ——提取所有行,第2至4列的元素
负数表示在构建矩阵子集时可排除该位置,这和向量中的用法一致:
m1[-1,] ——提取除了第1行之外的所有元素
m1[,-c(2,4)] ——提取除了第2和4列之外的所有元素
注意,矩阵是一个用两个维度表示和访问的向量,但它本质上仍然是一个向量。因此,向量的一维存取器也可以用来构建矩阵子集:
>
由于向量只包含相同类型的元素,矩阵也是如此。所以它们的操作方式也相似。若输入一个不等式,则返回同样大小的逻辑矩阵:
>
根据它就可以选择矩阵元素或赋值:
>
3.矩阵的运算
+-*/——四则运算(要求矩阵维数相同,类似Matlab中的点运算)
dim(x)——返回矩阵x的维数(几行×几列)
colSums()——对矩阵的各列求和
rowSums()——对矩阵的各行求和
colMeans()——对矩阵的各列求均值
rowMeans()——对矩阵的各行求均值
t()——对矩阵转置
det()——返回方阵的行列式
crossprod()——返回两个矩阵的内积
outer()——返回矩阵的外积(叉积)
%*%——矩阵乘法(要求左阵的列数=右阵的行数)
diag()——取矩阵对角线元素生成对角矩阵,若对象是向量,则返回以该向量为对角元素的矩阵
solve()——返回逆矩阵(要求矩阵可逆)
eigen()——返回矩阵的特征值与特征向量
三、多维数组(高维数据)
数组向更高维度的自然推广。具体来说,数组就是一个维度更高(通常大于2)、可访问的向量。数组也要求元素是同一类型。
1.创建多维数组
用函数array()将一个向量变成数组,基本格式为:
array(x,dim=...,dimnames=...)
其中,
x为数据向量作为多维数组的元素;
dim设置多维数组各维度的维数;
dimnames设置多维数组各维度的名称。
>
也可以在创建数组时对每个维度进行命名:
>
2. 构建数组子集
第3个维度姑且称为“页”。
a1[2,4,2]——提取第2行,第4列,第2页的元素
a1["r2","c4","k2"]——提取第r2行,第c4列,第k2页的元素
a1[1,2:4,1:2] ——提取第1行,第2至4列,第1至2页的元素
a1[,,2]——提取第2页的所有元素
dim(a1)——返回多维数组a的各维度的维数
主要参考文献:
[1] 任坤,R语言编程指南. 人民邮电出版社, 2017.
[2] 张良均,谢佳标,杨坦,肖刚. R语言与数据挖掘. 机械工业出版社,2016.
——————————————
原创作品,转载请注明