用户定义的S3组通用功能在R中如何工作?

如何解决用户定义的S3组通用功能在R中如何工作?

我正在阅读Advanced R by Hadley Wickham,在13.7.3 Group Generics部分感到困惑。

enter image description here

措词让我有些困惑,“……您无法定义自己的组通用……为您的班级定义单个组通用……”,但我认为本节的意思是,如果我定义组通用Math.MyClass,则Math对象将覆盖abs组通用(signMyClass等)中的所有功能。

可以通过运行以下命令来确认:

my_class <- structure(.Data = -1,class = "MyClass")

my_class
# [1] -1
# attr(,"class")
# [1] "MyClass"

abs(my_class)
# [1] 1
# attr(,"class")
# [1] "MyClass"

Math.MyClass <- function(x) { x }

abs(my_class)
# [1] -1
# attr(,"class")
# [1] "MyClass"

我知道这跟在special naming scheme generic.class之后,但是为什么.Dataabs(my_class)的值会受到影响?

当我创建变量my_class时,我设置了参数.Data = -1,并且-1的类为numeric,应该没有改变:

class(unclass(my_class))
# [1] "numeric"

my_numeric <- unclass(my_class)

class(my_numeric)
# [1] "numeric"

abs(my_numeric)
# [1] 1

那么为什么abs(my_class)在定义Math.MyClass之前和之后都不会输出相同的结果(1)?

如果我将组通用定义为Math.MyClass,在定义Math.MyClass <- function(x) {NextMethod()}前后,我确实会收到相同的结果,但是拥有组通用的意义何在?

而且,为什么我在运行以下命令时在定义abs(my_matrix)之前和之后都得到Math.matrix相同的答案:

my_matrix <- matrix(data = -1:-10,ncol = 5) + 0.0

class(my_matrix)
# [1] "matrix"

class(my_matrix[1,1])
# [1] "numeric"

my_matrix
#      [,1] [,2] [,3] [,4] [,5]
# [1,]   -1   -3   -5   -7   -9
# [2,]   -2   -4   -6   -8  -10

abs(my_matrix)
#      [,]    1    3    5    7    9
# [2,]    2    4    6    8   10

Math.matrix <- function(x) { x }

abs(my_matrix)
#      [,]    2    4    6    8   10

当我运行以下命令时:

your_class <- structure(.Data = list(-1),class = "YourClass")

your_class
# [[1]]
# [1] -1
# 
# attr(,"class")
# [1] "YourClass"

abs(your_class)
# Error in abs(your_class) : non-numeric argument to mathematical function

class(unclass(your_class))
# [1] "list"

your_list <- list(-1)

class(your_list)
# [1] "list"

abs(your_list)
# Error in abs(your_list) : non-numeric argument to mathematical function

很明显class的{​​{1}}确实很重要(无论如何最初是因为),因为.Dataabs(your_class)都导致相同的错误。

为了使事情变得更具挑战性,我发现运行abs(your_list)后,MyClass个对象的一切都会恢复正常:

rm(Math.MyClass)

有人可以更完整地解释什么是组通用类(为什么组通用类存在/它们完成什么/它们与R对象的父子关系/为什么某些对象中的my_class # [1] -1 # attr(,"class") # [1] "MyClass" abs(my_class) # [1] -1 # attr(,"class") # [1] "MyClass" rm(Math.MyClass) abs(my_class) # [1] 1 # attr(,"class") # [1] "MyClass" 自变量在分组通用已定义,其他不是/等)?

如果您觉得使用Python实例更容易解释,那么我在Python中比在R中具有更多的OOP经验。任何帮助将不胜感激!

解决方法

组泛型允许您更改特定数据类型的一组功能的行为。最好的解释方法是看一些例子。如果您运行methods("Math"),将会看到哪些类定义了此功能。

对于Math.Date,您会看到

function (x,...) 
stop(gettextf("%s not defined for \"Date\" objects",.Generic),domain = NA)

所有要做的就是告诉您,所有这些函数都未为Date对象定义。例如

abs(as.Date("2020-01-01"))
# Error in Math.Date(as.Date("2020-01-01")) : 
#   abs not defined for "Date" objects

通过在组级别设置此行为,无需对Math组中所有函数的特殊版本进行编码即可告诉您它们并未为该类定义,因为它们不是“那样”的数字。但是,即使该列表中的trunc()可能会出现错误,但实际上仍然有效

trunc(as.Date("2020-01-01"))
[1] "2020-01-01"

那是因为定义了trunc.Date

function (x,...) 
round(x - 0.4999999)

因此,组泛型的特殊之处在于,您可以为常见的math-y函数定义默认的“后备”行为。但是,如果要更改该行为,仍然可以为特定功能提供特定于类的实现。

请注意,Math组中列出的所有那些函数都调用相同的Math.MyClass。该函数有一个变量可用于了解实际调用了哪个函数。该变量称为.Generic,并在?UseMethod帮助页面上进行了讨论。例如

Math.MyClass<- function(x) { paste(.Generic,x) }
abs(my_class)
# [1] "abs -1"
trunc(my_class)
# [1] "trunc -1"
exp(my_class)
# [1] "exp -1"

这希望可以清楚地表明,您不希望在不调度.Generic的情况下直接在其中进行任何转换。有关确实对某些函数类型进行分派的函数示例,请查看Math.difftime

function (x,...) 
{
    switch(.Generic,abs =,sign =,floor =,ceiling =,trunc =,round =,signif = {
            units <- attr(x,"units")
            .difftime(NextMethod(),units)
        },stop(gettextf("'%s' not defined for \"difftime\" objects",domain = NA))
}

您可以看到,对于特定的功能子集,它将为“常规”实现调度,否则会引发错误。

因此,当您定义

Math.MyClass <- function(x) { x }

基本上,您告诉R,您将处理该类对象对abs()的调用。而且,当您在实现中未更改地返回x时,您基本上只是返回了相同的对象,而没有执行任何操作。当您未定义Math.MyClass时,R会通过“常规”步骤来确定如何调用该函数。由于您没有提供自定义的“身份”功能,因此它会退回到默认的数字行为。

关于matrix行为为什么没有改变的原因,是因为my_matrix的类是隐式确定的。如果确实转储了对象,则会看到

dput(my_matrix)
# structure(
#     c(-1,-2,-3,-4,-5,-6,-7,-8,-9,-10),#     .Dim = c(2L,5L))

请注意,它不会像您的my_class对象那样将类存储在对象本身中

dput(my_class)
# structure(-1,class = "MyClass")

对于隐式类,分派发生的方式略有不同,它的分派更像是没有多余的类。基于类的调度检查对象上的class属性。请注意,这会有所不同

my_matrix2 <- structure(my_matrix,class="matrix")
# abs(my_matrix2)
#      [,1] [,2] [,3] [,4] [,5]
# [1,]   -1   -3   -5   -7   -9
# [2,]   -2   -4   -6   -8  -10
# attr(,"class")
# [1] "matrix"

您可以看到在这种情况下,Math.matrix被调用并且什么都没有改变。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-