微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

实现并行属性 vctrs 类

如何解决实现并行属性 vctrs 类

我正在尝试使用存储表达式的 vctrs 包创建一个向量类。主要是因为我想在不同的 vctrs 向量中使用它。表达式不是向量类型,因此向量表达式(此处名为 vexpr)的简单实现会失败。

library(vctrs)

expr <- scales::math_format()(1:10)

new_vexpr <- function(x) {
  new_vctr(x,class = 'vexpr')
}

new_vexpr(expr)
#> Error: `.data` must be a vector type.

所以,我想,也许我可以将表达式本身实现为与向量并行的属性

new_vexpr <- function(x) {
  if (!is.expression(x)) {
    stop()
  }
  new_vctr(seq_along(x),expr = x,class = "vexpr")
}

format.vexpr <- function(x,...) {
  ifelse(is.na(vec_data(x)),NA,format(as.list(attr(x,"expr"))))
}

# Works!
x <- new_vexpr(expr)

我很快就遇到了麻烦,因为我还没有实现样板 vec_ptype2()vec_cast() 方法

# Looks like it might work
c(x,x)
#> <vexpr[20]>
#>  [1] 10^1L  10^2L  10^3L  10^4L  10^5L  10^6L  10^7L  10^8L  10^9L  10^10L
#> [11] 10^1L  10^2L  10^3L  10^4L  10^5L  10^6L  10^7L  10^8L  10^9L  10^10L

# Expression not concatenated (as might be expected)
attr(c(x,x),"expr")
#> expression(10^1L,10^2L,10^3L,10^4L,10^5L,10^6L,10^7L,10^8L,#>     10^9L,10^10L)

所以我尝试实现样板方法

vec_ptype2.vexpr.vexpr <- function(x,y,...) {
  new <- c(attr(x,"expr"),attr(y,"expr"))
  new_vctr(integer(0),expr = new,class = "vexpr")
}

vec_cast.vexpr.vexpr <- function(x,to,...) {
  new_vctr(vec_data(x),expr = attr(to,class = "vexpr")
}

这有助于连接向量,但返回错误的子集结果。

# Expression is concatenated!
attr(c(x,10^10L,10^1L,#>     10^7L,10^9L,10^10L)

# Subsetting doesn't make sense,should be 10^2L
x[2]
#> <vexpr[1]>
#> [1] 10^1L

# Turns out,full expression still there
attr(x[2],10^10L)

很好,所以我在 vctrs 系统之外定义了我自己的子集方法,这最初似乎有效。

# Define S3 subsetting method
`[.vexpr` <- function(x,i,...) {
  expr <- attr(x,"expr")
  ii <- vec_as_location(i,length(expr),names = names(x),missing = "propagate")
  
  new_vctr(vec_data(x)[ii],expr = expr[ii],class = "vexpr")
}

# Subsetting works!
x[2]
#> <vexpr[1]>
#> [1] 10^2L

# Seemingly sensible concatenation
c(x[2],NA)
#> <vexpr[2]>
#> [1] 10^2L <NA>

但也开始产生荒谬的结果。

# expr is duplicated? would have liked the 2nd expression to be `expression(NA)`
attr(c(x[2],NA),"expr")
#> expression(10^2L,10^2L)

reprex package (v0.3.0) 于 2021 年 1 月 18 日创建

显然,我在这里做错了某事,但我还没有成功调试这个问题。我还尝试为 vec_restore() 实现 vexpr 方法,但这让我更加困惑。你在某处看到过并行属性 vctrs 的很好的实现吗?你知道我可能做错了什么吗?

此处的相关问题:How do I build an object with the R vctrs package that can combine with c()(将 vctrs 与属性连接)

此处的相关讨论:https://github.com/r-lib/vctrs/issues/559

编辑:我不喜欢并行属性的想法。如果 vec_data(x)attr(x,"expr") 的索引,那也可以,但我也没有做到这一点。

EDIT2:将表达式包装在调用列表中似乎很适合一切。但是,我仍然对并行属性/索引属性的稳定性感兴趣。列表包装示例(似乎所有方法都可以正常工作!):

new_vexpr <- function(x) {
  if (!is.expression(x)) {
    x <- as.expression(x)
    if (!is.expression(x)) {
      stop()
    }
  }
  x <- as.list(x)
  new_vctr(x,class = "vexpr")
}

as.expression.vexpr <- function(x) {
  do.call(expression,vec_data(x))
}

解决方法

您可以将表达式包含在列表中:

library(vctrs)

expr <- scales::math_format()(1:10)

new_vexpr <- function(x) {
  new_vctr(list(x),class = 'vexpr')
}

res <- c(new_vexpr(expr),new_vexpr(expr))
res
#> <vexpr[2]>
#> [1] expression(10^1L,10^2L,10^3L,10^4L,10^5L,10^6L,10^7L,10^8L,10^9L,10^10L)
#> [2] expression(10^1L,10^10L)

res[2]
#> <vexpr[1]>
#> [1] expression(10^1L,10^10L)

reprex package (v0.3.0) 于 2021 年 1 月 21 日创建

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