本文作者:任坤,厦门大学王亚南经济研究院金融硕士生,研究兴趣为计算统计和金融量化交易,pipeR,learnR,rlist等项目的作者。

近年来,非关系型数据逐渐获得了更广泛的关注和使用。下面分别列举了一个典型的关系型数据表和一个典型的非关系型数据集。

关系型数据:一组学生的基本数据,包括姓名(Name)、性别(Gender)、年龄(Age)以及专业(Major)。

NAME GENDER AGE MAJOR
Ken Male 24 Finance
Ashley Female 25 Statistics
Jennifer Female 23 Computer Science

非关系型数据:一组程序开发者的基本信息,包括姓名(Name)、年龄(Age)、兴趣爱好(Interest)、编程语言以及使用年数(Language)。

NAME AGE INTEREST LANGUAGE
Ken 24 reading, music,movies R:2, C#:4, Python:3
James 25 sports, music R:3, Java:2, C++:5
Penny 24 movies, reading R:1, C++:4, Python:2

可以发现,第一个表中的关系型数据可以简单地放入矩形的数据表,而第二个表中的非关系型数据中InterestLanguage本身并不是单一值的字段,因而如果在关系型数据库中表示,可能需要建立多个表和关系来存储。

对于这种数据的处理,MongoDB是较为成熟的解决方案之一。在R中,data.frame可以用来很好地描述关系型数据表,也有data.tabledplyr等扩展包可以方便地处理这类数据。而list对象可以很好地表征结构灵活的非关系型数据,但是却缺乏可以灵活地处理list对象中存储非关系型数据的扩展包。

这就是 rlist 扩展包诞生的原因:让人们可以使用全部R的函数和功能,方便地访问list对象中存储的非关系型数据,从而轻松地、直观地进行非关系型数据映射 (mapping)、筛选(filtering)、分组(grouping)、排序(sorting)、更新(updating)等等。

可以用devtools扩展包直接从GitHub安装rlist最新的开发版本:

  1. devtools::install_github("rlist","renkun-ken")

下面将通过一些例子来分别介绍这个扩展包的主要功能。下面的例子基本都在以下数据中进行。

  1. library(rlist)
  2. devs <-
  3. list(
  4. p1=list(name="Ken",age=24,
  5. interest=c("reading","music","movies"),
  6. lang=list(r=2,csharp=4,python=3)),
  7. p2=list(name="James",age=25,
  8. interest=c("sports","music"),
  9. lang=list(r=3,java=2,cpp=5)),
  10. p3=list(name="Penny",age=24,
  11. interest=c("movies","reading"),
  12. lang=list(r=1,cpp=4,python=2)))
  13. str(devs)
  1. List of 3
  2. $ p1:List of 4
  3. ..$ name : chr "Ken"
  4. ..$ age : num 24
  5. ..$ interest: chr [1:3] "reading" "music" "movies"
  6. ..$ lang :List of 3
  7. .. ..$ r : num 2
  8. .. ..$ csharp: num 4
  9. .. ..$ python: num 3
  10. $ p2:List of 4
  11. ..$ name : chr "James"
  12. ..$ age : num 25
  13. ..$ interest: chr [1:2] "sports" "music"
  14. ..$ lang :List of 3
  15. .. ..$ r : num 3
  16. .. ..$ java: num 2
  17. .. ..$ cpp : num 5
  18. $ p3:List of 4
  19. ..$ name : chr "Penny"
  20. ..$ age : num 24
  21. ..$ interest: chr [1:2] "movies" "reading"
  22. ..$ lang :List of 3
  23. .. ..$ r : num 1
  24. .. ..$ cpp : num 4
  25. .. ..$ python: num 2

上面的代码是直接在R中建立一个名为devs的list对象,里面包含的正是前面提到的非关系型数据。由于直接输出数据占用篇幅较长,在后面的例子中可能采用str函数来显示数据。

映射(mapping)

list.map函数提供了list中元素的映射功能。

将每个元素映射到年龄(age):

  1. list.map(devs, age)
  1. $p1
  2. [1] 24
  3. $p2
  4. [1] 25
  5. $p3
  6. [1] 24

将每个元素映射到使用编程语言的平均年数:

  1. list.map(devs, mean(as.numeric(lang)))
  1. $p1
  2. [1] 3
  3. $p2
  4. [1] 3.333
  5. $p3
  6. [1] 2.333

将每个元素映射到使用的编程语言名称:

  1. list.map(devs, names(lang))
  1. $p1
  2. [1] "r" "csharp" "python"
  3. $p2
  4. [1] "r" "java" "cpp"
  5. $p3
  6. [1] "r" "cpp" "python"

筛选(filtering)

筛选出年龄不低于25岁的个体:

  1. str(list.filter(devs, age>=25))
  1. List of 1
  2. $ p2:List of 4
  3. ..$ name : chr "James"
  4. ..$ age : num 25
  5. ..$ interest: chr [1:2] "sports" "music"
  6. ..$ lang :List of 3
  7. .. ..$ r : num 3
  8. .. ..$ java: num 2
  9. .. ..$ cpp : num 5

筛选出使用R语言的个体:

  1. str(list.filter(devs, "r" %in% names(lang)))
  1. List of 3
  2. $ p1:List of 4
  3. ..$ name : chr "Ken"
  4. ..$ age : num 24
  5. ..$ interest: chr [1:3] "reading" "music" "movies"
  6. ..$ lang :List of 3
  7. .. ..$ r : num 2
  8. .. ..$ csharp: num 4
  9. .. ..$ python: num 3
  10. $ p2:List of 4
  11. ..$ name : chr "James"
  12. ..$ age : num 25
  13. ..$ interest: chr [1:2] "sports" "music"
  14. ..$ lang :List of 3
  15. .. ..$ r : num 3
  16. .. ..$ java: num 2
  17. .. ..$ cpp : num 5
  18. $ p3:List of 4
  19. ..$ name : chr "Penny"
  20. ..$ age : num 24
  21. ..$ interest: chr [1:2] "movies" "reading"
  22. ..$ lang :List of 3
  23. .. ..$ r : num 1
  24. .. ..$ cpp : num 4
  25. .. ..$ python: num 2

筛选出使用Python年限不低于3年的个体:

  1. str(list.filter(devs, lang$python >= 3))
  1. List of 1
  2. $ p1:List of 4
  3. ..$ name : chr "Ken"
  4. ..$ age : num 24
  5. ..$ interest: chr [1:3] "reading" "music" "movies"
  6. ..$ lang :List of 3
  7. .. ..$ r : num 2
  8. .. ..$ csharp: num 4
  9. .. ..$ python: num 3

分组(grouping)

按照年龄做互斥分组:

  1. str(list.group(devs, age))
  1. List of 2
  2. $ 24:List of 2
  3. ..$ p1:List of 4
  4. .. ..$ name : chr "Ken"
  5. .. ..$ age : num 24
  6. .. ..$ interest: chr [1:3] "reading" "music" "movies"
  7. .. ..$ lang :List of 3
  8. .. .. ..$ r : num 2
  9. .. .. ..$ csharp: num 4
  10. .. .. ..$ python: num 3
  11. ..$ p3:List of 4
  12. .. ..$ name : chr "Penny"
  13. .. ..$ age : num 24
  14. .. ..$ interest: chr [1:2] "movies" "reading"
  15. .. ..$ lang :List of 3
  16. .. .. ..$ r : num 1
  17. .. .. ..$ cpp : num 4
  18. .. .. ..$ python: num 2
  19. $ 25:List of 1
  20. ..$ p2:List of 4
  21. .. ..$ name : chr "James"
  22. .. ..$ age : num 25
  23. .. ..$ interest: chr [1:2] "sports" "music"
  24. .. ..$ lang :List of 3
  25. .. .. ..$ r : num 3
  26. .. .. ..$ java: num 2
  27. .. .. ..$ cpp : num 5

按照兴趣做非互斥分组:

  1. str(list.class(devs, interest))
  1. List of 4
  2. $ movies :List of 2
  3. ..$ p1:List of 4
  4. .. ..$ name : chr "Ken"
  5. .. ..$ age : num 24
  6. .. ..$ interest: chr [1:3] "reading" "music" "movies"
  7. .. ..$ lang :List of 3
  8. .. .. ..$ r : num 2
  9. .. .. ..$ csharp: num 4
  10. .. .. ..$ python: num 3
  11. ..$ p3:List of 4
  12. .. ..$ name : chr "Penny"
  13. .. ..$ age : num 24
  14. .. ..$ interest: chr [1:2] "movies" "reading"
  15. .. ..$ lang :List of 3
  16. .. .. ..$ r : num 1
  17. .. .. ..$ cpp : num 4
  18. .. .. ..$ python: num 2
  19. $ music :List of 2
  20. ..$ p1:List of 4
  21. .. ..$ name : chr "Ken"
  22. .. ..$ age : num 24
  23. .. ..$ interest: chr [1:3] "reading" "music" "movies"
  24. .. ..$ lang :List of 3
  25. .. .. ..$ r : num 2
  26. .. .. ..$ csharp: num 4
  27. .. .. ..$ python: num 3
  28. ..$ p2:List of 4
  29. .. ..$ name : chr "James"
  30. .. ..$ age : num 25
  31. .. ..$ interest: chr [1:2] "sports" "music"
  32. .. ..$ lang :List of 3
  33. .. .. ..$ r : num 3
  34. .. .. ..$ java: num 2
  35. .. .. ..$ cpp : num 5
  36. $ reading:List of 2
  37. ..$ p1:List of 4
  38. .. ..$ name : chr "Ken"
  39. .. ..$ age : num 24
  40. .. ..$ interest: chr [1:3] "reading" "music" "movies"
  41. .. ..$ lang :List of 3
  42. .. .. ..$ r : num 2
  43. .. .. ..$ csharp: num 4
  44. .. .. ..$ python: num 3
  45. ..$ p3:List of 4
  46. .. ..$ name : chr "Penny"
  47. .. ..$ age : num 24
  48. .. ..$ interest: chr [1:2] "movies" "reading"
  49. .. ..$ lang :List of 3
  50. .. .. ..$ r : num 1
  51. .. .. ..$ cpp : num 4
  52. .. .. ..$ python: num 2
  53. $ sports :List of 1
  54. ..$ p2:List of 4
  55. .. ..$ name : chr "James"
  56. .. ..$ age : num 25
  57. .. ..$ interest: chr [1:2] "sports" "music"
  58. .. ..$ lang :List of 3
  59. .. .. ..$ r : num 3
  60. .. .. ..$ java: num 2
  61. .. .. ..$ cpp : num 5

排序(sorting)

按照年龄升序排列:

  1. str(list.sort(devs, age))
  1. List of 3
  2. $ p1:List of 4
  3. ..$ name : chr "Ken"
  4. ..$ age : num 24
  5. ..$ interest: chr [1:3] "reading" "music" "movies"
  6. ..$ lang :List of 3
  7. .. ..$ r : num 2
  8. .. ..$ csharp: num 4
  9. .. ..$ python: num 3
  10. $ p3:List of 4
  11. ..$ name : chr "Penny"
  12. ..$ age : num 24
  13. ..$ interest: chr [1:2] "movies" "reading"
  14. ..$ lang :List of 3
  15. .. ..$ r : num 1
  16. .. ..$ cpp : num 4
  17. .. ..$ python: num 2
  18. $ p2:List of 4
  19. ..$ name : chr "James"
  20. ..$ age : num 25
  21. ..$ interest: chr [1:2] "sports" "music"
  22. ..$ lang :List of 3
  23. .. ..$ r : num 3
  24. .. ..$ java: num 2
  25. .. ..$ cpp : num 5

按照使用兴趣数量降序排列,然后按照R语言使用年数降序排列:

  1. str(list.sort(devs, desc(length(interest)), desc(lang$r)))
  1. List of 3
  2. $ p1:List of 4
  3. ..$ name : chr "Ken"
  4. ..$ age : num 24
  5. ..$ interest: chr [1:3] "reading" "music" "movies"
  6. ..$ lang :List of 3
  7. .. ..$ r : num 2
  8. .. ..$ csharp: num 4
  9. .. ..$ python: num 3
  10. $ p2:List of 4
  11. ..$ name : chr "James"
  12. ..$ age : num 25
  13. ..$ interest: chr [1:2] "sports" "music"
  14. ..$ lang :List of 3
  15. .. ..$ r : num 3
  16. .. ..$ java: num 2
  17. .. ..$ cpp : num 5
  18. $ p3:List of 4
  19. ..$ name : chr "Penny"
  20. ..$ age : num 24
  21. ..$ interest: chr [1:2] "movies" "reading"
  22. ..$ lang :List of 3
  23. .. ..$ r : num 1
  24. .. ..$ cpp : num 4
  25. .. ..$ python: num 2

更新(updating)

去除interestlang两个字段,加入nlang表示掌握语言数目,以及expert使用时间最长的语言名称:

  1. str(list.update(devs, interest=NULL, lang=NULL, nlang=length(lang),
  2. expert={
  3. longest <- sort(unlist(lang))[1]
  4. names(longest)
  5. }))
  1. List of 3
  2. $ p1:List of 4
  3. ..$ name : chr "Ken"
  4. ..$ age : num 24
  5. ..$ nlang : int 3
  6. ..$ expert: chr "r"
  7. $ p2:List of 4
  8. ..$ name : chr "James"
  9. ..$ age : num 25
  10. ..$ nlang : int 3
  11. ..$ expert: chr "java"
  12. $ p3:List of 4
  13. ..$ name : chr "Penny"
  14. ..$ age : num 24
  15. ..$ nlang : int 3
  16. ..$ expert: chr "r"

Lambda表达式

rlist中所有支持表达式计算的函数都支持 Lambda 表达式,允许用户访问列表元素的元数据(metadata),即元素本身、元素索引编号(index)、元素名称(name)。

  1. x <- list(a=c(1,2,3),b=c(3,4,5))
  2. list.map(x, sum(.))
  1. $a
  2. [1] 6
  3. $b
  4. [1] 12

在上面的代码中,.表示每个元素本身。此例中由于列表中每个元素都是一个数值向量,因此可以分别通过sum函数求和。如果不使用.来表示元素本身,可以通过形如 x
-> f(x)
 或者 x ~ f(x) 的 Lambda 表达式自定义符号。

  1. list.map(x, x -> sum(x))
  1. $a
  2. [1] 6
  3. $b
  4. [1] 12

默认情况下,.i表示当前元素的索引,.name表示当前元素的名称。下面用list.iter函数遍历x中的各个元素,对于每个元素显示自定义字符串。

  1. list.iter(x, cat(.name,":",.i,"\n"))
  1. a : 1
  2. b : 2

通过 Lambda 表达式自定义这些符号时,可以采用 f(x,i,name) -> expression 的形式,例如:

  1. list.map(x, f(x,i) -> x*i)
  1. $a
  2. [1] 1 2 3
  3. $b
  4. [1] 6 8 10

管道操作

由于rlist中函数结构设计具有很强的一致性,推荐和pipeR扩展包中定义的管道操作符一同使用,使得R中的非关系型数据操作易读、可维护。

下面的代码通过结合管道操作选择出喜欢音乐并且使用R的开发者的名字和年龄,结果组合成一个data.frame

  1. library(pipeR)
  2. devs %>>%
  3. list.filter("music" %in% interest & "r" %in% names(lang)) %>>%
  4. list.select(name,age) %>>%
  5. list.rbind %>>%
  6. data.frame
  1. name age
  2. p1 Ken 24
  3. p2 James 25

包含结构化对象的列表

下面是一个更为复杂的例子,其中涉及到生成一列 data.frame、处理一列线性模型等等:

  1. set.seed(1)
  2. 1:10 %>>%
  3. list.map(i -> {
  4. x <- rnorm(1000)
  5. y <- i * x + rnorm(1000)
  6. data.frame(x=x,y=y)
  7. }) %>>%
  8. list.map(df -> lm(y~x)) %>>%
  9. list.update(summary = m -> summary(m)) %>>%
  10. list.sort(m -> desc(summary$r.squared)) %>>%
  11. list.map(c(rsq=summary$r.squared, coefficients)) %>>%
  12. list.rbind %>>%
  13. data.frame
  1. rsq X.Intercept. x
  2. 1 0.9896 -0.032250 9.986
  3. 2 0.9871 0.031999 8.970
  4. 3 0.9832 -0.001191 7.993
  5. 4 0.9802 0.004400 6.958
  6. 5 0.9684 -0.034238 6.008
  7. 6 0.9626 0.007260 4.941
  8. 7 0.9450 -0.004309 3.995
  9. 8 0.8997 -0.012472 2.962
  10. 9 0.7994 0.016558 2.011
  11. 10 0.5008 -0.016187 1.006

其他功能

除了上述函数之外,rlist扩展包还提供了许多其他函数,这里只做简单介绍:

  • list.join:根表达式合并两个list
  • list.parse:将其他类型的对象转换为结构相同的list
  • list.loadlist.save:读写JSON, YAML, RData格式的list
  • list.iflist.whichlist.anylist.all:list元素的逻辑判断
  • list.findlist.findi:在list中按照表达式寻找指定数量的元素

详细介绍请参见帮助文档:

  1. help(package = rlist)

以及应用手册:

  1. vignette("introduction", package = "rlist")

参考:http://cos.name/2014/07/rlist-package/

R语言︱非结构化数据处理神器——rlist包的更多相关文章

  1. spark结构化数据处理:Spark SQL、DataFrame和Dataset

    本文讲解Spark的结构化数据处理,主要包括:Spark SQL.DataFrame.Dataset以及Spark SQL服务等相关内容.本文主要讲解Spark 1.6.x的结构化数据处理相关东东,但 ...

  2. Spark如何与深度学习框架协作,处理非结构化数据

    随着大数据和AI业务的不断融合,大数据分析和处理过程中,通过深度学习技术对非结构化数据(如图片.音频.文本)进行大数据处理的业务场景越来越多.本文会介绍Spark如何与深度学习框架进行协同工作,在大数 ...

  3. Python爬虫(九)_非结构化数据与结构化数据

    爬虫的一个重要步骤就是页面解析与数据提取.更多内容请参考:Python学习指南 页面解析与数据提取 实际上爬虫一共就四个主要步骤: 定(要知道你准备在哪个范围或者网站去搜索) 爬(将所有的网站的内容全 ...

  4. Apache Sqoop 结构化、非结构化数据转换工具

    简介: Apache Sqoop 是一种用于 Apache Hadoop 与关系型数据库之间结构化.非结构化数据转换的工具. 一.安装 MySQL.导入测试数据 1.文档链接:http://www.c ...

  5. SQL语言:结构化查询语言

    SQL语言:结构化查询语言 程序员或者DBA(数据库管理员)使用SQL和DBBSM进行交互,操纵数据库中的资源 分类: 1.DDL 数据定义语言 结构 create  创建   database ta ...

  6. MySQL 5.7:非结构化数据存储的新选择

    本文转载自:http://www.innomysql.net/article/23959.html (只作转载, 不代表本站和博主同意文中观点或证实文中信息) 工作10余年,没有一个版本能像MySQL ...

  7. Spark SQL结构化数据处理

    Spark SQL是Spark框架的重要组成部分, 主要用于结构化数据处理和对Spark数据执行类SQL的查询. DataFrame是一个分布式的,按照命名列的形式组织的数据集合. 一张SQL数据表可 ...

  8. hbase非结构化数据库与结构化数据库比较

    目的:了解hbase与支持海量数据查询的特性以及实现方式 传统关系型数据库特点及局限 传统数据库事务性特别强,要求数据完整性及安全性,造成系统可用性以及伸缩性大打折扣.对于高并发的访问量,数据库性能不 ...

  9. 结构化数据(structured),半结构化数据(semi-structured),非结构化数据(unstructured)

    概念 结构化数据:即行数据,存储在数据库里,可以用二维表结构来逻辑表达实现的数据. 半结构化数据:介于完全结构化数据(如关系型数据库.面向对象数据库中的数据)和完全无结构的数据(如声音.图像文件等)之 ...

随机推荐

  1. python下用OpenCV的圆形检测

    写在文章前 这些天因为工作需要要学习图像检测,笨笨的我啥都不会要盯着OpenCV重头开始学(:′⌒`),甚至查资料能力都很弱弱〒▽〒 夸一下我最好的男票(*^▽^*)  男盆友也不是做图像处理的 但是 ...

  2. Spring MVC的DispatcherServlet

    Spring MVC提供了一个名为org.springframework.web.servlet.DispatcherServlet的Selvet充当前端控制器,所有的请求驱动都围绕这个Dispatc ...

  3. ElasticSearch 6 Windows 安装

    前言 目前使用ElasticSearch 6.2最新版本,这里记录其在windows 2012R2系统上的安装步骤. 安装 1. 安装java,最新版本的ElasticSearch 需要java8 版 ...

  4. Sonar 数据库表关系整理一(续)

    更多原创测试技术文章同步更新到微信公众号 :三国测,敬请扫码关注个人的微信号,感谢! 简介:Sonar平台是目前较为流行的静态代码扫描平台,为了便于使用以及自己二次开发,有必要对它的数据库结构进行学习 ...

  5. 使用TensorFlow Object Detection API+Google ML Engine训练自己的手掌识别器

    上次使用Google ML Engine跑了一下TensorFlow Object Detection API中的Quick Start(http://www.cnblogs.com/take-fet ...

  6. Python基础篇(六)

    retun空值,后面的语句将不再被执行 >>> def test(): ...    print("just a test!") ...    return .. ...

  7. bzoj 2627: JZPKIL [伯努利数 Pollard-rho]

    2627: JZPKIL 题意:求 \[ \sum_{i=1}^n (n,i)^x [i,n]^y,\ [i,n] = lcm(i,n) \] \(n \le 10^{18},\ x,y\le 300 ...

  8. IO&&Serize 利用线程Thread.Sleep实现"自动输出"

    查看链接 https://github.com/jungle8884/C-.Net/tree/MyClassLibrary using System; using System.Collections ...

  9. 关于ES6 用箭头函数后的 this 指向问题

    最近写完小程序后, 开始学习React, 因为有编译器, 就直接用ES6 新语法了, 中间自然离不开  () => { console.log('箭头函数的this是指向哪的问题')}; var ...

  10. GitHub中开启二次验证Two-factor authentication,如何在命令行下更新和上传代码

    最近在使用GitHub管理代码,在git命令行管理代码时候遇到一些问题.如果开起了二次验证(Two-factor authentication两个要素认证),命令行会一直提示输入用户名和密码.查找了一 ...