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)
概念 结构化数据:即行数据,存储在数据库里,可以用二维表结构来逻辑表达实现的数据. 半结构化数据:介于完全结构化数据(如关系型数据库.面向对象数据库中的数据)和完全无结构的数据(如声音.图像文件等)之 ...
随机推荐
- Core Animation 文档翻译 (第五篇)
构建Layer层次结构 在APP中大多数情况下,将Layer和View对象结合使用是Layer最好的使用方式.然而,很多时候我们可能需要通过添加单独的Layer对象,以便增加视图继承层次:当为了提 ...
- Effective Java 之 --- 用私有构造器或者枚举类型强化Singleton属性
Singleton指仅仅被实例化一次的类,通常用来代表那些本质上唯一的系统组件,实现Singleton有三种方法: 1)公有静态成员是个final域,享有特权的用户可以调用AccessibleObje ...
- UVW源码漫谈(三)
咱们继续看uvw的源码,这次看的东西比较多,去除底层的一些东西,很多代码都是连贯的,耦合度也比较高了.主要包括下面几个文件的代码: underlying_type.hpp resource.hpp l ...
- 使用webpack、babel、react、antdesign配置单页面应用开发环境
这是Webpack+React系列配置过程记录的第一篇.其他内容请参考: 第一篇:使用webpack.babel.react.antdesign配置单页面应用开发环境 第二篇:使用react-rout ...
- 夏令营提高班上午上机测试 Day 4 解题报告
我要是没记错的话,今天的题难度算挺适中的. *标程来自高天宇哥哥 T1:小G的字符串 题目描述 有一天,小 L 给小 G 出了这样一道题:生成一个长度为 n 的.全由小写英文字母构成的字符串,只能使用 ...
- POJ3155 Hard Life [最大密度子图]
题意:最大密度子图 #include<iostream> #include<cstdio> #include<cstring> #include<algo ...
- HDU 4349 Xiao Ming's Hope [Lucas定理 二进制]
这种题面真是够了......@小明 题意:the number of odd numbers of C(n,0),C(n,1),C(n,2)...C(n,n). 奇数...就是mod 2=1啊 用Lu ...
- C#查询XML解决“需要命名空间管理器”问题
在查询xml时有时会遇到带有前缀的xml,例如:"<ows:Keyword></ows:Keyword>" 这时像往常一样查询就会报错,类似于"需 ...
- ACE_TEST1.obj : error LNK2019: 无法解析的外部符号
ACE_TEST1.obj : error LNK2019: 无法解析的外部符号 "int __cdecl ace_main_i(int,char * * const)" (?ac ...
- WPF项目学习.二
WPF用MVVM的解决记录 版权声明:本文为博主初学经验,未经博主允许不得转载. 一.前言 记录在学习与制作WPF过程中遇到的解决方案. 焦点的控制,键盘事件触发,输入框的数字限制,异步处理,隐藏状 ...