在前面的章节中,我们已经学习了存储表的关系型数据库,支持嵌套数据结构的非关
系型数据库。在 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. 简单的应用可以用storyBoard

    可是问题,你不知道你的项目有多复杂,storyBoard跳转控制有代码这么灵活吗? 1. 假是是根据推送来推出页面呢? 2. 假如我要根据不同情况不停地推出不同的页面呢?storyBoard怎么确定关 ...

  2. Leetcode: Pow(x, n) and Summary: 负数补码总结

    Implement pow(x, n). Analysis:  Time Complexity: O(LogN) Iterative code: refer to https://discuss.le ...

  3. sql中字符串如何比大小

    从字符串的第一个字符开始比较ASSCII码值,如果相等则看下一个,以此类推. 数字的ASCII码<大写字母的ASCII码<小写字母的ASCII码. ASCII码

  4. 统计方法运行时间【Java实现】

    接口Command:定义命令的执行操作 package common; public interface Command { // 运行方法 void run(); } CommandRuntime ...

  5. python2.7运行selenium webdriver api报错Unable to find a matching set of capabilities

    在火狐浏览器33版本,python2.7运行selenium webdriver api报错:SessionNotCreatedException: Message: Unable to find a ...

  6. OpenGL边用边学------2 经典照相机模型

    https://blog.csdn.net/smstong/article/details/50290327 实际照相步骤 1 布置场景和调整照相机位置 3 选择镜头对焦Focus 4 按下快门 5 ...

  7. Php cli模式下执行报错/usr/bin/php: /usr/local/lib/libxml2.so.2: no version information available (required by /usr/bin/php)

    centos下php cli模式报错 /usr/bin/php: /usr/local/lib/libxml2.so.2: no version information available (requ ...

  8. Linux解压文件到指定目录

    Linux解压文件到指定目录 tar在Linux上是常用的打包.压缩.加压缩工具,他的参数很多,折里仅仅列举常用的压缩与解压缩参数 参数:-c :create 建立压缩档案的参数:-x : 解压缩压缩 ...

  9. 20145324王嘉澜 《网络对抗技术》 MAL_逆向与Bof基础

    实践目标 •本次实践的对象是一个名为pwn1的linux可执行文件. •该程序正常执行流程是:main调用foo函数,foo函数会简单回显任何用户输入的字符串. •该程序同时包含另一个代码片段,get ...

  10. 20145329 《网络对抗技术》客户端Adobe阅读器渗透攻击

    两台虚拟机: kali ip:192.168.96.130 windows xp sp3 ip:192.168.96.133 1.kali下打开显示隐藏文件 2.在kali终端中开启msfconsol ...