将数据框写入YAML格式的R文件

4

I have a dataframe:

df <- data.frame(name = c("bob","joe"),
                 target = c("yellow", "grey"),
                 code1 = c("fly", "walk"),
                 code2 = c("jump", "run"))

我希望将信息写入一个具有特定结构��yaml文件:

samples:
        bob:
            target: yellow
            code1: fly
            code2: jump

        joe:
            target: grey
            code1: walk
            code2: run

我在实现这个特定结构的 Yaml 输出时遇到了问题。

1
你是否正在使用yaml包?目前你是如何尝试的? - be_green
@be_green yaml包提供保存函数吗? - Blaszard
我认为你只需连接到文本文件并转储内容即可保存,但是as.yaml提供了一个很好的便利函数。问题在于他有分层数据,而这些数据无法由data.frame正确表示。 - be_green
3个回答

6

使用除了yaml输出之外的任何包的版本:

library(yaml)
out <- as.yaml(list(samples=split(replace(df, "name", NULL), df$name)))

# just to show it works: 
cat(out)

#samples:
#  bob:
#    target: yellow
#    code1: fly
#    code2: jump
#  joe:
#    target: grey
#    code1: walk
#    code2: run

2

如果其他人遇到这个问题,想要一个更完整的解决方案,这是我在工作流程中使用 purrr 包解决类似问题的方法。

这是我的示例数据:

df <- data.frame(name = c("bob", "bob", "joe", "joe"),
                 target = c("yellow", "red", "yellow", "red"),
                 method = c("fly", "jump", "walk", "run"),
                 after = c("lunch", "breakfast", "dinner", "breakfast"),
                 stringsAsFactors = F)

这与OP提供的相似,但包含了额外的一级。

以下是我构建YAML文件的方法:

library(purrr)
library(dplyr)

nested_lists <- df %>%
  split(f = .$name) %>%
  purrr::map(dplyr::select, -name) %>%
  purrr::map(~ split(.x, f = .x$target)) %>%
  purrr::map_depth(2, dplyr::select, -target) %>%
  list(samples = .)

这个名为nested_lists的对象可以使用yaml::write_yaml写入文件,或者使用as.yaml打印到屏幕上:

> cat(yaml::as.yaml(nested_lists))
samples:
  bob:
    red:
      method: jump
      after: breakfast
    yellow:
      method: fly
      after: lunch
  joe:
    red:
      method: run
      after: breakfast
    yellow:
      method: walk
      after: dinner

这是一种很好的方法,它可以很好地概括任意层级。

例如,如果我们用purrr::map_depth(1, ...)替换purrr::map(...)调用,并将嵌套列表扩展到另一个级别,模式变得更加清晰:

library(purrr)
library(dplyr)

nested_lists3 <- df %>%
  split(f = .$name) %>%
  purrr::map_depth(1, dplyr::select, -name) %>%
  purrr::map_depth(1, ~ split(.x, f = .x$target)) %>%
  purrr::map_depth(2, dplyr::select, -target) %>%
  purrr::map_depth(2, ~ split(.x, f = .x$method)) %>%
  purrr::map_depth(3, dplyr::select, -method) %>%
  list(samples = .)

cat(yaml::as.yaml(nested_lists3))

输出:

samples:
  bob:
    red:
      jump:
        after: breakfast
    yellow:
      fly:
        after: lunch
  joe:
    red:
      run:
        after: breakfast
    yellow:
      walk:
        after: dinner

1
我不确定你现在是怎么做的,但这是我的解决方案,使用yaml和data.table库。首先我们构建数据表,然后构建所需的嵌套格式,接着从列表的每个元素中移除姓名列,最后将其转换为yaml对象。函数cat返回未经处理的文本。
library(data.table)
library(yaml)
library(magrittr)

df <- data.table(name = c("bob","joe"),
                 target = c("yellow", "grey"),
                 code1 = c("fly", "walk"),
                 code2 = c("jump", "run")) %>% 
  split(by = "name") %>%
  lapply(function(x) x[,name := NULL] %>% .[]) %>% 
  list(samples = .) %>% 
  as.yaml

> cat(df)
samples:
  bob:
    target: yellow
    code1: fly
    code2: jump
  joe:
    target: grey
    code1: walk
    code2: run

你可以使用 write 函数将文件写出。
write(df, "C:/filepath/file.txt")

为什么要加载data.table,重新创建已提供的“df”,只是为了执行一个NULL赋值?而且你还没有加载magrittr或dplyr来使用“%>%”管道。 - thelatemail
两个格式问题:name 应该缩进 2 个制表符,并且每个名称组之间应该空一行。 - skurp
data.table只是我的习惯,很抱歉没有包含库调用。 - be_green

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