R 中的类
类是用于创建对象的蓝图,包含其成员变量及属性。
正如前文所述,R 有两种类体系:S3 和 S4。
S3 类
这些类通过将函数拆分为泛型与方法,从而实现函数重载。
函数 = 泛型 + 方法
S3 与 C#、Java 等其他编程语言非常不同。它实现起来非常简单,仅使用第一个参数进行分发。因此,从程序员角度看,它不需要太多预备知识。
S3 通过严格的命名约定 generic.dot.class 来工作。
generic.class
方法的参数应包含泛型的参数,且方法应包含 ...arg。
构建 S3 类及示例
下面的示例将演示如何构建一个 S3 类。示例展示了创建列表、传入组件、设置合适的类名,并打印结果。
如下所示,“studentBio” 是一个列表,组件以列表形式传入,分别为 “student_name”、“student_age” 和 “student_contact”。类名为 “Student Info”,“studentBio” 为新建的类实例,其值如下所示。
studentBio <- list(studentName = "Harry Potter", studentAge = 19, studentContact="London")
class(studentBio) <- "StudentInfo"
studentBio
$studentName
[1] "Harry Potter"
$studentAge
[1] 19
$studentContact
[1] "London"
attr(,"class")
[1] "StudentInfo"
上述代码将输出如下内容:
$studentName
"Harry Potter"
$studentAge
19
$studentContact
"London"
attr(,"class")
"StudentInfo"
如果您对在 R 中编写函数还不熟悉,请阅读 R 函数使用教程!
在 S3 中创建自定义泛型方法
您将使用下面的代码实现一个泛型函数。
下面的代码展示了名为 “contact” 的泛型函数,将对象作为参数传入。同时,使用 “UseMethod” 与名为 “contact” 的泛型函数配合,以实现方法的“分发”,即根据传入参数的不同返回不同结果的过程。
contact <- function(object) {
UseMethod("contact")
}
接下来为先前创建的 “StudentInfo” 类编写一个对应的方法。方法名为 “contact”,后接点号与类名 “StudentInfo”。在函数体内,通过 “$” 访问属性 “studentContact”。
contact.StudentInfo <- function(object) {
cat("Your contact is", object$studentContact, "\n")
}
contact(studentBio)
Your contact is London
上述代码使用 object$studentContact,即将对象作为参数传入函数,并借助 “$” 访问属性 “studentContact”,输出结果如下。
Your contact is London
S4 类
S4 类更为严格、规范,更贴近面向对象概念。S4 的类由正式的类定义来表示。更具体地说,S4 为方法和泛型提供了 setter 和 getter 函数。与 S3 类相比,S4 能够支持多重分发。
下面将通过创建并讨论示例,来具体了解 R 中上述类。
S4 类通过 set class 函数定义。
setClass()
构建 S4 类及示例
如前所述,S4 类通过 setClass() 方法定义。您将使用 setClass() 方法创建并定义 S4 类。我们将使用一个子程序来验证数据一致性(验证),并设置默认值(原型)。
以下为定义类及插槽的代码:
下面用于定义一个类(也称为 “prototype”),其中定义了插槽:类名为 “employee”,name 为 character,id 为 numeric,contact 为 character。
setClass("employee", slots=list(name="character", id="numeric", contact="character"))
以下代码可用于创建 S4 的具体实例或对象。
使用 “new” 并在其中指定类名 “employee”,为 name、id 和 contact 等插槽填充值,从而创建对象。
obj <- new("employee",name="Steven", id=1002, contact="West Avenue")
obj
An object of class "employee"
Slot "name":
[1] "Steven"
Slot "id":
[1] 1002
Slot "contact":
[1] "West Avenue"
An object of class "employee"
Slot "name":
"Steven"
Slot "id":
1002
Slot "contact":
"West Avenue"
以上输出表明,所创建的对象属于 "employee" 类;其 Slot "name" 为 "Steven",Slot "id" 值为 1002,Slot "contact" 值为 "West Avenue"。
函数与命令
要检查某对象是否为 S4 对象,可使用以下两个命令:
命令 ‘is.object(obj)’ 用于检查某变量或实例是否引用一个对象。
is.object(obj)
TRUE
上述代码将输出如下结果:
TRUE
命令 ‘is.S4(obj)’ 用于检查某变量或实例是否为 S4 对象。
isS4(obj)
TRUE
上述代码将输出如下结果:
TRUE
访问与修改插槽值
访问插槽
插槽通过 "@" 访问,而不是使用 "$"。
使用 ‘obj@name’ 即对象名加插槽名来访问名称 “Steven”,‘obj@id’ 同理。
obj@name
obj@id
'Steven'
1002
上述代码将得到如下输出:
'Steven'
1002
修改插槽
使用赋值运算符("<-")即可修改插槽值,例如将 ‘obj@contact’ 赋为新值 "North Avenue"。
obj@contact <- "North Avenue"
obj
An object of class "employee"
Slot "name":
[1] "Steven"
Slot "id":
[1] 1002
Slot "contact":
[1] "North Avenue"
上述代码将得到如下输出:
An object of class "employee"
Slot "name":
"Steven"
Slot "id":
1002
Slot "contact":
"North Avenue"
从以上输出可见,Slot "contact" 的值已由先前的 "West Avenue" 改为 "North Avenue"。
另外,也可使用 ‘slot()’ 来修改值。
‘slot(obj, "id")’ 表示获取插槽 "id",并将其赋值为 1004,随后用 ‘obj’ 打印结果。
slot(obj,"id") <- 1004
obj
An object of class "employee"
Slot "name":
[1] "Steven"
Slot "id":
[1] 1004
Slot "contact":
[1] "North Avenue"
An object of class "employee"
Slot "name":
"Steven"
Slot "id":
1004
Slot "contact":
"North Avenue"
以上输出显示,Slot "id" 的值已由 1002 改为 1004。
在 S4 中创建自定义泛型方法
我们来创建一个函数,使其按需打印输出。使用 ‘setMethod()’ 与泛型函数 ‘show()’。同时,通过 ‘@’ 访问所有插槽的值并打印其名称。最后,通过 ‘obj’ 获取输出。
setMethod("show",
"employee",
function(object) {
cat("Name:",object@name, "\n")
cat("Id:",object@id, "\n")
cat("Contact:", object@contact, "\n")
}
)
obj
Name: Steven
Id: 1004
Contact: North Avenue
Name: Steven
Id: 1004
Contact: North Avenue
以上输出表明,结果以插槽名及其对应值的形式打印。
恭喜
恭喜您,已完成本教程!
在本教程中,您学习了面向对象编程(OOP)、R 的对象、S3 与 S4 等不同类及其构建方式,并通过示例了解了如何创建泛型函数等内容。
如果您想进一步学习 R,请查看 DataCamp 的课程:
面向对象编程(OOP)是一种编程范式,它使用不同的方法围绕数据或对象来设计软件,而不是仅靠函数。在 OOP 语境中,方法其实就是函数。之所以称为面向对象,是因为所有处理都围绕对象及其字段展开。每个对象都有不同的属性和行为。
在面向对象编程中,整个程序可以被分成不同的类,从而更快理解程序的执行流程。R 是一门函数式编程语言,引入 OOP 有助于管理大型系统问题。OOP 常用于管理 GUI 应用,尤其是 Web 应用。面向对象编程非常适合构建数据分析工具,但并不适合直接进行数据分析本身。
OOP 的体系
主要有两种 OOP 体系,如下所述:
注意:这些类将在后文详细讨论。
R 中的对象
对象是类的实例。此外,在 R 中一切皆对象,欲了解更多,请参阅 R 的数据类型。对象也可以拥有诸如 class、attributes、dimnnames、names 等属性。
例如,对象通过
<-,进行赋值。请看下面的代码片段,其中 “a1” 和 “a2” 是变量,被赋予数值。对象也可以被赋为一组数字,其中 “a3” 是一个包含多个数字的向量对象。
这里的 c 将 10、20、30 组合成一个向量。
让我们来看一个真实场景:学生这个对象拥有姓名、年龄、年级和性别等属性;老师这个对象拥有姓名、年龄和性别等属性。
上述代码会得到如下输出:
从上面的示例可以看到,不同类型的对象。“student” 和 “teacher” 对象(也称变量)分别包含类型为 “character” 和 “double” 的值。