gpt4 book ai didi

r - 了解自定义就地修改功能的代码?

转载 作者:行者123 更新时间:2023-12-04 04:24:46 24 4
gpt4 key购买 nike

我看到这个帖子:http://r.789695.n4.nabble.com/speeding-up-perception-tp3640920p3646694.html来自马特·道尔(Matt Dowle),早点讨论? data.table的实现思路包裹。

他使用以下代码:

x = list(a = 1:10000, b = 1:10000) 
class(x) = "newclass"
"[<-.newclass" = function(x,i,j,value) x # i.e. do nothing
tracemem(x)
x[1, 2] = 42L

具体我在看:
"[<-.newclass" = function(x,i,j,value) x

我试图了解那里做了什么以及我如何使用这个符号。

在我看来:
  • i 是行索引
  • j 是列索引
  • value 是要分配的值
  • x 是正在考虑的对象

  • 因此,我最好的猜测是我定义了一个用于就地修改的自定义函数(对于给定的类)。
    [<-.newclass正在为类 newclass 进行类修改。

    了解发生了什么:
    通常下面的代码应该返回一个错误:
    x = list(a = 1:10000, b = 1:10000) 
    x[1, 2] = 42L

    所以我猜示例代码没有任何实际用途。

    尝试使用逻辑:

    一个简单的无意义尝试是对要插入的值进行平方:
    x[i, j] <- value^2

    全试:
    > x = matrix(1:9, 3, 3)
    > class(x) = "newclass"
    > "[<-.newclass" = function(x, i, j, value) x[i, j] <- value^2 # i.e. do something
    > x[1, 2] = 9
    Error: C stack usage 19923536 is too close to the limit

    这似乎不起作用。

    我的问题:
    "[<-.newclass" = function(x,i,j,value) x 

    这个符号究竟是如何工作的,我将如何使用它?

    (我添加了 data.table 标签,因为链接的讨论是关于 data.table 中的“按引用”就地修改,我认为)。

    最佳答案

    `[<-`()函数(传统上)用于 subassignment ,更广泛地说,是一种 replacement function .它也是通用的(更具体地说,是 internal generic ),它允许您 write custom methods因为它,正如你正确推测的那样。

    替换功能

    一般来说,当你调用一个替换函数时,比如...

    foo(x) <- bar(y)

    ... <- 右侧的表达式(所以这里 bar(y) )作为命名的 value 被传递论据 `foo<-`()x作为第一个参数,对象 x用结果重新赋值:也就是说,上述调用相当于写:

    x <- `foo<-`(x, value = bar(y))

    所以为了工作,所有替换函数必须至少有两个参数,其中之一必须命名为 value .
    大多数替换函数只有这两个参数,但也有异常(exception):例如 `attr<-` 并且,通常,子分配。

    子任务

    当您接到类似 x[i, j] <- y 的子分配电话时, ij作为附加参数传递给 `[<-`()功能与 xy作为第一和 value参数分别为:

    x <- `[<-`(x, i, j, value = y) # x[i, j] <- y

    matrix 的情况下或 data.frame , ij将用于选择行和列;但总的来说,情况并非如此。自定义类的方法可以对参数做任何事情。考虑这个例子:

    x <- matrix(1:9, 3, 3)
    class(x) <- "newclass"

    `[<-.newclass` <- function(x, y, z, value) {
    x + (y - z) * value # absolute nonsense
    }

    x[1, 2] <- 9
    x
    #> [,1] [,2] [,3]
    #> [1,] -8 -5 -2
    #> [2,] -7 -4 -1
    #> [3,] -6 -3 0
    #> attr(,"class")
    #> [1] "newclass"

    这是有用的还是合理的?可能不是。但它是有效的 R 代码吗?绝对地!

    在实际应用中很少看到自定义子赋值方法,如 `[<-`()根据您的类的底层对象,通常“正常工作”正如您所期望的那样。一个值得注意的异常(exception)是 `[<-.data.frame` ,其中底层对象是一个列表,但子赋值的行为类似于矩阵。 (另一方面,许多类确实需要自定义子集方法,因为默认的 `[`() 方法会删除大多数属性,包括 class 属性,详情参见 ?`[`)。

    至于为什么你的例子不起作用:请记住,您正在为泛型函数编写方法,并且所有常规规则都适用。如果我们使用 `[<-`()的函数形式并在您的示例中展开方法 dispatch,我们可以立即看到它失败的原因:

    `[<-.newclass` <- function(x, i, j, value) {
    x <- `[<-.newclass`(x, i, j, value = value^2) # x[i, j] <- value^2
    }

    也就是说,函数是递归定义的,没有基本情况,导致无限循环。解决此问题的一种方法是 unclass(x)在调用下一个方法之前:

    `[<-.newclass` <- function(x, i, j, value) {
    x <- unclass(x)
    x[i, j] <- value^2
    x # typically you would also add the class back here
    }

    (或者,使用更高级的技术,也可以用显式的 next 方法替换主体,如下所示: NextMethod(value = value^2) 。这对继承和父类(super class)更有效。)

    只是为了验证它是否有效:

    x <- matrix(1:9, 3, 3)
    class(x) <- "newclass"

    x[1, 2] <- 9
    x
    #> [,1] [,2] [,3]
    #> [1,] 1 81 7
    #> [2,] 2 5 8
    #> [3,] 3 6 9

    完全困惑!

    至于 Dowle 的“什么都不做”子赋值示例的上下文,我相信这是为了说明早在 R 2.13.0 中,自定义子赋值方法总是会导致创建对象的深拷贝,即使该方法本身做了什么都没有。 (情况不再如此,因为我相信 R 3.1.0。)

    创建于 2018-08-15 由 reprex package (v0.2.0)。

    关于r - 了解自定义就地修改功能的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51769745/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com