在前面的章节中,我们已经学习了存储表的关系型数据库,支持嵌套数据结构的非关
系型数据库。在 R 中,最常见的嵌套数据结构就是列表对象。之前的章节都关注操作表格
数据。本节,我们一起玩转作者开发的 rlist 包,这是一个为操作非表格数据设计的包。
rlist 的设计和 dplyr 非常相似。它提供了针对列表对象的映射、筛选、选择、排
序、分组和聚合功能。运行以下代码来从 CRAN 安装 rlist 包:
install.packages("rlist")
我们有一个非表格式版本的产品数据,储存在 data/products.json。在这个文件
中,每个产品都以 JSON 形式表达,如下:
{
"id": "T01",
"name": "SupCar",
"type": "toy",
"class": "vehicle",
"released": true,
"stats": {
"material": "Metal",
"size": 120,
"weight": 10
},
"tests": {
"quality": null,
"durability": 10,
"waterproof": false
},
"scores": [8, 9, 10, 10, 6, 5]
}
所有的产品都被存储在一个 JSON 数组中,就像这样: [ {...}, {...} ]。不同
于将数据储存在不同的表中,我们把所有与产品相关的东西都放入一个对象中。然后使
用 rlist 的函数来处理这种格式的数据。首先载入 rlist 包:
library(rlist)
为了把数据以列表的形式载入 R 中,我们需要使用 jsonlite::fromJSON( ),或
者就直接使用 rlist 提供的 list.load( )函数:
products <- list.load("data/products.json")
str(products[[1]])
## List of 8
## $ id : chr "T01"
## $ name : chr "SupCar"
## $ type : chr "toy"
## $ class : chr "vehicle"
## $ released: logi TRUE
## $ stats :List of 3
## ..$ material: chr "Metal"
## ..$ size : int 120
## ..$ weight : int 10
## $ tests :List of 3
## ..$ quality : NULL
## ..$ durability: int 10
## ..$ waterproof: logi FALSE
## $ scores : int [1:6] 8 9 10 10 6 5
现在,列表 products 存储了所有产品的信息。products 的每个成分都包含了一个
产品的所有相关信息。
可以调用 list.map( ) 函数,在每个成分的语义中计算表达式:
str(list.map(products, id))
## List of 6
## $ : chr "T01"
## $ : chr "T02"
## $ : chr "M01"
## $ : chr "M02"
## $ : chr "M03"
## $ : chr "M04"
这个函数迭代计算 products 中每个成分的 id 并返回一个新的列表,其中包含所有
相关的结果。list.mapv( ) 函数简化了这个列表,返回一个向量:
list.mapv(products, name)
## [1] "SupCar" "SupPlane" "JeepX" "AircraftX"
## [5] "Runner" "Dancer"
为了对 products 进行筛选,我们可以调用 list.filter( )函数并配合使用逻辑
条件。只有所有条件都返回 TRUE 的 products 的元素,才会被筛选出来:
released_products <- list.filter(products, released)
list.mapv(released_products, name)
## [1] "SupCar" "JeepX" "AircraftX" "Runner"
注意到, rlist 的函数设计也和 dplyr 的函数设计很相似,也就是说,输入的数据永
远作为第 1 个参数。因此我们可以使用管道操作符将结果逐步向前传送:
products %>%
list.filter(released) %>%
list.mapv(name)
## [1] "SupCar" "JeepX" "AircraftX" "Runner"
可以使用 list.select( ) 函数将输入列表的每个成分的某些特定字段都筛选出来:
products %>%
list.filter(released, tests$waterproof) %>%
list.select(id, name, scores) %>%
str()
## List of 3
## $ :List of 3
## ..$ id : chr "M01"
## ..$ name : chr "JeepX"
## ..$ scores: int [1:6] 6 8 7 9 8 6
## $ :List of 3
## ..$ id : chr "M02"
## ..$ name : chr "AircraftX"
## ..$ scores: int [1:7] 9 9 10 8 10 7 9
## $ :List of 3
## ..$ id : chr "M03"
## ..$ name : chr "Runner"
## ..$ scores: int [1:10] 6 7 5 6 5 8 10 9 8 9
除此之外,还可以用 list.select( ) 函数创建新的字段:
products %>%
list.filter(mean(scores) >= 8) %>%
list.select(name, scores, mean_score = mean(scores)) %>%
str()
## List of 3
## $ :List of 3
## ..$ name : chr "SupCar"
## ..$ scores : int [1:6] 8 9 10 10 6 5
## ..$ mean_score: num 8
## $ :List of 3
## ..$ name : chr "SupPlane"
## ..$ scores : int [1:5] 9 9 10 10 10
## ..$ mean_score: num 9.6
## $ :List of 3
## ..$ name : chr "AircraftX"
## ..$ scores : int [1:7] 9 9 10 8 10 7 9
## ..$ mean_score: num 8.86
也可以用 list.sort( ) 函数,按照特定字段或值对列表元素进行排序,再使
用 list.stack( ) 将所有元素整合成一个数据框:
products %>%
list.select(name, mean_score = mean(scores)) %>%
list.sort(-mean_score) %>%
list.stack()
## name mean_score
## 1 SupPlane 9.600000
## 2 AircraftX 8.857143
## 3 SupCar 8.000000
## 4 Dancer 7.833333
## 5 JeepX 7.333333
## 6 Runner 7.300000
为了给列表分组,可以调用 list.group( ) 创建一个嵌套列表,其中所有元素都被
分组变量的字段值分割开来:
products %>%
list.select(name, type, released) %>%
list.group(type) %>%
str()
## List of 2
## $ model:List of 4
## ..$ :List of 3
## .. ..$ name : chr "JeepX"
## .. ..$ type : chr "model"
## .. ..$ released: logi TRUE
## ..$ :List of 3
## .. ..$ name : chr "AircraftX"
## .. ..$ type : chr "model"
## .. ..$ released: logi TRUE
## ..$ :List of 3
## .. ..$ name : chr "Runner"
## .. ..$ type : chr "model"
## .. ..$ released: logi TRUE
## ..$ :List of 3
## .. ..$ name : chr "Dancer"
## .. ..$ type : chr "model"
## .. ..$ released: logi FALSE
## $ toy :List of 2
## ..$ :List of 3
## .. ..$ name : chr "SupCar"
## .. ..$ type : chr "toy"
## .. ..$ released: logi TRUE
## ..$ :List of 3
## .. ..$ name : chr "SupPlane"
## .. ..$ type : chr "toy"
## .. ..$ released: logi FALSE
rlist 也提供了许多其他函数,从而能够方便地操作非表格式数据。举个例子,函数
list.table( ) 便是 table( ) 的加强版,它使得 table( ) 可以直接作用于列表元素:
products %>%
list.table(type, class)
## class
## type people vehicle
## model 2 2
## toy 0 2
通过在输入列表的语义中计算每个参数,它也支持多维表格:
products %>%
list.filter(released) %>%
list.table(type, waterproof = tests$waterproof)
## waterproof
## type FALSE TRUE
## model 0 3
## toy 1 0
尽管数据是通过非表格形式存储的,我们仍然可以进行复杂的数据操作,并用表格形
式展示结果。例如,假设我们需要计算两个产品的平均得分,并统计有多少种不同的得分。
其中,这两个产品具有最高的平均得分,且至少包含 5 种得分。
我们可以将这个任务分解成几个数据操作的小任务,这些小任务可以轻松地通
过 rlist 的函数处理。由于数据操作中需要的步骤较多,我们使用管道操作来组织工作流:
products %>%
list.filter(length(scores) >= 5) %>%
list.sort(-mean(scores)) %>%
list.take(2) %>%
list.select(name,
mean_score = mean(scores),
n_score = length(scores)) %>%
list.stack()
## name mean_score n_score
## 1 SupPlane 9.600000 5
## 2 AircraftX 8.857143 7
以上代码看起来很直观,而且可以很方便地预测和分析每一步操作。如果最终结果可
以用表格展示,我们就调用 list.stack( ),这样就能够将所有列表元素组合成一个数据框。
想了解更多关于 rlist 的函数,可以阅读 rlist 教程(https://renkun.me/rlist-tutorial/)。还
有很多处理嵌套数据结构的包,它们具有不同的设计理念,例如 purrr(https://github. com/
hadley/purrr)。如果感兴趣,可以访问他们的网站。

使用 rlist 包处理嵌套数据结构的更多相关文章

  1. jar包有嵌套的jar的打包成jar的方法

    1.先写一个类,将其打包成jar包. 代码如下: package com.wjy.jar; public class GetUserName { public String getUserName() ...

  2. R语言︱非结构化数据处理神器——rlist包

    本文作者:任坤,厦门大学王亚南经济研究院金融硕士生,研究兴趣为计算统计和金融量化交易,pipeR,learnR,rlist等项目的作者. 近年来,非关系型数据逐渐获得了更广泛的关注和使用.下面分别列举 ...

  3. 解析复杂的嵌套数据结构-jsonpath

    JsonPath是一种简单的方法来提取给定JSON文档的部分内容. JsonPath有许多编程语言,如Javascript,Python和PHP,Java. JsonPath提供的json解析非常强大 ...

  4. 【数据结构的JavaScript版实现】data-struct-js的npm包初版作成

    [数据结构的JavaScript版实现]data-struct-js的npm包初版作成 码路工人 CoderMonkey [数据结构的JavaScript版实现] 拖了这么久,终于趁着春节假期把初版( ...

  5. 引擎设计跟踪(九.9) 文件包系统(Game Package System)

    很早之前,闪现过写文件包系统的想法, 但是觉得还没有到时候. 由于目前工作上在做android ndk开发, 所以业余时间趁热做了android的移植, 因为android ndk提供的mountab ...

  6. js处理层级数据结构的一些总结

    开发者对复杂的数据结构的处理能力也是体现开发者水平的一个度量吧...最近发现自己对一些嵌套数据结构.层级数据结构的处理能力不大足...经常被这些把自己绕晕...严重影响开发效率...就稍微低总结了一下 ...

  7. UML之包图

    包图是UML中用类似于文件夹的符号表示的模型元素的组合,系统中的每个元素都只能为一个包所有,一个包可嵌套在另一个包中,使用包图可将相关元素归入一个系统,一个包中包含附属包.图表或单个元素.简单的来说, ...

  8. day 16 包的导入

    包的认识 '''包通过文件夹来管理一系列功能相近的模块​包:一系列模块的集合体重点:包中一定有一个专门用来管理包中所有模块的文件包名:存放一系列模块的文件夹名字包名(包对象)存放的是管理模块的那个文件 ...

  9. Python 入门基础13 --模块与包

    本节内容: 一.模块及使用 1.模块及使用 2.起别名.from导入 3.自执行与模块 二.包的使用 2.1 包中模块的使用:import 2.2 包的嵌套 2.3 包中模块的使用:from ...i ...

随机推荐

  1. dialog提交表单

    <div id="dialog" title="添加客户"> <!--表单提交--> <form id="dialogF ...

  2. rabbitmq_坑

      一.None of the specified endpoints were reachable 这个异常在创建连接时抛出(CreateConnection()),原因一般是ConnectionF ...

  3. MySQL创建数据表并建立主外键关系

    为mysql数据表建立主外键需要注意以下几点: 需要建立主外键关系的两个表的存储引擎必须是InnoDB. 外键列和参照列必须具有相似的数据类型,即可以隐式转换的数据类型. 外键列和参照列必须创建索引, ...

  4. 011-/etc/resolv.conf详解

  5. 24最小生成树之Prim算法

    最小生成树的Prim算法 思想:采用子树延伸法 将顶点分成两类: 生长点——已经在生成树上的顶点 非生长点——未长到生成树上的顶点 使用待选边表: 每个非生长点在待选边表中有一条待选边,一端连着非生长 ...

  6. Linux下DNS服务器配置

    一步:yum install -y bind bind-utils bind-chroot yum install bind* //安装DNS服务 第二步:systemctl stop firewal ...

  7. Linux系统下C语言程序的构建过程

    本文转载自:http://www.ruanyifeng.com/blog/2014/11/compiler.html 源码要运行,必须先转成二进制的机器码.这是编译器的任务. 比如,下面这段源码(假定 ...

  8. Java EE业务处理流程与XML的引入

    Java EE基于MVC架构的业务处理流程 MVC架构业务处理流程 XML定义 XML是可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言.XML被设计用于数据的存 ...

  9. 轻型池不支持执行公共语言运行时(CLR)。禁用以下两个选项中的一个: “clr enabled”或“lightweight pooling”解决方法

    执行2变一下代码   : 注意:1表示启用,0表示禁用. sp_configure ; GO sp_configure ; GO sp_configure ; go RECONFIGURE; GO E ...

  10. Python 除法运算

    Python中的除法较其它语言显得非常高端,有套很复杂的规则.Python中的除法有两个运算符,/和// 首先来说/除法: 在python 2.x中/除法就跟我们熟悉的大多数语言,比如Java啊C啊差 ...