如何在R6中正确编写类方法并链接它们

发布于 2025-01-25 11:16:37 字数 876 浏览 3 评论 0原文

我需要创建自己的类对象,该对象采用数据框并具有方法“ get_data”来选择数据框架, “选择”以通过其名称选择列和“滤镜”以用某些值过滤行。 选择和过滤器与Dplyr相似,但不使用DPLYR。

我希望他们可以这样链接:

result <- df_object$get_data(df)$select(col1, col2, period)$filter(period)

我该怎么做,以使“过滤器”方法可以过滤已经选择的值?现在它过滤初始数据集。另外,如何更改方法,以使选择和过滤不需要数据参数?请给我一些提示,我觉得我这样做的方法是错误的。 Do I need to add some fields to 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), ])

I need to create my own class object that takes a dataframe and has methods 'get_data' to choose dataframe,
'select' to select columns by their names and 'filter' to filter rows with certain values.
Select and filter are a kind of similar to dplyr, but without using dplyr.

I would like they could be chained like this:

result <- df_object$get_data(df)$select(col1, col2, period)$filter(period)

What can I do so that 'filter' method would filter already selected values? Now it filters initial dataset. Also how to change methods so that select and filter wouldn't need data argument? Please give me some tips, I feel like I'm doing it a wrong way. Do I need to add some fields to 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), ])

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

究竟谁懂我的在乎 2025-02-01 11:16:37

如果要链成员函数,则需要这些成员功能才能返回self。这意味着R6对象必须修改其包含的数据。由于R6的好处是减少副本,因此我可能会保留数据的完整副本,并具有select_funcfilter_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
  })
)

这允许我们要链过滤器并选择方法:

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

并且我们的选择方法也可以采用名称:

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

为了完整性,您需要某种类型的安全性,我还将添加一个重置方法来删除所有过滤。这有效地为您提供了一个数据框架,其中过滤和选择是无损的,这实际上可能非常有用。

If you want to chain member functions, you need those member functions to return self. This means that the R6 object has to modify the data it contains. Since the benefit of R6 is to reduce copies, I would probably keep a full copy of the data, and have select_func and filter_func update some row and column indices:

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
  })
)

This allows us to chain the filter and select methods:

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

and our select method can take names too:

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

For completeness, you need some type safety, and I would also add a reset method to remove all filtering. This effectively gives you a data frame where the filtering and selecting are non-destructive, which could actually be very useful.

Created on 2022-05-01 by the reprex package (v2.0.1)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文