在前面的章节中,我们已经学习了存储表的关系型数据库,支持嵌套数据结构的非关
系型数据库。在 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. [LeetCode] 255. Verify Preorder Sequence in Binary Search Tree_Medium tag: Preorder Traversal, tree

    Given an array of numbers, verify whether it is the correct preorder traversal sequence of a binary ...

  2. javascript按字节截取标题中字符串

    在网页展示中经常会碰到,标题过长,需要截取字符串,用CSS的实现的话各种兼容问题,下面为大家介绍下javascript如何按字节截取字符串 做为一个前端开发人员在网页展示中经常会碰到,标题过长,需要截 ...

  3. IBatis 配置各种数据库

    IBatis 与各种数据库之间的配置在providers.config这个文件下. <?xml version="1.0" encoding="utf-8" ...

  4. js实现轮播图

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. PKU2418_树种统计(map应用||Trie树)

    Description Hardwoods are the botanical group of trees that have broad leaves, produce a fruit or nu ...

  6. Java设计模式应用——模板方法模式

    所谓模板方法模式,就是在一组方法结构一致,只有部分逻辑不一样时,使用抽象类制作一个逻辑模板,具体是实现类仅仅实现特殊逻辑就行了.类似科举制度八股文,文章结构相同,仅仅具体语句有差异,我们只需要按照八股 ...

  7. Ignite初探

    Guava是一个很方便的本地缓存工具,但是在多节点处理的过程中,本地缓存无法满足数据一致性的问题.分布式缓存Ignite很好的解决了数据一致性,可靠性,事务性等方面的问题. Ignite支持分区方式和 ...

  8. c++第十一天

    <c++ primer, 5E> 第68页到第81页,笔记: 1.读取未知量的string对象示例 #include<iostream> using std::cin; usi ...

  9. linux不常用但很有用的命令(持续完善)

    Linux登录后设置提示信息: /etc/issue 本地端登录前显示信息文件 /etc/issue.net 网络端登录前显示信息文件 /etc/motd 登陆后显示信息文件 可以添加以下几个常用选项 ...

  10. PHP安装包TS和NTS的区别

    原文链接:http://blog.csdn.net/zhuifengshenku/article/details/38796555 TS指Thread Safety,即线程安全,一般在IIS以ISAP ...