如何在 R6 中正确编写 class 方法并将它们链接起来
How to correctly write class methods in R6 and chain them
我需要创建自己的 class 对象,该对象采用数据框并具有选择数据框的方法 'get_data',
'select' 到 select 列按名称和 'filter' 过滤具有特定值的行。
Select和filter是一种类似于dplyr的方法,但是没有使用dplyr。
我希望它们可以这样链接:
result <- df_object$get_data(df)$select(col1, col2, period)$filter(period)
我该怎么做才能让 'filter' 方法过滤已经 select 的值?现在它过滤初始数据集。另外如何更改方法以使 select 和过滤器不需要数据参数?请给我一些提示,我觉得我做错了。我需要向 class 添加一些字段吗?
dataFrame <- R6Class("dataFrame",
list(data = "data.frame"),
public = list(
get_data = function(data) {data},
select_func = function(data, columns) {data[columns]},
filter_func = function(data, var) {data[var, ]}
))
# Create new object
df_object <- dataFrame$new()
# Call methods
df_object$get_data(df)
df_object$select_func(df, c("month", "forecast"))
df_object$filter_func(df[df$month %in% c(1, 2), ])
如果要链接成员函数,则需要将这些成员函数链接到 return self
。这意味着 R6 对象必须修改它包含的数据。由于 R6 的好处是减少副本,我可能会保留数据的完整副本,并让 select_func
和 filter_func
更新一些行和列索引:
library(R6)
dataFrame <- R6Class("dataFrame",
public = list(
data = data.frame(),
rows = 0,
columns = 0,
initialize = function(data) {
self$data <- data
self$rows <- seq(nrow(data))
self$columns <- seq_along(data)
},
get_data = function() {self$data[self$columns][self$rows,]},
select_func = function(cols) {
if(is.character(cols)) cols <- match(cols, names(self$data))
self$columns <- cols
self
},
filter_func = function(r) {
if(is.logical(r)) r <- which(r)
self$rows <- r
self
})
)
这允许我们链接过滤器和 select 方法:
dataFrame$new(iris)$filter_func(1:5)$select_func(1:2)$get_data()
#> Sepal.Length Sepal.Width
#> 1 5.1 3.5
#> 2 4.9 3.0
#> 3 4.7 3.2
#> 4 4.6 3.1
#> 5 5.0 3.6
我们的 select 方法也可以取名字:
dataFrame$new(mtcars)$select_func(c("mpg", "wt"))$get_data()
#> mpg wt
#> Mazda RX4 21.0 2.620
#> Mazda RX4 Wag 21.0 2.875
#> Datsun 710 22.8 2.320
#> Hornet 4 Drive 21.4 3.215
#> Hornet Sportabout 18.7 3.440
#> Valiant 18.1 3.460
#> Duster 360 14.3 3.570
#> Merc 240D 24.4 3.190
#> Merc 230 22.8 3.150
#> Merc 280 19.2 3.440
#> Merc 280C 17.8 3.440
#> Merc 450SE 16.4 4.070
#> Merc 450SL 17.3 3.730
#> Merc 450SLC 15.2 3.780
#> Cadillac Fleetwood 10.4 5.250
#> Lincoln Continental 10.4 5.424
#> Chrysler Imperial 14.7 5.345
#> Fiat 128 32.4 2.200
#> Honda Civic 30.4 1.615
#> Toyota Corolla 33.9 1.835
#> Toyota Corona 21.5 2.465
#> Dodge Challenger 15.5 3.520
#> AMC Javelin 15.2 3.435
#> Camaro Z28 13.3 3.840
#> Pontiac Firebird 19.2 3.845
#> Fiat X1-9 27.3 1.935
#> Porsche 914-2 26.0 2.140
#> Lotus Europa 30.4 1.513
#> Ford Pantera L 15.8 3.170
#> Ferrari Dino 19.7 2.770
#> Maserati Bora 15.0 3.570
#> Volvo 142E 21.4 2.780
为了完整起见,您需要一些类型安全,我还会添加一个重置方法来删除所有过滤。这有效地为您提供了一个数据框,其中过滤和 selecting 是 non-destructive,这实际上可能非常有用。
由 reprex package (v2.0.1)
创建于 2022-05-01
我需要创建自己的 class 对象,该对象采用数据框并具有选择数据框的方法 'get_data', 'select' 到 select 列按名称和 'filter' 过滤具有特定值的行。 Select和filter是一种类似于dplyr的方法,但是没有使用dplyr。
我希望它们可以这样链接:
result <- df_object$get_data(df)$select(col1, col2, period)$filter(period)
我该怎么做才能让 'filter' 方法过滤已经 select 的值?现在它过滤初始数据集。另外如何更改方法以使 select 和过滤器不需要数据参数?请给我一些提示,我觉得我做错了。我需要向 class 添加一些字段吗?
dataFrame <- R6Class("dataFrame",
list(data = "data.frame"),
public = list(
get_data = function(data) {data},
select_func = function(data, columns) {data[columns]},
filter_func = function(data, var) {data[var, ]}
))
# Create new object
df_object <- dataFrame$new()
# Call methods
df_object$get_data(df)
df_object$select_func(df, c("month", "forecast"))
df_object$filter_func(df[df$month %in% c(1, 2), ])
如果要链接成员函数,则需要将这些成员函数链接到 return self
。这意味着 R6 对象必须修改它包含的数据。由于 R6 的好处是减少副本,我可能会保留数据的完整副本,并让 select_func
和 filter_func
更新一些行和列索引:
library(R6)
dataFrame <- R6Class("dataFrame",
public = list(
data = data.frame(),
rows = 0,
columns = 0,
initialize = function(data) {
self$data <- data
self$rows <- seq(nrow(data))
self$columns <- seq_along(data)
},
get_data = function() {self$data[self$columns][self$rows,]},
select_func = function(cols) {
if(is.character(cols)) cols <- match(cols, names(self$data))
self$columns <- cols
self
},
filter_func = function(r) {
if(is.logical(r)) r <- which(r)
self$rows <- r
self
})
)
这允许我们链接过滤器和 select 方法:
dataFrame$new(iris)$filter_func(1:5)$select_func(1:2)$get_data()
#> Sepal.Length Sepal.Width
#> 1 5.1 3.5
#> 2 4.9 3.0
#> 3 4.7 3.2
#> 4 4.6 3.1
#> 5 5.0 3.6
我们的 select 方法也可以取名字:
dataFrame$new(mtcars)$select_func(c("mpg", "wt"))$get_data()
#> mpg wt
#> Mazda RX4 21.0 2.620
#> Mazda RX4 Wag 21.0 2.875
#> Datsun 710 22.8 2.320
#> Hornet 4 Drive 21.4 3.215
#> Hornet Sportabout 18.7 3.440
#> Valiant 18.1 3.460
#> Duster 360 14.3 3.570
#> Merc 240D 24.4 3.190
#> Merc 230 22.8 3.150
#> Merc 280 19.2 3.440
#> Merc 280C 17.8 3.440
#> Merc 450SE 16.4 4.070
#> Merc 450SL 17.3 3.730
#> Merc 450SLC 15.2 3.780
#> Cadillac Fleetwood 10.4 5.250
#> Lincoln Continental 10.4 5.424
#> Chrysler Imperial 14.7 5.345
#> Fiat 128 32.4 2.200
#> Honda Civic 30.4 1.615
#> Toyota Corolla 33.9 1.835
#> Toyota Corona 21.5 2.465
#> Dodge Challenger 15.5 3.520
#> AMC Javelin 15.2 3.435
#> Camaro Z28 13.3 3.840
#> Pontiac Firebird 19.2 3.845
#> Fiat X1-9 27.3 1.935
#> Porsche 914-2 26.0 2.140
#> Lotus Europa 30.4 1.513
#> Ford Pantera L 15.8 3.170
#> Ferrari Dino 19.7 2.770
#> Maserati Bora 15.0 3.570
#> Volvo 142E 21.4 2.780
为了完整起见,您需要一些类型安全,我还会添加一个重置方法来删除所有过滤。这有效地为您提供了一个数据框,其中过滤和 selecting 是 non-destructive,这实际上可能非常有用。
由 reprex package (v2.0.1)
创建于 2022-05-01