本文作者:任坤,厦门大学王亚南经济研究院金融硕士生,研究兴趣为计算统计和金融量化交易,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最新的开发版本:

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

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

library(rlist)
devs <-
  list(
    p1=list(name="Ken",age=24,
      interest=c("reading","music","movies"),
      lang=list(r=2,csharp=4,python=3)),
    p2=list(name="James",age=25,
      interest=c("sports","music"),
      lang=list(r=3,java=2,cpp=5)),
    p3=list(name="Penny",age=24,
      interest=c("movies","reading"),
      lang=list(r=1,cpp=4,python=2)))
str(devs)
List of 3
 $ p1:List of 4
  ..$ name    : chr "Ken"
  ..$ age     : num 24
  ..$ interest: chr [1:3] "reading" "music" "movies"
  ..$ lang    :List of 3
  .. ..$ r     : num 2
  .. ..$ csharp: num 4
  .. ..$ python: num 3
 $ p2:List of 4
  ..$ name    : chr "James"
  ..$ age     : num 25
  ..$ interest: chr [1:2] "sports" "music"
  ..$ lang    :List of 3
  .. ..$ r   : num 3
  .. ..$ java: num 2
  .. ..$ cpp : num 5
 $ p3:List of 4
  ..$ name    : chr "Penny"
  ..$ age     : num 24
  ..$ interest: chr [1:2] "movies" "reading"
  ..$ lang    :List of 3
  .. ..$ r     : num 1
  .. ..$ cpp   : num 4
  .. ..$ python: num 2

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

映射(mapping)

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

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

list.map(devs, age)
$p1
[1] 24

$p2
[1] 25

$p3
[1] 24

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

list.map(devs, mean(as.numeric(lang)))
$p1
[1] 3

$p2
[1] 3.333

$p3
[1] 2.333

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

list.map(devs, names(lang))
$p1
[1] "r"      "csharp" "python"

$p2
[1] "r"    "java" "cpp" 

$p3
[1] "r"      "cpp"    "python"

筛选(filtering)

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

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

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

str(list.filter(devs, "r" %in% names(lang)))
List of 3
 $ p1:List of 4
  ..$ name    : chr "Ken"
  ..$ age     : num 24
  ..$ interest: chr [1:3] "reading" "music" "movies"
  ..$ lang    :List of 3
  .. ..$ r     : num 2
  .. ..$ csharp: num 4
  .. ..$ python: num 3
 $ p2:List of 4
  ..$ name    : chr "James"
  ..$ age     : num 25
  ..$ interest: chr [1:2] "sports" "music"
  ..$ lang    :List of 3
  .. ..$ r   : num 3
  .. ..$ java: num 2
  .. ..$ cpp : num 5
 $ p3:List of 4
  ..$ name    : chr "Penny"
  ..$ age     : num 24
  ..$ interest: chr [1:2] "movies" "reading"
  ..$ lang    :List of 3
  .. ..$ r     : num 1
  .. ..$ cpp   : num 4
  .. ..$ python: num 2

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

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

分组(grouping)

按照年龄做互斥分组:

str(list.group(devs, age))
List of 2
 $ 24:List of 2
  ..$ p1:List of 4
  .. ..$ name    : chr "Ken"
  .. ..$ age     : num 24
  .. ..$ interest: chr [1:3] "reading" "music" "movies"
  .. ..$ lang    :List of 3
  .. .. ..$ r     : num 2
  .. .. ..$ csharp: num 4
  .. .. ..$ python: num 3
  ..$ p3:List of 4
  .. ..$ name    : chr "Penny"
  .. ..$ age     : num 24
  .. ..$ interest: chr [1:2] "movies" "reading"
  .. ..$ lang    :List of 3
  .. .. ..$ r     : num 1
  .. .. ..$ cpp   : num 4
  .. .. ..$ python: num 2
 $ 25:List of 1
  ..$ p2:List of 4
  .. ..$ name    : chr "James"
  .. ..$ age     : num 25
  .. ..$ interest: chr [1:2] "sports" "music"
  .. ..$ lang    :List of 3
  .. .. ..$ r   : num 3
  .. .. ..$ java: num 2
  .. .. ..$ cpp : num 5

按照兴趣做非互斥分组:

str(list.class(devs, interest))
List of 4
 $ movies :List of 2
  ..$ p1:List of 4
  .. ..$ name    : chr "Ken"
  .. ..$ age     : num 24
  .. ..$ interest: chr [1:3] "reading" "music" "movies"
  .. ..$ lang    :List of 3
  .. .. ..$ r     : num 2
  .. .. ..$ csharp: num 4
  .. .. ..$ python: num 3
  ..$ p3:List of 4
  .. ..$ name    : chr "Penny"
  .. ..$ age     : num 24
  .. ..$ interest: chr [1:2] "movies" "reading"
  .. ..$ lang    :List of 3
  .. .. ..$ r     : num 1
  .. .. ..$ cpp   : num 4
  .. .. ..$ python: num 2
 $ music  :List of 2
  ..$ p1:List of 4
  .. ..$ name    : chr "Ken"
  .. ..$ age     : num 24
  .. ..$ interest: chr [1:3] "reading" "music" "movies"
  .. ..$ lang    :List of 3
  .. .. ..$ r     : num 2
  .. .. ..$ csharp: num 4
  .. .. ..$ python: num 3
  ..$ p2:List of 4
  .. ..$ name    : chr "James"
  .. ..$ age     : num 25
  .. ..$ interest: chr [1:2] "sports" "music"
  .. ..$ lang    :List of 3
  .. .. ..$ r   : num 3
  .. .. ..$ java: num 2
  .. .. ..$ cpp : num 5
 $ reading:List of 2
  ..$ p1:List of 4
  .. ..$ name    : chr "Ken"
  .. ..$ age     : num 24
  .. ..$ interest: chr [1:3] "reading" "music" "movies"
  .. ..$ lang    :List of 3
  .. .. ..$ r     : num 2
  .. .. ..$ csharp: num 4
  .. .. ..$ python: num 3
  ..$ p3:List of 4
  .. ..$ name    : chr "Penny"
  .. ..$ age     : num 24
  .. ..$ interest: chr [1:2] "movies" "reading"
  .. ..$ lang    :List of 3
  .. .. ..$ r     : num 1
  .. .. ..$ cpp   : num 4
  .. .. ..$ python: num 2
 $ sports :List of 1
  ..$ p2:List of 4
  .. ..$ name    : chr "James"
  .. ..$ age     : num 25
  .. ..$ interest: chr [1:2] "sports" "music"
  .. ..$ lang    :List of 3
  .. .. ..$ r   : num 3
  .. .. ..$ java: num 2
  .. .. ..$ cpp : num 5

排序(sorting)

按照年龄升序排列:

str(list.sort(devs, age))
List of 3
 $ p1:List of 4
  ..$ name    : chr "Ken"
  ..$ age     : num 24
  ..$ interest: chr [1:3] "reading" "music" "movies"
  ..$ lang    :List of 3
  .. ..$ r     : num 2
  .. ..$ csharp: num 4
  .. ..$ python: num 3
 $ p3:List of 4
  ..$ name    : chr "Penny"
  ..$ age     : num 24
  ..$ interest: chr [1:2] "movies" "reading"
  ..$ lang    :List of 3
  .. ..$ r     : num 1
  .. ..$ cpp   : num 4
  .. ..$ python: num 2
 $ p2:List of 4
  ..$ name    : chr "James"
  ..$ age     : num 25
  ..$ interest: chr [1:2] "sports" "music"
  ..$ lang    :List of 3
  .. ..$ r   : num 3
  .. ..$ java: num 2
  .. ..$ cpp : num 5

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

str(list.sort(devs, desc(length(interest)), desc(lang$r)))
List of 3
 $ p1:List of 4
  ..$ name    : chr "Ken"
  ..$ age     : num 24
  ..$ interest: chr [1:3] "reading" "music" "movies"
  ..$ lang    :List of 3
  .. ..$ r     : num 2
  .. ..$ csharp: num 4
  .. ..$ python: num 3
 $ p2:List of 4
  ..$ name    : chr "James"
  ..$ age     : num 25
  ..$ interest: chr [1:2] "sports" "music"
  ..$ lang    :List of 3
  .. ..$ r   : num 3
  .. ..$ java: num 2
  .. ..$ cpp : num 5
 $ p3:List of 4
  ..$ name    : chr "Penny"
  ..$ age     : num 24
  ..$ interest: chr [1:2] "movies" "reading"
  ..$ lang    :List of 3
  .. ..$ r     : num 1
  .. ..$ cpp   : num 4
  .. ..$ python: num 2

更新(updating)

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

str(list.update(devs, interest=NULL, lang=NULL, nlang=length(lang),
  expert={
    longest <- sort(unlist(lang))[1]
    names(longest)
  }))
List of 3
 $ p1:List of 4
  ..$ name  : chr "Ken"
  ..$ age   : num 24
  ..$ nlang : int 3
  ..$ expert: chr "r"
 $ p2:List of 4
  ..$ name  : chr "James"
  ..$ age   : num 25
  ..$ nlang : int 3
  ..$ expert: chr "java"
 $ p3:List of 4
  ..$ name  : chr "Penny"
  ..$ age   : num 24
  ..$ nlang : int 3
  ..$ expert: chr "r"

Lambda表达式

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

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

$b
[1] 12

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

list.map(x, x -> sum(x))
$a
[1] 6

$b
[1] 12

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

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

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

list.map(x, f(x,i) -> x*i)
$a
[1] 1 2 3

$b
[1]  6  8 10

管道操作

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

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

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

包含结构化对象的列表

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

set.seed(1)
1:10 %>>%
  list.map(i -> {
    x <- rnorm(1000)
    y <- i * x + rnorm(1000)
    data.frame(x=x,y=y)
  }) %>>%
  list.map(df -> lm(y~x)) %>>%
  list.update(summary = m -> summary(m)) %>>%
  list.sort(m -> desc(summary$r.squared)) %>>%
  list.map(c(rsq=summary$r.squared, coefficients)) %>>%
  list.rbind %>>%
  data.frame
      rsq X.Intercept.     x
1  0.9896    -0.032250 9.986
2  0.9871     0.031999 8.970
3  0.9832    -0.001191 7.993
4  0.9802     0.004400 6.958
5  0.9684    -0.034238 6.008
6  0.9626     0.007260 4.941
7  0.9450    -0.004309 3.995
8  0.8997    -0.012472 2.962
9  0.7994     0.016558 2.011
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中按照表达式寻找指定数量的元素

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

help(package = rlist)

以及应用手册:

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. Java并发系列[4]----AbstractQueuedSynchronizer源码分析之条件队列

    通过前面三篇的分析,我们深入了解了AbstractQueuedSynchronizer的内部结构和一些设计理念,知道了AbstractQueuedSynchronizer内部维护了一个同步状态和两个排 ...

  2. 浅谈对SpringMVC的认识

    SpringMVC概念:     他是一个轻量级的开源框架,应用于表现层,基于MVC的设计模式. SpringMVC的特点:     1.他是单例的可以设置成多例.     2.他的线程是安全的    ...

  3. 面向对象编程之super内置函数的用法

    先来看一段代码: 定义一个名叫People的父类,又定义了一个叫Teacher的老师类和一个叫Student的学生类 来继承People的类,并根据这两个子类实例化出两个对象s1和t1. class ...

  4. Java8之Lambda表达式基础

    Java 8中,将会提供对lambda的支持,函数式编程FP(Functional Programming)将会得到很好地支持,而函数式编程的一个重要特点就是适合并行运算. λ:希腊字母表中排序第十一 ...

  5. FTP工具

    上传本地资源到FTP服务器,可以使用LeapFTP软件.左侧为本地资源,右侧为FTP资源.输入用户名,密码,连接后直接拖动即可. 为本地资源建立FTP,可以方便进行设备升级.文件传输等.

  6. BZOJ 4078: [Wf2014]Metal Processing Plant [放弃了]

    以后再也不做$World Final$的题了................ 还我下午 bzoj上TLE一次后就不敢交了然后去uva交 Claris太神了代码完全看不懂 还有一个代码uva上竟然WA了 ...

  7. BZOJ 1951: [Sdoi2010]古代猪文 [Lucas定理 中国剩余定理]

    1951: [Sdoi2010]古代猪文 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 2194  Solved: 919[Submit][Status] ...

  8. 福建百度seo和推广,关键词排名优化,网络营销推广培训

    福建百度seo和推广,关键词排名优化,网络营销推广培训 福建百度seo和推广,关键词排名优化,网络营销推广培训,那么如何才能够让自己的文章信息被百度收录呢?只要说自己的文章能够被百度收录,那么你的信息 ...

  9. 简单认识一下什么是vue-router

    什么是vue-router? 用通俗一点的话来讲,其实就是一个url和组件之间的映射关系,当我们访问不同的url的时候在页面渲染不同的组件 vue-router怎么用? vue-router作为一个v ...

  10. NoSQLBooster for MongoDB的基本使用

    连接 File -> Quik Connect ( Ctrl + Shift + N ) 或 Connect -> From URI 填入 mongodb://username:passw ...