簡體   English   中英

返回數據框作為主要結果,但也返回信息列表作為副作用

[英]Returning data frame as main result but also informative list as side effect

我正在寫一個 function ,我希望主要的 output 成為一個數據框(可以通過管道傳輸到其他函數),但我也希望允許用戶訪問信息列表或最終結果中省略的樣本向量. 是否有關於如何 go 的最佳實踐,或者可以很好地做到這一點的函數/包的示例?

目前我正在探索將信息作為屬性返回並發出警告,通知用戶他們可以使用attr(resulting-df, "omitted")訪問列表

任何建議將不勝感激,謝謝!

library(dplyr)

iris <- iris %>%
  mutate(index = 1:nrow(.))

return_filtered <- function(df) {

  res <- filter(df, Sepal.Length > 6)
  omitted <- setdiff(iris$index, res$index)

  attr(res, "omitted") <- omitted
  return(res)

}

iris2 <- return_filtered(iris)
attributes(iris2)
#> $names
#> [1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"     
#> [6] "index"       
#> 
#> $class
#> [1] "data.frame"
#> 
#> $row.names
#>  [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#> [26] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
#> [51] 51 52 53 54 55 56 57 58 59 60 61
#> 
#> $omitted
#>  [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18  19
#> [20]  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36  37  38
#> [39]  39  40  41  42  43  44  45  46  47  48  49  50  54  56  58  60  61  62  63
#> [58]  65  67  68  70  71  79  80  81  82  83  84  85  86  89  90  91  93  94  95
#> [77]  96  97  99 100 102 107 114 115 120 122 139 143 150

reprex package (v2.0.1) 創建於 2022-04-02

這個問題可能有點基於意見,但我認為這不是題外話,因為肯定有比當前方法更簡潔、更正式的方法來實現你想要的。

將額外信息作為屬性保存是合理的,但如果你打算這樣做,那么創建一個 S3 class 更符合習慣和可擴展性,這樣你就可以隱藏屬性的默認打印,確保你的屬性受到保護,並定義屬性的 getter function,這樣用戶就不必篩選多個屬性來獲得正確的屬性。

首先,我們將調整您的 function 以使用任何數據框,並允許它采用任何謂詞,以便它按預期與dplyr::filter一起工作。 我們還得到 function 添加到返回對象的 class 屬性中,以便它返回一個新的 S3 object 繼承自data.frame

return_filtered <- function(df, predicate) {
  predicate    <- rlang::enquo(predicate)
  df$`..id..`  <- seq(nrow(df))
  res          <- dplyr::filter(df, !!predicate)
  filtered     <- setdiff(seq(nrow(df)), res$`..id..`)
  res$`..id..` <- NULL
  
  attr(res, "filtered") <- filtered
  class(res)            <- c("filtered", class(df))
  
  return(res)
}

我們將定義一個打印方法,以便在打印 object 時不顯示屬性:

print.filtered <- function(x, ...) {
  class(x) <- class(x)[class(x) != "filtered"]
  print(x, ...)
}

為了從屬性中獲取過濾掉的數據,我們可以創建一個新的通用 function,它只適用於我們的新 class:

get_filtered <- function(x) UseMethod("get_filtered")

get_filtered.default <- function(x) {
  stop("'get_filtered' only works on filtered objects")
}

get_filtered.filtered <- function(x) {
  attr(x, "filtered")
}

所以現在,當我們調用return_filtered時,它似乎與dplyr::filter一樣工作,返回看似正常的數據框:

df <- return_filtered(iris, Sepal.Length > 7)

df
#>    Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
#> 1           7.1         3.0          5.9         2.1 virginica
#> 2           7.6         3.0          6.6         2.1 virginica
#> 3           7.3         2.9          6.3         1.8 virginica
#> 4           7.2         3.6          6.1         2.5 virginica
#> 5           7.7         3.8          6.7         2.2 virginica
#> 6           7.7         2.6          6.9         2.3 virginica
#> 7           7.7         2.8          6.7         2.0 virginica
#> 8           7.2         3.2          6.0         1.8 virginica
#> 9           7.2         3.0          5.8         1.6 virginica
#> 10          7.4         2.8          6.1         1.9 virginica
#> 11          7.9         3.8          6.4         2.0 virginica
#> 12          7.7         3.0          6.1         2.3 virginica

但是我們可以使用get_filtered function 從中獲取過濾掉的數據。

get_filtered(df)
#>   [1]   1   2   3   4   5   6   7   8   9  10  11  12  13  14  15  16  17  18
#>  [19]  19  20  21  22  23  24  25  26  27  28  29  30  31  32  33  34  35  36
#>  [37]  37  38  39  40  41  42  43  44  45  46  47  48  49  50  51  52  53  54
#>  [55]  55  56  57  58  59  60  61  62  63  64  65  66  67  68  69  70  71  72
#>  [73]  73  74  75  76  77  78  79  80  81  82  83  84  85  86  87  88  89  90
#>  [91]  91  92  93  94  95  96  97  98  99 100 101 102 104 105 107 109 111 112
#> [109] 113 114 115 116 117 120 121 122 124 125 127 128 129 133 134 135 137 138
#> [127] 139 140 141 142 143 144 145 146 147 148 149 150

在未過濾的數據幀上調用get_filtered返回信息性錯誤:

get_filtered(iris)
#> Error in get_filtered.default(iris): 'get_filtered' only works on filtered objects

reprex package (v2.0.1) 創建於 2022-04-02

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM