《R语言编程艺术》——3.4 增加或删除矩阵的行或列

3.4 增加或删除矩阵的行或列

严格来说,矩阵的长度和维度是固定的,因此不能增加或删除行或列。但是可以给矩阵重新赋值,这样可以得到和增加或删除一样的效果。
3.4.1 改变矩阵的大小
回忆之前通过重新赋值改变向量大小的方法:

第一个例子里,x原来长度为5,通过拼接和重新赋值,将其长度变为6。事实上我们没有改变x的长度,而是生成一个新的向量,然后赋值给x。
注意 重新赋值的过程可能会在用户看不见的情况下进行,在14章我们将会介绍。例如,即使是x[2]<-12这种小操作事实上都是一个重新赋值的过程。
类似的操作可以用来改变矩阵的大小。例如,函数rbind()(代表row bind,按行组合)和函数cbind()(代表column bind,按列组合)可以给矩阵增加行或列。

这里,cbind()把一列由1组成的向量和z组合在一起,创建了一个新矩阵。上面我们只是直接输出了结果,实际上也可以把这个新的矩阵赋值给z(或其他变量),如下所示:

不过,请谨慎使用cbind()!和创建向量一样,创建一个新的矩阵是很耗时间的(毕竟矩阵也属于向量)。在下面的代码中,cbind()创建了一个新矩阵:

新的矩阵正好被赋值给z,也就是说我们给这个新矩阵取名为z,与原来的矩阵同名,而原来的矩阵被覆盖了)。问题是创建新矩阵会减低程序速度,如果在循环中重复创建矩阵,将浪费大量的时间。
因此在循环中每次往矩阵中添加一行(列),最后矩阵会变成一个大矩阵,这种做法是不可取的,最好一开始就定义好一个大矩阵。这个事先定义的矩阵是空的,但是在循环过程中逐行或列进行赋值,这种做法避免了循环过程中每次进行耗时的矩阵内存分配。
也可以通过重新赋值来删除矩阵的行或列:

3.4.2 扩展案例:找到图中距离最近的一对端点
计算图中多个端点之间距离是计算机或统计学中常见的例子。这类问题在聚类算法和基因问题中经常出现。
我们以计算城市之间的距离为例,这比计算DNA链间距离更直观。
假设有一个距离矩阵,其第i行第j列的元素代表城市i和城市j间的距离。我们需要写一个函数,输入城市距离矩阵,输出城市间最短的距离,以及对应的两个城市。代码如下:


以下是一个调用该函数的例子:

最小值是6,位于在第3行第4列。可以看到apply()函数在这里起重要作用。
我们的任务很简单:找到矩阵中最小的非零元素。首先找到每行中的最小值—仅一个命令apply()即可对所有行达到此目的—然后找到这些最小值中最小的那一个。但如你所见,这段代码的逻辑还是略微有些复杂。
注意一个很关键的地方,这个矩阵是对称的,因为城市i到城市j的距离与从城市j到城市i的距离相等。因此在找第i行最小值时,只需要在第i+1,i+2,……n等元素中搜索(n是矩阵的总列数)。因此在调用apply()时,矩阵d的最后一行是可以跳过不用管的。
由于矩阵可能很大,如果有1000个城市的话,那么矩阵就有100万个元素。所以我们要利用矩阵的对称性来节省时间。但是这样也带来一个问题:在计算每行最小值时,我们需要知道该行在原矩阵中的行号, 而apply()函数不能直接提供给它所调用的函数。所以在代码的第6行,我们给原矩阵增加了一列,为相应的行号,目的是让apply()函数所调用的函数能够识别出行号。
apply()所调用的函数是imin()函数,它的定义开始于代码第15行,该函数寻找形式参数x所代表的这一行的最小元素及其所在位置的索引。例如,对例子中矩阵q的第一行调用函数imin(),可求出最小值是8,出现在该行第4列的位置。为求得最小元素的位置,第18行使用了函数which.min(),这是R语言中非常方便的函数。
请注意第19行。之前我们利用矩阵的对称性,在寻找最小值的时候跳过了每行的前半部分,这一点可从第18行表达式中的(i+1):(lx-1)看出。但是这也意味着which.min()返回的最小值的位置索引是相对于范围(i+1): (lx-1)的。例如在q的第三行,尽管第4个元素最小,但是which.min()返回的是1。因此我们需要在which.min()的结果上增加i,如第19行所示。
最后,要正确使用apply()的输出结果需要费点儿功夫。对于上面例子中的矩阵q,apply()函数将会返回一个矩阵wmins:

这个矩阵的第二行包含d矩阵的上三角部分各行最小值,第一行则是这些值的索引。例如wmins的第一列表明,q的第一行中最小值是8,位于第4列。
第9行代码选出整个矩阵最小值所在的行号i,在矩阵q的例子中结果为6。第10行则求出该行最小值在第j列,在矩阵q的例子中结果为4。就是说整个矩阵的最小值在第i行第j列,这个信息在11行将会被用到。
同时,apply()输出结果的第一行是各行最小值所在的列。这样我们就可以找出距离最近的城市分别是什么了。我们已经知道城市3是两个城市之一,而wmins第一行第三列对应的是4,因此城市3和城市4是距离最近的,程序第9行和第10行表示了这一推理过程。
如果该矩阵中最小值是唯一的,那么就有更简单的方法:

这段代码直接找到d的最小元素的所在位置。其中参数arr.ind=TRUE指定,which()函数返回的坐标必须是矩阵下标—也就是行号和列号,而不是一个单一的向量索引。如果没有这个参数,d就会被当作向量来处理。
前面提到过,这段新代码只有当最小值唯一时才有用。如果此条件不成立,which()函数会返回多个行/列数对,与我们的目标相悖。如果我们用原来那版代码,当d有多个最小值时,只会返回其中一个。
另外一个问题是效率。新的代码实质上包含两个(隐性的)循环:一个是计算最小值smallest,另一个是调用which()。因此新的代码会比原来那版更慢。
在这两种方法中,如果特别关注运行速度,并且可能有多个最小值,那么最好选择原来那版代码,否则就选用另一个。而后者的简洁性使之更容易阅读和维护。

时间: 2024-08-29 12:15:21

《R语言编程艺术》——3.4 增加或删除矩阵的行或列的相关文章

《R语言编程艺术》——3.1 创建矩阵

3.1 创建矩阵 矩阵的行和列的下标都从1开始.例如矩阵a左上角的元素记作a[1, 1].矩阵在R中是按列存储的,也就是说先存储第一列,再存储第二列,以此类推,如2.1.3小节所示. 创建矩阵的方法之一就是使用matrix()函数: 这里把第一列(即1和2)与第二列(3和4)连接在一起.因此数据是(1,2,3,4).然后我们给出行数和列数.由于R是按列存储的,这就决定了这四个数在矩阵中的位置. 上例指定了矩阵中全部的4个元素,因此没必要同时设定列数ncol和行数nrow这两个参数,只需要给出其中

《R语言编程艺术》——3.3 对矩阵的行和列调用函数

3.3 对矩阵的行和列调用函数 *apply()函数系列是R中最受欢迎同时也是最常用的,该函数系列包括apply().tapply()和lapply().这里我们主要介绍apply().apply()函数允许用户在矩阵的各行或各列上调用指定的函数.3.3.1 使用apply()函数以下是apply()函数的一般形式: 参数解释如下:m 是一个矩阵.dimcode 是维度编号,若取值为1代表对每一行应用函数,若取值为2代表对每一列应用函数.f是应用在行或列上的函数.fargs是f的可选参数集.例如

《R语言编程艺术》——导读

前言 R是一种用于数据处理和统计分析的脚本语言,它受到由AT&T实验室开发的统计语言S的启发,且基本上兼容于S语言.S语言的名称代表统计学(statistics),用来纪念AT&T开发的另一门以一个字母命名的编程语言,这就是著名的C语言.后来一家小公司买下了S,给它添加了图形用户界面并命名为S-Plus. 由于R是免费的,而且有更多的人贡献自己的代码,R语言变得比S和S-Plus更受欢迎.R有时亦称为GNU S,以反映它的开源属性.(GNU项目是开源软件的一个重要集合.) 为什么在统计工作

《R语言编程艺术》——1.3 函数入门

1.3 函数入门 和大多数编程语言一样,R语言编程的核心是编写"函数".函数就是一组指令的集合,用来读取输入.执行计算.返回结果.我们先定义一个函数oddcount(),以此简单介绍函数的用法.这个函数的功能是计算整数向量中奇数的个数.一般情况下,我们会用文本编辑器编写好函数代码并保存在文件中,不过在这个简单粗略的例子中,我们只需要在R的交互模式中一行行输入代码.接下来,我们还会在几个测试案例中调用这个函数: 首先,我们告诉R想定义一个名为oddcount的函数,该函数有一个参数x.左

《R语言编程艺术》——第2章 2.0 向量

第2章 2.0 向量 R语言最基本的数据类型是向量(vector).第1章已经给出了向量的一些例子,本章将详细介绍向量.首先考察向量与R语言的其他数据类型之间的关系.与C语言家族不同,R语言中,单个数值(标量)没有单独的数据类型,它只不过是向量的一种特例.而另一方面,R语言中矩阵是向量的一种特例,这一点与C语言家族相同.接下来我们会用大量时间关注以下话题:循环补齐:在一定情况下自动延长向量.筛选:提取向量子集.向量化:对向量的每一个元素应用函数.这些运算是R编程的核心,在本书的其他部分也会经常提

《R语言编程艺术》——2.1 标量、向量、数组与矩阵

2.1 标量.向量.数组与矩阵 在许多编程语言中,向量与标量(即单个数值)不同.例如,考虑下面的C代码: 这段代码请求编译器给一个x的整型变量x分配空间,并给一个名为y的三元素整型数组(C语言中的术语,类似于R中的向量)分配内存空间.但在R中,数字实际上被当做一元向量,因为数据类型里没有标量.R语言中变量类型称为模式(mode).回顾第1章,同一向量中的所有元素必须是相同的模式,可以是整型.数值型(浮点数).字符型(字符串).逻辑型(布尔逻辑).复数型等等.如果在程序中查看变量x的类型,可以调用

《R语言编程艺术》——1.4 R语言中一些重要的数据结构

1.4 R语言中一些重要的数据结构 R有多种数据结构.本节将简单介绍几种常用的数据结构,使读者在深入细节之前先对R语言有个大概的认识.这样,读者至少可以开始尝试一些很有意义的例子,即使这些例子背后更多的细节还需要过一段时间才能揭晓.1.4.1 向量,R语言中的战斗机 向量类型是R语言的核心.很难想象R语言代码或者R交互式会话可以一点都不涉及向量. 向量的元素必须属于某种"模式"(mode),或者说是数据类型.一个向量可以由三个字符串组成(字符模式),或者由三个整数元素组成(整数模式),

《R语言编程艺术》——1.7 获取帮助

1.7 获取帮助 有很多种资源可以帮你学习关于R的更多知识,其中包括R自身的一些工具,当然,还有网上的资料. 开发者们做了很多工作使R更加自文档化.下面我们将介绍一些R内置的帮助工具,以及互联网上的资源.1.7.1 help()函数 想获取在线帮助,可调用help().例如,要获取seq()函数的信息,就键入下面的命令: 1.7.2 example()函数 每个帮助条目都附带有例子.R的一个非常好用的特性是,example()函数会为你运行例子代码.示例如下: sep()函数可以生成多种等差数值

《R语言编程艺术》——3.5 向量与矩阵的差异

3.5 向量与矩阵的差异 在本章开始的时候,我说过矩阵就是一个向量,只是多了两个属性:行数和列数.这里,我们再深入说明这个问题.考虑以下例子: 因为z是向量,因此我们可以求它的长度: 换句话说,从面向对象编程的角度说,矩阵类(matrix class)是实际存在的.如第1章所说,R的大部分类都是S3类,用$符号就可访问其各组件.矩阵类有一个dim属性,是一个由矩阵的行数和列数组成的向量.本书第9章讲详细介绍关于类的更多细节问题. 以用dim()函数访问dim属性: 这些其实都是对dim函数的一个