跳到内容

扩展数组是常规 Arrow Array 对象的包装器,提供一些自定义的行为和/或存储。 扩展类型的一个常见用例是定义 Arrow Array 和 R 对象之间的自定义转换,当默认转换速度慢或丢失对数组中值的解释很重要的元数据时。 对于大多数类型,内置的 vctrs 扩展类型 可能就足够了。

用法

new_extension_type(
  storage_type,
  extension_name,
  extension_metadata = raw(),
  type_class = ExtensionType
)

new_extension_array(storage_array, extension_type)

register_extension_type(extension_type)

reregister_extension_type(extension_type)

unregister_extension_type(extension_name)

参数

storage_type

底层存储数组的数据类型

extension_name

扩展名。 这应该使用“点”语法进行命名空间(即,“some_package.some_type”)。 命名空间“arrow”保留给 Apache Arrow 库定义的扩展类型。

extension_metadata

一个包含类型序列化版本的 raw()character() 向量。 字符向量的长度必须为 1,并且在转换为 raw() 之前转换为 UTF-8。

type_class

一个 R6::R6Class,其 $new() 类方法将用于构造该类型的新实例。

storage_array

底层存储的 Array 对象。

extension_type

一个 ExtensionType 实例。

返回值

  • new_extension_type() 根据指定的 type_class 返回一个 ExtensionType 实例。

  • new_extension_array() 返回一个 ExtensionArray,其 $type 对应于 extension_type

  • register_extension_type()unregister_extension_type()reregister_extension_type() 返回 NULL,不可见。

详情

这些函数创建、注册和取消注册 ExtensionTypeExtensionArray 对象。 要使用扩展类型,您必须

  • 定义一个继承自 ExtensionTypeR6::R6Class 并重新实现一个或多个方法(例如,deserialize_instance())。

  • 创建一个类型构造函数(例如,my_extension_type()),该函数调用 new_extension_type() 以创建一个 R6 实例,该实例可以在包中的其他位置用作 数据类型

  • 创建一个数组构造函数(例如,my_extension_array()),该函数调用 new_extension_array() 以创建您的扩展类型的 Array 实例。

  • 使用 register_extension_type() 注册使用构造函数函数创建的扩展类型的虚拟实例。

如果在 R 包中定义扩展类型,您可能需要在该包的 .onLoad() 钩子中使用 reregister_extension_type(),因为您的包可能会在其开发过程中在同一 R 会话中重新加载,并且如果为相同的 extension_name 调用两次 register_extension_type() 将会出错。 有关使用这些功能中的大多数功能的扩展类型的示例,请参阅 vctrs_extension_type()

示例

# Create the R6 type whose methods control how Array objects are
# converted to R objects, how equality between types is computed,
# and how types are printed.
QuantizedType <- R6::R6Class(
  "QuantizedType",
  inherit = ExtensionType,
  public = list(
    # methods to access the custom metadata fields
    center = function() private$.center,
    scale = function() private$.scale,

    # called when an Array of this type is converted to an R vector
    as_vector = function(extension_array) {
      if (inherits(extension_array, "ExtensionArray")) {
        unquantized_arrow <-
          (extension_array$storage()$cast(float64()) / private$.scale) +
          private$.center

        as.vector(unquantized_arrow)
      } else {
        super$as_vector(extension_array)
      }
    },

    # populate the custom metadata fields from the serialized metadata
    deserialize_instance = function() {
      vals <- as.numeric(strsplit(self$extension_metadata_utf8(), ";")[[1]])
      private$.center <- vals[1]
      private$.scale <- vals[2]
    }
  ),
  private = list(
    .center = NULL,
    .scale = NULL
  )
)

# Create a helper type constructor that calls new_extension_type()
quantized <- function(center = 0, scale = 1, storage_type = int32()) {
  new_extension_type(
    storage_type = storage_type,
    extension_name = "arrow.example.quantized",
    extension_metadata = paste(center, scale, sep = ";"),
    type_class = QuantizedType
  )
}

# Create a helper array constructor that calls new_extension_array()
quantized_array <- function(x, center = 0, scale = 1,
                            storage_type = int32()) {
  type <- quantized(center, scale, storage_type)
  new_extension_array(
    Array$create((x - center) * scale, type = storage_type),
    type
  )
}

# Register the extension type so that Arrow knows what to do when
# it encounters this extension type
reregister_extension_type(quantized())

# Create Array objects and use them!
(vals <- runif(5, min = 19, max = 21))
#> [1] 20.42644 20.32484 20.21635 20.83541 19.04193

(array <- quantized_array(
  vals,
  center = 20,
  scale = 2^15 - 1,
  storage_type = int16()
)
)
#> ExtensionArray
#> <QuantizedType <20;32767>>
#> [
#>   13973,
#>   10643,
#>   7089,
#>   27373,
#>   -31393
#> ]

array$type$center()
#> [1] 20
array$type$scale()
#> [1] 32767

as.vector(array)
#> [1] 20.42644 20.32481 20.21635 20.83538 19.04193