能否将dataframe对象转换为tribble构造函数?

16

我有这样的数据:

library(tidyverse)
df <- tibble(
    x = c(0, 179, 342, 467, 705, 878, 1080, 1209, 1458, 1639, 1805, 2000, 2121, 2339, 2462, 2676, 
      2857, 3049, 3227, 3403, 3583, 3651, 4009, 4034, 4151, 4194, 4512, 4523, 4679, 5789), 
    y = c(4.7005, 4.8598, 5.0876, 5.0938, 5.3891, 5.6095, 5.8777, 6.0064, 6.3063, 6.4723, 6.6053, 
          6.8145, 6.9078, 7.1701, 7.2633, 7.3865, 7.5766, 7.644, 7.8018, 7.9505, 8.0974, 8.1937, 
          8.2391, 8.294, 8.3143, 8.3452, 8.5092, 8.5172, 8.5993, 9.0275))

我是否可以将我的数据框/ tibble 对象转换为一个tribble“构造函数”?

我正在寻找类似于dput的东西,但更轻巧,并专门用于数据框。


3
包含大量功能,但操作迅速:clipr::write_clip(df); datapasta::tribble_paste() - alistaire
2
如果有人想要提交PR,这是GitHub上一个开放问题的主题:https://github.com/tidyverse/tibble/issues/127 - alistaire
@alistaire,我已经在tibble的分支上放了我的实现版本 - 请看下面的答案。 - Nick Kennedy
7个回答

22

datapasta::dpasta() 应该是合适的。来自您示例的输出:

dpasta(df)
tibble::tribble(
    ~x,     ~y,
     0, 4.7005,
   179, 4.8598,
   342, 5.0876,
   467, 5.0938,
   705, 5.3891,
   878, 5.6095,
  1080, 5.8777,
  1209, 6.0064,
  1458, 6.3063,
  1639, 6.4723,
  1805, 6.6053,
  2000, 6.8145,
  2121, 6.9078,
  2339, 7.1701,
  2462, 7.2633,
  2676, 7.3865,
  2857, 7.5766,
  3049,  7.644,
  3227, 7.8018,
  3403, 7.9505,
  3583, 8.0974,
  3651, 8.1937,
  4009, 8.2391,
  4034,  8.294,
  4151, 8.3143,
  4194, 8.3452,
  4512, 8.5092,
  4523, 8.5172,
  4679, 8.5993,
  5789, 9.0275
  )

https://cran.r-project.org/web/packages/datapasta/index.html https://github.com/MilesMcBain/datapasta


这是唯一一个对于包含引号(例如json)的字符串列实际上对我起作用的方法。 - Stefan F

13

我认为mc_tribble是一个更好的名称,并且你似乎可以将其压缩成:

mc_tribble <- function(indf, indents = 4, mdformat = TRUE) {
  name <- as.character(substitute(indf))
  name <- name[length(name)]

  meat <- capture.output(write.csv(indf, quote = TRUE, row.names = FALSE))
  meat <- paste0(
    paste(rep(" ", indents), collapse = ""),
    c(paste(sprintf("~%s", names(indf)), collapse = ", "),
      meat[-1]))

  if (mdformat) meat <- paste0("    ", meat)
  obj <- paste(name, " <- tribble(\n", paste(meat, collapse = ",\n"), ")", sep = "")
  if (mdformat) cat(paste0("    ", obj)) else cat(obj)
}

试一试:

short_iris <- head(iris)

mc_tribble(short_iris)

改进:

  • 代码更短
  • 捕获“tibble”的名称
  • 增加了缩进的参数
  • 增加了一个参数,方便在Stack Overflow上添加4个空格
  • 听起来更美味

我已将此添加到我的"SOfun"包中。您可以使用以下命令进行安装:

source("http://news.mrdwab.com/install_github.R")
install_github("mrdwab/overflow-mrdwab") # for writeClip -- plus it's awesome
install_github("mrdwab/SOfun")

使用方法非常简单:

library(SOfun)
mc_tribble(short_iris)

优点:

  • 现在会将输出内容复制到您的剪贴板中(如果您已安装“overflow”插件)
  • 比以前更加实惠!

这太棒了。你认为有没有一种简单的方法来扩展它以保留列类型?(例如带字符的列z?) - emehex
@emehex,现在就试一下。 - A5C1D2H2I1M1N2O1R2T1
1
现在,我们能否请您简要介绍一下什么是Tribble? - David Arenburg
这太棒了 @A5C1D2H2I1M1N2O1R2T1。我会向 tidyverse 包提交一个 PR,就像 alistaire 链接的那样。 - emehex
1
@emehex,安装overflow,然后安装SOfun,你就可以使用 library(SOfun); mc_tribble(iris) :-) - A5C1D2H2I1M1N2O1R2T1

2
根据Kirill的评论,现在这已经是一个包的一部分:https://github.com/krlmlr/deparse,它在函数deparsec中实现。
library(deparse)
#> 
#> Attaching package: 'deparse'
#> The following object is masked from 'package:base':
#> 
#>     deparse
library(tibble)

# dataframe
df <- tribble(
  ~a, ~b, ~c,
  1L, 0.1, "a"
)

# tribble script
deparsec(df, as_tribble = TRUE)
#> tribble(
#>   ~a, ~b,  ~c, 
#>   1L, 0.1, "a"
#> )

创建于2018年08月09日,使用reprex包 (v0.2.0)。

似乎 deparse 已经消失了。 - DHW
1
不确定我是否理解 -- devtools::install_github("krlmlr/deparse") 仍然可以安装。 - shiro
哦,我错过了Github的链接。我刚刚看到它已经从CRAN上移除了。 - DHW

2

我受到了@A5C1D2H2I1M1N2O1R2T1的启发,创建了一个更为全面的解决方案。它可以处理大多数标准列类型,包括字符、因子、整数、数字、逻辑和列表。它还采用了dput的语法,关于第二个参数,所以应该能够输出到文件、连接或(默认情况下)控制台。它还采用了dput的标准返回值,即其输入,不可见。

dput_to_var <- function(x) {
  con <- textConnection("out", "w", local = TRUE)
  dput(x, con)
  close(con)
  paste(out, collapse = "")
}

dput_tribble <- function(indf, file = "") {
  stopifnot(is.data.frame(indf))
  cols <- lapply(indf, function(col) {
    switch(class(col),
           factor =, character = paste0("\"", col, "\""),
           logical =, numeric =, integer = col,
           list = lapply(col, dput_to_var)
           )
  })
  meat <- c(paste(sprintf("~%s", names(indf)), collapse = ", "),
            do.call(paste, c(cols, sep = ", ")))
  out <- paste0("tribble(\n", paste(meat, collapse = ",\n"), ")")
  if (is.character(file)) {
    if (nzchar(file)) {
      file <- file(file, "wt")
      on.exit(close(file))
    } else {
      file <- stdout()
    }
  }
  writeLines(out, file)
  invisible(indf)
}

根据@alistaire的建议,我已经fork了tibble包并添加了这个功能。我已经发起了pull request


1
之前的版本中失败后,我花了一些时间试图拼凑出我想要的东西:
“mribble”函数(如make tribble):
mribble <- function(df) {

    names <- colnames(df)
    names <- sapply("~", paste, names, sep = "")
    names <- as.character(names)
    names <- paste(names, collapse = ", ")
    names <- paste(names, ",\n", sep = "")

    rows <- NULL
    for(i in seq_along(1:nrow(df))) {
        r <- as.character(df[i,])
        r <- paste(r, collapse = ", ")
        r <- paste(r, ",\n", sep = "")
        rows <- c(rows, r)
    }

    last <- rows[length(rows)]
    rows <- rows[-length(rows)]
    last <- substr(last, 1, nchar(last)-3)
    rows <- c(rows, last)

    meat <- c(names, rows)
    meat <- paste(meat, collapse = "")

    bun <- paste("df <- tribble(\n", meat, ")", sep = "")

    cat(bun)
}

mribble(df)

这将在控制台中打印出以下内容:
df <- tribble(
    ~x, ~y,
    0, 4.7005,
    179, 4.8598,
    342, 5.0876,
    467, 5.0938,
    705, 5.3891,
    878, 5.6095,
    1080, 5.8777,
    1209, 6.0064,
    1458, 6.3063,
    1639, 6.4723,
    1805, 6.6053,
    2000, 6.8145,
    2121, 6.9078,
    2339, 7.1701,
    2462, 7.2633,
    2676, 7.3865,
    2857, 7.5766,
    3049, 7.644,
    3227, 7.8018,
    3403, 7.9505,
    3583, 8.0974,
    3651, 8.1937,
    4009, 8.2391,
    4034, 8.294,
    4151, 8.3143,
    4194, 8.3452,
    4512, 8.5092,
    4523, 8.5172,
    4679, 8.5993,
    5789, 9.027)

我的解决方案很粗糙,无法处理字符。欢迎提供反馈。

0

包作者Miles McBain的答案已经不正确了,因为包已经更新。现在正确的函数是:

your_data <- 
  data.frame(
    x = 1:3,
    y = 4:6
  )

datapasta::tribble_paste(your_data)

这将在光标处粘贴一个tribble。如果您想返回字符串而不是粘贴它,则有tribble_contruct(),如果您想复制tribble而不是将其粘贴到光标处,以便可以选择放置位置,请使用tribble_format()。这些函数也支持管道操作。


0

{有建设性的}可以做到:

# remotes::install_github("cynkra/constructive")
library(constructive)
construct(df, opts_tbl_df("tribble"))
tibble::tribble(
  ~x,   ~y,
  0,    4.7005,
  179,  4.8598,
  342,  5.0876,
  467,  5.0938,
  705,  5.3891,
  878,  5.6095,
  1080, 5.8777,
  1209, 6.0064,
  1458, 6.3063,
  1639, 6.4723,
  1805, 6.6053,
  2000, 6.8145,
  2121, 6.9078,
  2339, 7.1701,
  2462, 7.2633,
  2676, 7.3865,
  2857, 7.5766,
  3049, 7.644,
  3227, 7.8018,
  3403, 7.9505,
  3583, 8.0974,
  3651, 8.1937,
  4009, 8.2391,
  4034, 8.294,
  4151, 8.3143,
  4194, 8.3452,
  4512, 8.5092,
  4523, 8.5172,
  4679, 8.5993,
  5789, 9.0275,
)

你也可以使用read.table(),如果你不想要一个tibble,但是对于这个例子非常有用:

construct(df, opts_tbl_df("next"), opts_data.frame("read.table"))
read.table(header = TRUE, text = "
x     y
0.    4.7005
179.  4.8598
342.  5.0876
467.  5.0938
705.  5.3891
878.  5.6095
1080. 5.8777
1209. 6.0064
1458. 6.3063
1639. 6.4723
1805. 6.6053
2000. 6.8145
2121. 6.9078
2339. 7.1701
2462. 7.2633
2676. 7.3865
2857. 7.5766
3049. 7.644
3227. 7.8018
3403. 7.9505
3583. 8.0974
3651. 8.1937
4009. 8.2391
4034. 8.294
4151. 8.3143
4194. 8.3452
4512. 8.5092
4523. 8.5172
4679. 8.5993
5789. 9.0275
") |>
  structure(class = c("tbl_df", "tbl", "data.frame"))

这里我们使用“next”来回退到下一个类(“data.frame”)的构造函数,并将数据框的构造函数设置为“read.table”,然后修复属性,以便最终得到一个 tibble。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接