扩展数组是围绕常规 Arrow 数组 对象的包装器,提供了一些自定义行为和/或存储。扩展类型的一个常见用例是定义 Arrow 数组 和 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
底层存储的 数组 对象。
- extension_type
一个 扩展类型 实例。
详情
这些函数创建、注册和注销 扩展类型 和 扩展数组 对象。要使用扩展类型,您必须
定义一个继承自 扩展类型 的 R6::R6Class 并重新实现一个或多个方法(例如,
deserialize_instance()
)。创建一个类型构造函数(例如,
my_extension_type()
),该函数调用new_extension_type()
来创建一个 R6 实例,该实例可以在包的其他地方用作 数据类型。创建一个数组构造函数(例如,
my_extension_array()
),该函数调用new_extension_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