返回首页

【r-高级】R-面向对象编程(一)

时间:2019-08-03 来源:原创/投稿/转载作者:管理员点击: 162

  借助面向对象的编码风格,并加以合理的抽象,我们可以简单地模仿对象的重要特性,于是,问题和模型之间的转换就变得清晰自然

  举例,下面vec1类型是double,意味其内部类型或者说存储模式是双精度浮点型数字。但它的类是numeric。

  下面data1类型是list,意味data1的内部类型或者存储模式是列表,但它的S3类是data.frame。

  一个类可以用多种方法定义它的行为,尤其是它与其他类的关系。在S3系统中,我们可以创建泛型函数(generic function),对于不同的类,由泛型函数决定调用哪个方法,这就是S3方法分派(method dispatch)的工作机理。

  R中有许多基于某个通用目的定义的S3泛型函数,我们先看看head()与tail()。head()展示一个数据对象的前n条记录,tail()展示后n条。这跟x[1:n]是不同的,因为对不同的类的对象,记录的定义是不同的。对原子向量(数值、字符向量等),前n条记录指前n个元素。但对于数据框,前n条记录指前n行而不是前n列。

  我们发现函数中并没有实际的操作细节。它调用UseMethod(head)来让泛型函数head()执行方法分派,也就是说,对于不同的类,它可能有不同的执行方式(过程)。

  注意,方法都是以method.class形式表示,如果我们输入一个data.frame,head()会调用head.data.frame方法。当没有方法可以匹配对象的类时,函数会自动转向method.default方法。这就是方法分派的一个实际过程。

  S3泛型函数和方法在统一各个模型的使用方式上是最有用的。比如我们可以创建一个线性模型,以不同角度查看模型信息:

  线性模型本质上是由模型拟合产生的数据字段构成的列表,所以lm1的类型是list,但是它的类是lm,因此泛型函数根据lm选择方法:

  甚至没有明确调用S3泛型函数时,S3方法分派也会自动进行。如果我们输入lm1:

  为什么打印出来的不像列表呢?因为print()是一个泛型函数,它为lm选择了一个方法来打印线性模型最重要的信息。我们可以调用getS3method(print, lm)获取实际使用的方法与想象的进行验证:

  print()展示模型的一个简要版本,summary()展示更详细的信息。summary()也是一个泛型函数,它为模型的所有类提供了许多方法:

  实际上,summary()的输出结果也是一个对象,包含的数据都可以被访问。在这个例子里,这个对象是一个列表,是summary.lm类,它有可供print()选择的自己的方法:

  还有一些其他有用的且与模型相关的泛型函数,例如plot(),predict()。不同的内置模型和第三方扩展包提供的模型都能实现这些泛型函数。

  为避免依次生成这4个图,我们用par()将绘图区域划分为2x2的子区域。

【责任编辑:管理员】
随机推荐 更多>>