R语言数据操纵:如何构建子集

时间:2024-04-08 17:54:21

目录

向量的子集

矩阵的子集

数据框的子集

列表的子集

如何处理缺失值

向量化操作


构建子集的基本方法:

1.使用[]提取一个或多个类型相同的元素

2.使用[[]]从列表或者数据框中提取元素

3.使用$按名字从列表或数据框中提取元素

向量的子集

比如有一个向量x,他的内容是1到5,我们使用[]+要提取元素的下标可以提取对应的元素,比如要提取第四个元素,他的下标是4,我们就写x[4]

如果要提取前四个元素,就要写x[1:4]

如果要提取向量x中大于3的元素,就要写x[x>3],运行结果如下

实际上x>3这个表达式的运行结果是一个逻辑向量,如图所示

所以x[x>3]提取的是这个表达式结果中对应位置为TRUE的元素

我们还可以使用[]提取要同时满足好几个判断条件的元素,此时需要借助逻辑操作符&和|,他们分别是与操作符和或操作符。

比如我们要提取x中大于2并且小于5的元素

又比如我们要提取x中小于2或者大于4的元素

如果向量的元素已经起了名字,我们还可以直接在[]中写入对应元素的名字来提取对应的元素,注意写名字的时候也要写上双引号。

比如我们给刚才的向量x中每一个元素都起上名字

现在我们要提取第二个元素,就可以写x["b"],运行结果如图,同时显示了这个元素与他的名字。

使用名字来提取子集的方法在很多时候非常有用,因为我们可能并不知道要提取的元素下标是几,但是却知道他的名字。

矩阵的子集

比如有一个两行三列的矩阵如图

现在要提取第二行第三列的元素,可以写成x[2,3],这样6就被提取了出来

如果要提取某一整行的数据,可以这样

只需要把逗号后面的列空着就可以,提取某一列同理,只需要把逗号前面的行空着就可以。

如果要拿到第二行的第一列和第三列元素,可以这样写

有一个问题就是,我们以[]这种方式从矩阵中提取的元素,是向量还是矩阵?这可以通过class函数来验证,如图

显然这已经不是矩阵了,而是一个一维的数据结构类型,可以认为是一个只含一个元素的向量类型。如果我们不希望提取出来的元素变成向量类型,而是仍然保留其矩阵类型的性质,可以在使用[]提取元素的时候增加一个参数drop,如图

此时提取元素的运行结果就变成了矩阵性质的数据结构,可以认为是一个一行一列的矩阵。这在有些情况下是有用的,因为有的函数要求参数类型必须是矩阵类型。

数据框的子集

比如有这样一个数据框x

数据框构建子集的方式与矩阵由很多相似之处,比如提取某一列的方法都是在逗号后面加要提取的列

也可以使用要提取的列的列名

我们当然可以直接使用第几行第几列这种方式来唯一确定要提取的元素,但由于我们还在创建数据框的同时给数据框的每个元素都命名了,因此还可以单独提取数据框每个元素的子集,比如x$v1就拿到了名为v1的这一列,此时x$v1就是一个向量了,是一个一维的数据结构,x$v1[3]就可以提取x$v1这个向量的第三个元素,当然也可以提取其第一第二个元素。x$v1[c(1,2)],如图

提取v1这一列小于4并且v2这一列大于等于8的行,列不做要求,可以这样写

确实是只有第三行满足要求。其中前面的条件表示v1这一列小于4的行,而后面的条件是v2这一列大于等于8的行,同时成立的就只有第三行。

再比如提取v1中大于2的行,发现第3 4 5行都满足条件。

如果在判断条件之前加上一个which,会发生什么?

我们发现结果和上面的居然是一样的。那么which这个函数是做什么的呢?which的作用其实是给出哪些位置是真。我们可以单独运行一下which这一句

如果直接运行这个判断条件,结果是这样

因此which返回的其实是向量中为TRUE的那些元素的下标

提取到子集之后,我们还可以对子集进行操作,比如把提取到的子集赋值为NA

此时数据框就变成了这样

实际上R语言中提供了专门构建子集的函数subset,他需要至少两个参数,一个是原始的数据集,一个是筛选子集的条件。

列表的子集

构建列表的子集使用的是[[]],$,[[]][],[[]][[]]等,相对于数据框或者矩阵子集的构建要更麻烦一些。因为可能会涉及到嵌套列表或者不完全匹配的情况

比如我们先创建这样一个列表

提取列表中第一个元素可以使用下标或者对应元素的名字,如图

我们发现用只用一个[]拿到的是列表中某个元素的名字和内容,如果我们想要只拿到某个元素的内容而不包括他的名字,应该使用嵌套的方括号[[]],比如

也可以使用$符号,如图

当然也可以借助c函数提取列表中的多个元素

介绍一个容易用错的点,如果我们先把id赋给y

这样是可以提取到某一行内容的,但是如果用$符号,就无法提取到某一行的内容

如图,虽然此时的y中放的是id,但仍然无法使用$提取到列表x某一个元素的内容

也就是说使用$符号的对象只能是列表直接的名字,而不能是被赋值为列表名字的变量。

如何从列表中获取嵌套的元素?就比如有这样一个列表

列表中有两个元素,第一个元素是一个列表,第二个元素是一个向量

假如我们想要拿到第一个元素也就是那个列表中的2,应该怎么做?

前面已经说过嵌套的[]能够拿到不含列表元素名字的内容,也就是说我们写x[[1]]就拿到了第一个列表,那么要再拿到这个列表中的某个元素内容,只需要再次使用一个嵌套的[]即可,如图

表示拿到了x列表中第一个元素(也就是列表a)中的第二个元素的内容。当然如果要同时拿到嵌套列表的名字,就在拿到嵌套列表的基础上使用一个[]即可

实际上要拿到列表中嵌套的某个数据结构的内容,还有一种更简单的方式,就是借助c函数。如图

这两句代码分别表示想要拿到列表x中第一个元素的第二个元素,想要拿到列表x第二个元素的第一个元素,这样的写法拿到的均为元素内容而不包括这些元素的名字

列表中的不完全匹配

假如有这样一个列表,它包含一个元素,这个元素是一个名为qwer的向量

那么我们如果想要拿到这个向量内容,当然可以使用$符号加上这个向量的名字,而在实际操作中我们发现即使只有这个名字的第一个字母,也能够正确的提取到这个向量的内容,如图

这种现象被称为列表的不完全匹配。

上面是使用$符号的方式,再来看看直接使用[[]]是否也存在不完全匹配

我们发现也是存在的,但是需要把参数exact设置成FALSE

注意如果一个列表中有好几个元素的名字第一个字母都相同,就会对使用不完全匹配造成一定影响,比如一个元素名叫a,还有一个元素名叫asaaxfg,那么在使用不完全匹配的时候就只能使用as

如何处理缺失值

先创建一个包含缺失值的向量x

is.na函数可以用来判断向量中有无缺失值,这个函数会在对应下标为缺失值的位置返回TRUE,而不是缺失值的位置返回FALSE,如果要提取x中非缺失值的元素,只需要在is.na结果前面加一个!即可

有时候还需要提取两个向量对应下标位置均不是缺失值的元素,如图

这时候就要借助函数complete.cases函数,他的返回值仍然是一堆逻辑值,只有在传入的两个向量对应下标均非缺失值的时候才返回TRUE

complete.cases函数的返回值可以让我们方便的提取x和y中对应位置都不是缺失值的元素,就是从上帝视角来看,把这些向量一个个堆好,某一列中都没有缺失值的元素,如图

再来看一个比较复杂的例子,我们加载R中自带的一个数据集datasets

airquality是datasets中的某个子集,使用head函数可以查看他的前六行。在以后会经常见到这样的表格,其中每一行叫做一个记录,每一列叫做一个变量,所以这里展示了六个变量的六个记录。

complete.cases返回值是一个非常长的逻辑向量,值为TRUE的代表数据框airquality中没有缺失值的行

利用complete.cases的返回值这个逻辑向量可以非常便捷的提取出没有缺失值的行,提取的时候对列没有做要求,表示要看这六个变量的情况,如图

要查看这个数据框的前10行,可以这样

向量化操作

用一个例子来解释什么是向量化操作

现在x和y均为向量,我们想要得到另一个向量,这个向量里面存放的内容是x和y两个向量下标相同位置的元素之和,如果是在C语言中,我们需要借助循环,但是在R中,直接写x+y即可,运行之后就是对应位置相加的结果

对应下标位置作乘法或者除法同理

如果是矩阵呢?

比如我创建了x和y两个矩阵,在创建y矩阵的时候我是用了rep函数,表示把2重复四次,因此y矩阵的内容是4个2

此时来看这两个矩阵加法或者乘法的结果

发现使用这种方法做的矩阵乘法其实是对应位置的元素相乘,我们知道真正的矩阵乘法不是这样的,而应该是乘行乘列,要做真正的矩阵乘法,应该使用运算符%*%,如图