美文网首页
R 包学习-yaml

R 包学习-yaml

作者: Thinkando | 来源:发表于2020-05-13 00:02 被阅读0次

    yaml 配置文件管理包

    http://blog.fens.me/r-yaml

    前言

    YAML是专门用来写配置文件的语言,YAML的首要设计目的是为了方便人们读写,而JSON的首要设计目标是简单性和通用性。因此,YAML可以看作是JSON的自然超集,可以提高人们的可读性和更完整的信息模型,每个JSON文件也是一个有效的YAML文件。

    目录

    1. YAML是什么
    2. YAML语法介绍
    3. R语言yaml包使用
    4. R语言config包使用
    5. 案例:ETL过程的配置管理

    1. YAML是什么

    YAML 是 YAML Ain’t Markup Language的缩写,是一种数据序列化语言YAML主页。YAML强调以数据为中心,设计目标包括易于阅读,为不同编程语言提供方便的数据交换,适合描述数据结构,标准接口支持通用工具,支持一次性处理,丰富的表达能力与可扩展性,易于使用。

    YAML支持3种数据结构:

    • 键值表,键值对的集合,包括映射,哈希,字典。
    • 序列,为一组排列的值,包括数组,列表。
    • 常量,为单个的不可再分隔的值,包括字符串,布尔值,整数,浮点数,Null,时间,日期

    2. YAML语法介绍

    由于YAML是JSON的自然超集,所以我们每个YAML语法段,都可以用JSON进行表示。本文介绍 YAML 的语法,你通过在线 JS-YAML 解析器进行验证。

    1. YAML文件使用 Unicode 编码作为字符标准编码,默认为UTF-8。
    2. 使用“#”来表示注释内容。
    3. 使用空格作为嵌套缩进工具,通常建议使用两个空格缩进,不建议使用 tab。
    4. YAML文件后缀为 .yml,如:abc.yml 。
    5. YAML文件可以由一或多个文档组成,文档间使用—(三个横线)在每文档开始作为分隔符。同时,文档也可以使用…(三个点号)作为结束符。
    6. 键值表:使用 :(冒号)空格表示单个键值对,使用”{}”表示一个键值表,”? ” 问号+空格表示复杂的键。当键是一个列表或键值表时,就需要使用本符号来标记。

    
    date: 2015-02-01                                    # 单个键值对
    items: {no: 1234, descript: cpu, price: 800.00}     # 多个键值对
    
    

    JSON输出

    
    { date: Sun Feb 01 2015 08:00:00 GMT+0800 (中国标准时间),
      items: { no: 1234, descript: 'cpu', price: 800 } }
    
    

    7. 序列表示:使用 -(横线)单个空格表示单个列表项, 使用”[]”表示一组数据, 组合表示。每个结构都可以嵌套组成复杂的表示结构。

    7.1 序列

    
    --- # 序列
    - blue                                              # 列表
    - red
    - green
    
    

    JSON输出

    
    [ 'blue', 'red', 'green' ]
    
    

    7.2 嵌套结构

    
    -
      - [blue, red, green]        
      - [Age, Bag]
    
    

    JSON输出

    
    [ [ [ 'blue', 'red', 'green' ], [ 'Age', 'Bag' ] ] ]
    
    

    7.3 复合结构对象

    
    --- # 复合结构
    languages:
     - English
     - 中文
     - 日本語
    websites:
     blog: fens.me
     YAML: yaml.org 
     R: www.r-project.org
    
    

    JSON输出

    
    { languages: [ 'English', '中文', '日本語' ],
      websites: { blog: 'fens.me', YAML: 'yaml.org', R: 'www.r-project.org' } }
    
    

    8. 文本块:使用 “|” 和文本内容缩进表示的块:保留块中已有的回车换行,相当于段落块。使用 “>” 和文本内容缩进表示的块:将块中回车替换为空格,最终连接成一行。使用定界符“”(双引号)、‘’(单引号)或回车表示的块:最终表示成一行。

    8.1 段落: 每行保留回车

    
    lines: |          
      北京市朝阳区
      ABC小区#292
    
    

    JSON输出

    { lines: '北京市朝阳区\nABC小区#292\n' }
    

    8.2 一行:最后一个回车

    
    lines: > 
      北京市朝阳区
      ABC小区#292
    
    

    JSON输出

    { lines: '北京市朝阳区 ABC小区#292\n' }
    
    

    8.3 连续一行:无回车

    
    lines:    
      “北京市朝阳区
      ABC小区#292”
    
    

    JSON输出

    { lines: '“北京市朝阳区 ABC小区#292”' }
    
    

    9. 数据类型:整数,浮点数,字符串,NULL,日期,布尔,时间。

    
    --- # 数据类型
    integer: 12345     # 整数标准形式
    octal: 0o34        # 八进制表示,第二个是字母 o
    hex: 0xFF          # 十六进制表示
    
    float: 1.23e+3     # 浮点数
    fixed: 13.67       # 固定小数
    minmin: -.inf      # 表示负无穷
    notNumber: .NaN    # 无效数字
    
    null:              # 空值
    boolean: [true, false] # 布尔值
    string: '12345'    # 字符串
    
    date: 2015-08-23   # 日期
    datetime: 2015-08-23T02:02:00.1z  # 日期时间
    iso8601: 2015-08-23t21:59:43.10-05:00  # iso8601 日期格式
    spaced: 2015-08-23 21:59:43.10 -5      # ?
    
    

    JSON输出

    
    { integer: 12345,
      octal: '0o34',
      hex: 255,
      float: 1230,
      fixed: 13.67,
      minmin: -Infinity,
      notNumber: NaN,
      null: null,
      boolean: [ true, false ],
      string: '12345',
      date: Sun Aug 23 2015 08:00:00 GMT+0800 (中国标准时间),
      datetime: '2015-08-23T02:02:00.1z',
      iso8601: Mon Aug 24 2015 10:59:43 GMT+0800 (中国标准时间),
      spaced: Mon Aug 24 2015 10:59:43 GMT+0800 (中国标准时间) }
    
    

    10. 特殊字符:!(叹号),!!(双叹号)

    
    --- # 特殊字符
    isString: !!str 2015-08-23     # 强调是字符串不是日期数据
    picture: !!binary |            # Base64  图片
      R0lGODlhDAAMAIQAAP//9/X
      17unp5WZmZgAAAOfn515eXv
      Pz7Y6OjuDg4J+fn5OTk6enp
      56enmleECcgggoBADs=
    
    

    JSON输出

    
    { isString: '2015-08-23',
      picture: 
       [ 71,
         73,
         70,
         56,
         57,
         97,
         12,
         0,
         12,
         0,
         132,
         0,
         0,
         255,
         255,
         247,
         245,
         245,
         238,
         233,
         233,
         229,
         102,
         102,
         102,
         0,
         0,
         0,
         231,
         231,
         231,
         94,
         94,
         94,
         243,
         243,
         237,
         142,
         142,
         142,
         224,
         224,
         224,
         159,
         159,
         159,
         147,
         147,
         147,
         167,
         167,
         167,
         158,
         158,
         158,
         105,
         94,
         16,
         39,
         32,
         130,
         10,
         1,
         0,
         59 ] }
    
    

    11. 下面是内置类型
    !!int # 整数类型
    !!float # 浮点类型
    !!bool # 布尔类型
    !!str # 字符串类型
    !!binary # 也是字符串类型
    !!timestamp # 日期时间类型
    !!null # 空值
    !!set # 集合
    !!omap, !!pairs # 键值列表或对象列表
    !!seq # 序列,也是列表
    !!map # 键值表

    11.1 omap

    
    --- !!omap
    - Mark: 65
    - Sammy: 63
    - Key: 58
    
    

    JSON输出

    <pre style="margin: 0pt 0pt 15px; padding: 10px; background: none 0% 0% repeat scroll rgb(249, 249, 212); overflow: auto;">[ { Mark: 65 }, { Sammy: 63 }, { Key: 58 } ]</pre>

    11.2 set

    
    --- !!set           # 注意,“?”表示键为列表,在这里列表为 null
    ? Mark
    ? Sammy
    ? Key
    
    

    JSON输出

    <pre style="margin: 0pt 0pt 15px; padding: 10px; background: none 0% 0% repeat scroll rgb(249, 249, 212); overflow: auto;">{ Mark: null, Sammy: null, Key: null }
    </pre>

    12. 锚点与引用:使用 “&” 定义数据锚点(即要复制的数据),使用 “*” 引用上述锚点数据(即数据的复制目的地)。

    
    hr:
       - Mark McGwire
       # Following node labeled SS
       - &SS 定义要复制的数据
    
    rbi:
       - *SS # Subsequent occurrence   这里是数据复制目标
       - Ken Griffey
    
    

    JSON输出

    
    { hr: [ 'Mark McGwire', '定义要复制的数据' ],
      rbi: [ '定义要复制的数据', 'Ken Griffey' ] }
    
    

    YAML 语法结构还是挺简单的,主要是3个数据结构类型的组合使用。我们理解了核心语法后,接下来就可以使用R语言来调用YAML了,进行在R语言中的配置管理。

    3. R语言yaml包使用

    R语言中,有多个包都可以进行YAML的数据解析,我来介绍2个包一个是yaml包,另一个是config包,下面我们分别介绍一下。2个包都能解析YAML文件,但设计目标是不同的。

    • yaml包,是专门用来解析YAML语法的包,核心功能就是解析YAML文件到R对象,再把R对象生成YAML文件。
    • config包,是专门用来进行配置管理的。用于项目配置管理的场景,当开发,测试和生产环境同一个参数需要配置不同的值,使用config包使用起来比yaml包更简单。

    开发所使用的系统环境

    • Win10 64bit
    • R: 3.6.1 x86_64-w64-mingw32/x64 b4bit

    先让我来学习一下yaml包,yaml包安装和使用,都很容易。首先,我们先进行安装。

    
    > install.packages("yaml")
    > library(yaml)
    
    

    查看yaml包,发现一共就5个函数

    • read_yaml,读取一个YAML文件
    • write_yaml,写入到一个YAML文件
    • as.yaml,转换R对象为YAML字符串
    • yaml.load,转换YAML字符串到R对象
    • yaml.load_file,读文件转换YAML到R对象,看了一个代码和read_yaml()函数没有什么区别

    接下来,我们新建一个abc.yml文件,用于描述一个订单。

    
    invoice: 31223
    date   : 2020-01-23
    bill-to: &id001
        given  : 小明
        address:
            lines: |
                北京市朝阳区
                ABC小区 #292
            city    : 北京
    ship-to: *id001
    product:
        - sku         : BL394D
          quantity    : 4
          price       : 450.00
        - sku         : BL4438H
          quantity    : 1
          price       : 2392.00
    tax  : 251.42
    total: 4443.52
    
    

    使用yaml包,来加载这个文件。

    > abc<-read_yaml("abc.yml",fileEncoding = "UTF-8")
    
    

    查看R语言结构,就是映射为R语言中的list结构。
    [图片上传失败...(image-c6ce79-1589298966859)]

    在R语言中,修改结果。

    
    # 修改日期
    abc$date<- '2019-01-01'
    
    # 去掉第二件商品
    abc$product[2]<-NA
    
    

    输出保存为新的文件abc2.yml

    write_yaml(abc,"abc2.yml",fileEncoding = "UTF-8")
    

    打开文件abc2.yml

    
    invoice: 31223
    date: '2019-01-01'
    bill-to:
      given: 小明
      address:
        lines: |
          北京市朝阳区
          ABC小区 #292
        city: 北京
    ship-to:
      given: 小明
      address:
        lines: |
          北京市朝阳区
          ABC小区 #292
        city: 北京
    product:
    - sku: BL394D
      quantity: 4
      price: 450.0
    - .na
    tax: 251.42
    total: 4443.52
    
    

    我们可以进行JSON转换,再通过JSON的格式进行观察。在R语言中JSON和R的详细介绍,请参考文章R和JSON的傻瓜式编程

    
    # 加载JSON库
    > library(RJSONIO)
    > abcj<-toJSON(abc)
    
    # 查看JSON
    > cat(abcj)
    {
     "invoice": 31223,
    "date": "2019-01-01",
    "bill-to": {
     "given": "小明",
    "address": {
     "lines": "北京市朝阳区\nABC小区 #292\n",
    "city": "北京" 
    } 
    },
    "ship-to": {
     "given": "小明",
    "address": {
     "lines": "北京市朝阳区\nABC小区 #292\n",
    "city": "北京" 
    } 
    },
    "product": [
     {
     "sku": "BL394D",
    "quantity": 4,
    "price":      450 
    },
    null 
    ],
    "tax":   251.42,
    "total":  4443.52 
    }
    
    

    4. R语言config包使用

    config包,是RStudio公司开发的,是专门用来进行配置管理的。用于项目配置管理的场景,区别开发,测试和生产环境可能需要不同的值,使用起来比yaml更简单。

    首先是安装。

    
    > install.packages("config")
    > library(config)
    
    

    使用config包,我们新一个datasource.yml。用来描述,在软件项目开发时,开发环境(default),测试环境(test),生产环境(production)对于datafile这个参数,会用于不同的文件。

    
    # 开发环境
    default:
      time: 5
      datafile: "data-dev.csv"
    
    # 测试环境
    test:
      time: 30
      datafile: "data-test.csv"
    
    # 生产环境
    production:
      inherits: test
      datafile: "data-prod.csv"
    
    

    使用config包读取datasource.yml。

    
    # 默认情况会加载default配置
    > dev <- config::get(file = "datasource.yml")
    > dev
    $time
    [1] 5
    
    $datafile
    [1] "data-dev.csv"
    
    attr(,"config")
    [1] "default"
    attr(,"file")
    [1] "c:\\work\\R\\config\\datasource.yml"
    
    

    当我们在生产环境时,可以在R的运行时环境配置好全局的环境变量,这个时候就可以直接取对prod的配置信息了。

    
    # 设置全局变量
    > Sys.setenv(R_CONFIG_ACTIVE = "production")
    
    # 判断是否production被激活
    > config::is_active("production")
    [1] TRUE
    
    # 获得配置
    > prod <- config::get(file = "datasource.yml")
    > prod
    $time
    [1] 30
    $inherits
    [1] "test"
    $datafile
    [1] "data-prod.csv"
    attr(,"config")
    [1] "production"
    attr(,"file")
    [1] "c:\\work\\R\\config\\datasource.yml"
    
    

    所以,我们看到config包,提供了对于yaml的在软件管理的场景的使用方法,很简单,更方便。

    5. 案例:ETL过程的配置管理

    现在,我们已经完全了解了yaml的语法,以及程序如何调用的使用方法了,那么接下来就是真正地发挥YAML的作用了,把YAML的配置管理用于具体的业务逻辑中。

    我设计了一个真实的场景,做数据项目的时候,经常需要对数据进行各种变形处理,就是常说的ETL过程。先加载数据,然后数据处理,最后输出数据,进行可视化。

    image

    数据的连续处理过程,在这个思路上其实也出现了一大批软件,通过界面拖拽就实现的功能操作。从软件设计的角度来说,数据连续处理的过程,是非常适合用配置管理的。以配置的方法简化了软件开发的复杂度,又能让用户自己参与其中,用户体验那叫一个爽。

    我们就可以用YAML格式,来做为不同软件的核心数据交换结构。基于这个文字型的数据结构,用户可以自己编写,因为易读易懂。同时,基于这个文字型的数据结构,程序可以解析关键的配置信息,这样就打通人和程序的对话格式。把原本看起来很复杂的过程,进行了抽象,便利地实现,用户可参与的配置任务。

    我设计一个task.yml的文件,用于描述一个数据处理的过程。

    
    version: v1.0              # 定义版本
    
    resource:                   # 数据源
      - database: &mysql1
          dbname: yaml
          host: localhost
          port: 3306
          username: yaml
          password: yaml
      - file: &file1 
          path: C:/work/demo/test.csv   
          file_encoding: 'utf-8'
    
    data_input:                 # 数据读取
      method: mysql             # 数据读取方法,格式为 method: 方法名
      dataref: *mysql1
      param:                    
        table_name: iris_table
        columns: Sepal.Length
    
    data_analysis:     
      method: mean              # 分析方法,格式为 method: 方法名
      param:                    # 参数
        na_rm: FALSE            # 具体参数格式 参数名: 参数值
    
    data_output:
      method: csv               # 数据输出方法,格式为 method: 方法名
      dataref: *file1
    
    

    配置解释:

    • version:定义配置文件版本
    • resource:定义数据源,数据库,文件等
    • data_input:定义数据数据输入,引用数据源
    • data_analysis: 定义数据处理方法,计算平均值
    • data_output:定义数据数据输出,引用数据源

    运行R语言的代码,就可以执行上面的配置过程,下面的代码是只是一个代码结构,涉及到很多具体的函数调用细节,等下次在详细介绍。

    
    library(magrittr)
    task<-read_yaml("task.yml",fileEncoding = "UTF-8")
    task
    
    run<-function(task){
      data_input<-function(obj){}          #数据加载
      data_analysis<-function(dat,obj){}   #数据处理
      data_output<-function(dat,obj){}     #数据输出
    
      data_input(task$data_input)  %>% 
        data_analysis(a,task$data_analysis) %>% 
        data_output(task$data_output)
    }
    
    # 运行函数
    run(task)
    
    

    本文对YAML进行比较完整的介绍,配置管理工作是软件开发中非常重要的,现在工具越来越便利,把程序员可以从大量复杂的场景剥离出来,只专注于代码本身,可以极大地提高开发效率,并保证程序的质量。把YAML试试用起来吧。

    相关文章

      网友评论

          本文标题:R 包学习-yaml

          本文链接:https://www.haomeiwen.com/subject/iviwnhtx.html