R语言︱非结构化数据处理神器——rlist包
本文作者:任坤,厦门大学王亚南经济研究院金融硕士生,研究兴趣为计算统计和金融量化交易,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 |
可以发现,第一个表中的关系型数据可以简单地放入矩形的数据表,而第二个表中的非关系型数据中Interest和Language本身并不是单一值的字段,因而如果在关系型数据库中表示,可能需要建立多个表和关系来存储。
对于这种数据的处理,MongoDB是较为成熟的解决方案之一。在R中,data.frame可以用来很好地描述关系型数据表,也有data.table, dplyr等扩展包可以方便地处理这类数据。而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)
去除interest和lang两个字段,加入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:根表达式合并两个listlist.parse:将其他类型的对象转换为结构相同的listlist.load,list.save:读写JSON, YAML, RData格式的listlist.if,list.which,list.any,list.all:list元素的逻辑判断list.find,list.findi:在list中按照表达式寻找指定数量的元素- …
详细介绍请参见帮助文档:
help(package = rlist)
以及应用手册:
vignette("introduction", package = "rlist")
参考:http://cos.name/2014/07/rlist-package/
R语言︱非结构化数据处理神器——rlist包的更多相关文章
- spark结构化数据处理:Spark SQL、DataFrame和Dataset
本文讲解Spark的结构化数据处理,主要包括:Spark SQL.DataFrame.Dataset以及Spark SQL服务等相关内容.本文主要讲解Spark 1.6.x的结构化数据处理相关东东,但 ...
- Spark如何与深度学习框架协作,处理非结构化数据
随着大数据和AI业务的不断融合,大数据分析和处理过程中,通过深度学习技术对非结构化数据(如图片.音频.文本)进行大数据处理的业务场景越来越多.本文会介绍Spark如何与深度学习框架进行协同工作,在大数 ...
- Python爬虫(九)_非结构化数据与结构化数据
爬虫的一个重要步骤就是页面解析与数据提取.更多内容请参考:Python学习指南 页面解析与数据提取 实际上爬虫一共就四个主要步骤: 定(要知道你准备在哪个范围或者网站去搜索) 爬(将所有的网站的内容全 ...
- Apache Sqoop 结构化、非结构化数据转换工具
简介: Apache Sqoop 是一种用于 Apache Hadoop 与关系型数据库之间结构化.非结构化数据转换的工具. 一.安装 MySQL.导入测试数据 1.文档链接:http://www.c ...
- SQL语言:结构化查询语言
SQL语言:结构化查询语言 程序员或者DBA(数据库管理员)使用SQL和DBBSM进行交互,操纵数据库中的资源 分类: 1.DDL 数据定义语言 结构 create 创建 database ta ...
- MySQL 5.7:非结构化数据存储的新选择
本文转载自:http://www.innomysql.net/article/23959.html (只作转载, 不代表本站和博主同意文中观点或证实文中信息) 工作10余年,没有一个版本能像MySQL ...
- Spark SQL结构化数据处理
Spark SQL是Spark框架的重要组成部分, 主要用于结构化数据处理和对Spark数据执行类SQL的查询. DataFrame是一个分布式的,按照命名列的形式组织的数据集合. 一张SQL数据表可 ...
- hbase非结构化数据库与结构化数据库比较
目的:了解hbase与支持海量数据查询的特性以及实现方式 传统关系型数据库特点及局限 传统数据库事务性特别强,要求数据完整性及安全性,造成系统可用性以及伸缩性大打折扣.对于高并发的访问量,数据库性能不 ...
- 结构化数据(structured),半结构化数据(semi-structured),非结构化数据(unstructured)
概念 结构化数据:即行数据,存储在数据库里,可以用二维表结构来逻辑表达实现的数据. 半结构化数据:介于完全结构化数据(如关系型数据库.面向对象数据库中的数据)和完全无结构的数据(如声音.图像文件等)之 ...
随机推荐
- Swing EDT引起的客户端卡死
最近调试程序时发现,点击某个界面时会出现卡死的情况,出现的频率还是比较频繁的. 再次出现卡死的情况后,利用jvisualvm查看线程的运行情况,dump操作之后发现线程间出现了死锁: Found on ...
- 洛谷 [P1020] 导弹拦截 (N*logN)
首先此一眼就能看出来是一个非常基础的最长不下降子序列(LIS),其朴素的 N^2做法很简单,但如何将其优化成为N*logN? 我们不妨换一个思路,维护一个f数组,f[x]表示长度为x的LIS的最大的最 ...
- BZOJ 1076: [SCOI2008]奖励关 [DP 期望 状压]
传送门 题意:$n$种宝物,出现$k$次每次一种,每种宝物有价值和吃掉它之前必须要吃掉的宝物的集合,求采取最优策略的期望最大价值 1<=k<=100,1<=n<=15,分值为[ ...
- CF 2015 ICL, Finals, Div. 1 J. Ceizenpok’s formula [Lucas定理]
http://codeforces.com/gym/100633/problem/J Lucas定理P不是质数裸题 #include <iostream> #include <cst ...
- POJ2891 Strange Way to Express Integers [中国剩余定理]
不互质情况的模板题 注意多组数据不要一发现不合法就退出 #include <iostream> #include <cstdio> #include <cstring&g ...
- BZOJ 1018: [SHOI2008]堵塞的交通traffic [线段树 区间信息]
1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec Memory Limit: 162 MBSubmit: 3064 Solved: 1027[Submi ...
- C# 简单内存补丁
写在开头:看了一些视频教程,感觉OD为什么别人学个破解那么容易,我就那么难了呢,可能是没有那么多时间吧. 解释:个人见解:所谓内存补丁,即:通过修改运行程序的内容,来达到某种目的的操作.修改使用Ope ...
- 关于 iOS 分类(Category)的实现代码
其实质是对一个类的扩充,对类扩充的方法有两种: (1)通过继承(经常用到) (2)通过分类 一个已知类Name 其头文件Name.h #import <Foundation/Foundation ...
- CENTOS6.6 下mysql MHA架构搭建
本文来自我的github pages博客http://galengao.github.io/ 即www.gaohuirong.cn 摘要: 本篇是自己搭建的一篇mysql MHA文章 前面的安装步骤基 ...
- Linux 上 C 程序的内存布局
在仔细研究这个问题之前,我认为 C 程序在内存中只有代码段,堆和栈三部分构成.前几天面试被问到了这个问题,才发现自己的印象是不完全的. 在本文中通过解析析一个 C 程序中变量和函数的地址来分析 C 程 ...