【问题标题】:Does dplyr::mutate work with record-style columns?dplyr::mutate 是否适用于记录样式的列?
【发布时间】:2020-01-14 04:54:41
【问题描述】:

我最近一直在测试 vctrs 包,尤其是最近他们所谓的“记录样式”对象,我想知道是否有任何方法可以让它们与 dplyr::mutate 配合使用。目前,当 dplyr::mutate 在我尝试使用对象时给我一个关于对象长度的错误。

我不知道合适的内置类型,因此我将使用this vignette 中描述的理性类。

library("vctrs")
library("dplyr")
new_rational <- function(n = integer(), d = integer()) {
  vec_assert(n, ptype = integer())
  vec_assert(d, ptype = integer())

  new_rcrd(list(n = n, d = d), class = "vctrs_rational")
}

format.vctrs_rational <- function(x, ...) {
  n <- field(x, "n")
  d <- field(x, "d")

  out <- paste0(n, "/", d)
  out[is.na(n) | is.na(d)] <- NA

  out
}

到目前为止一切都很好,但是当我尝试使用 dplyr::mutate 创建一个有理数列时,我收到了一个错误

df <- data.frame(n = c(1L, 2L, 3L), d = 2L)
df %>% dplyr::mutate(frac = new_rational(n, d))
#> Error: Column `frac` must be length 3 (the number of rows) or one, not 2

但是在基础 R 中创建列就可以了:

df$rational <- new_rational(df$n, df$d)
df
#>   n d rational
#> 1 1 2      1/2
#> 2 2 2      2/2
#> 3 3 2      3/2

是否有一些技巧可以使用 dplyr::mutate 让它工作,或者这是不可能的?

【问题讨论】:

  • 将它们存储为列表,df %&gt;% dplyr::mutate(frac = as.list(new_rational(n, d)))

标签: r dplyr vctrs


【解决方案1】:

new_rational 以列表格式返回输出,如下所示

> typeof(new_rational(n=1L, d=2L))
[1] "list"

所以,我们可以使用mapas.list“@Ronak 的建议”将输出作为列表,然后使用unnest

df %>% dplyr::mutate(frac = purrr::map2(n,d, ~new_rational(.x, .y))) %>% 
       tidyr::unnest(cols=c(frac))
# A tibble: 3 x 3
      n     d       frac
  <int> <int> <vctrs_rt>
1     1     2        1/2
2     2     2        2/2
3     3     2        3/2

【讨论】:

  • new_rational 矢量化的。 new_rational(df$n, df$d) 工作。
  • @RonakShah 抱歉,我想我误解了这个概念。现在我看到在 mutate 中使用 as.listlistrowwise 之间的区别@
【解决方案2】:

从 vctrs 0.3.6 / R 4.0.3 开始,您的代表按预期工作:

library("vctrs")
library("dplyr")
new_rational <- function(n = integer(), d = integer()) {
  vec_assert(n, ptype = integer())
  vec_assert(d, ptype = integer())
  
  new_rcrd(list(n = n, d = d), class = "vctrs_rational")
}

format.vctrs_rational <- function(x, ...) {
  n <- field(x, "n")
  d <- field(x, "d")
  
  out <- paste0(n, "/", d)
  out[is.na(n) | is.na(d)] <- NA
  
  out
}

df <- data.frame(n = c(1L, 2L, 3L), d = 2L)
df %>% dplyr::mutate(frac = new_rational(n, d))
#>   n d frac
#> 1 1 2  1/2
#> 2 2 2  2/2
#> 3 3 2  3/2

reprex package (v0.3.0) 于 2021 年 2 月 3 日创建

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    • 2018-04-30
    • 1970-01-01
    • 2018-02-18
    • 2019-09-16
    • 1970-01-01
    相关资源
    最近更新 更多