在第一节中,我们回顾了许多用于操作数据框的内置函数。然后,了解了 sqldf 扩展
包,它使得简单的数据查询和统计变得更简便。然而,两种方法都有各自的局限性。使用
内置函数可能既繁琐又缓慢,而相对于各式各样的 R 函数来说,SQL 又不够强大,所以用

sqldf 进行数据的汇总统计,也不容易。
data.table 包提供了一个加强版的 data.frame。它运行效率极高,而且能够处
理适合内存的大数据集,它通过 [ ] 实现了一种自然的数据操作语法。如果尚未安装,
请运行以下命令:
install.packages("data.table")
安装成功后,我们就可以加载它,并查看它都提供了些什么:
library(data.table)
##
## Attaching package: 'data.table'
## The following objects are masked from 'package:reshape2':
##
## dcast, melt
注 意 到, 前 面 加 载 的 reshape2 包 中 已 经 定 义 了 dcast( ) 和 melt( ) 。
data.table 包提供了加强版的 dcast( ) 和 melt( ),它们的功能更强大,性能更高,
内存使用也更高效。本节的后续部分我们将介绍它们。
创建一个 data.table 与创建一个 data.frame 非常相似:
dt <- data.table(x = 1:3, y = rnorm(3), z = letters[1:3])
d
## x y z
## 1: 1 -0.2469598 a
## 2: 2 1.4126529 b
## 3: 3 -1.2174483 c
通过 str( ) 查看它的结构:
str(dt)
## Classes 'data.table' and 'data.frame': 3 obs. of 3 variables:
## $ x: int 1 2 3
## $ y: num -0.247 1.413 -1.217
## $ z: chr "a" "b" "c"
## - attr(*, ".internal.selfref") = <externalptr>
很明显,dt 的类是 data.table 和 data.frame,这意味着 data.table 继承自
data.frame。换句话说,它继承了 data.frame 的一些行为,但是增强了其他部分。
data.table 的基本语法 dt[i,j,by]。简单来说,就是使用 i 选择行,用 by 分组,
然后计算 j。接下来我们就看看 data.table 具体继承了什么,增强了什么。
首先,仍然先载入产品数据。但这次我们使用 data.table 包中的 fread( )函数来
读取数据。fread( ) 函数非常快,内存效率很高,而且直接返回了 data.table:
product_info <- fread("data/product-info.csv")
product_stats <- fread("data/product-stats.csv")
product_tests <- fread("data/product-tests.csv")
toy_tests <- fread("data/product-toy-tests.csv")
如果查看 product_info,可以看到它的数据格式与 data.frame 几乎是一样:
product_info
## id name type class released
## 1: T01 SupCar toy vehicle yes
## 2: T02 SupPlane toy vehicle no
## 3: M01 JeepX model vehicle yes
## 4: M02 AircraftX model vehicle yes
## 5: M03 Runner model people yes
## 6: M04 Dancer model people no
再次查看它的结构:
str(product_info)
## Classes 'data.table' and 'data.frame': 6 obs. of 5 variables:
## $ id : chr "T01" "T02" "M01" "M02" ...
## $ name : chr "SupCar" "SupPlane" "JeepX" "AircraftX" ...
## $ type : chr "toy" "toy" "model" "model" ...
## $ class : chr "vehicle" "vehicle" "vehicle" "vehicle" ...
## $ released: chr "yes" "no" "yes" "yes" ...
## - attr(*, ".internal.selfref")=<externalptr>
与 data.frame 不同,如果对 data.table 只提供一个参数来构建子集的话,是选
择行而不是选择列:
product_info[1]
## id name type class released
## 1: T01 SupCar toy vehicle yes
product_info[1:3]
## id name type class released
## 1: T01 SupCar toy vehicle yes
## 2: T02 SupPlane toy vehicle no
## 3: M01 JeepX model vehicle yes
如果为 [ ] 提供负值,意味着排除对应记录(行),这与构建向量子集完全一致:
product_info[-1]
## id name type class released
## 1: T02 SupPlane toy vehicle no
## 2: M01 JeepX model vehicle yes
## 3: M02 AircraftX model vehicle yes
## 4: M03 Runner model people yes
## 5: M04 Dancer model people no
此外,data.table 也提供了许多特殊符号,它们是data.table 的重要组成部分。.N 是
最有用的符号之一,它表示在当前的分组中,对象的数目(即每组的行数)。有了这个符号,我们
就不必再用nrow(product_info) 计算行数。但是在 [ ] 中单独使用 .N 是指提取最后一行:
product_info[.N]
## id name type class released
## 1: M04 Dancer model people no
也可以轻松地选择第一和最后一行:
product_info[c(1, .N)]
## id name type class released
## 1: T01 SupCar toy vehicle yes
## 2: M04 Dancer model people no
在对 data.table 构建子集时,能够根据语义自动地计算表达式。也就是说,在选取列
时,可以直接使用列名,就像使用 subset( )、transform( ) 和 with( )一样。例如,
选择已经发布的产品时,我们可以直接使用 released 作为第 1 个参数来选择满足条件的行:
product_info[released == "yes"]
## id name type class released
## 1: T01 SupCar toy vehicle yes
## 2: M01 JeepX model vehicle yes
## 3: M02 AircraftX model vehicle yes
## 4: M03 Runner model people yes
方括号内的第 1 个参数是行筛选器,第 2 个则对筛选后的数据进行适当地计算(包括
选择某些列或执行某个表达式)。例如,我们可以直接使用 id 来表达 roduct_info$id,
这里提取满足 released 取值为 yes 的 id 列:
product_info[released == "yes", id]
## [1] "T01" "M01" "M02" "M03"
而选择 data.frame 的列的方式(“id”)在这里不起作用。如果把一个字符向量作为
第 2 个参数,就会得到这个字符向量本身,因为一个字符串就只是表示一个字符串,可以
试一下:
product_info[released == "yes", "id"]
## [1] "id"
为了避免这种情况,我们可以设定 with = FALSE。这样,第 2 个参数就可以根据字
符向量选择列,并且不论指定多少列,总是返回 data.table:
product_info[released == "yes", "id", with = FALSE]
## id
## 1: T01
## 2: M01
## 3: M02
## 4: M03
product_info[released == "yes", c("id", "name"), with = FALSE]
## id name
## 1: T01 SupCar
## 2: M01 JeepX
## 3: M02 AircraftX
## 4: M03 Runner
第 2 个参数也可以是表达式。例如,生成一张表,用于反映每种 type 和 class 的组
合中的 released 取值为 yes 的产品数量:
product_info[released == "yes", table(type, class)]
## class
## type people vehicle
## model 1 2
## toy 0 1
要注意是,给第 2 个参数提供 list(),它仍然会被转换为 data.table:
product_info[released == "yes", list(id, name)]
## id name
## 1: T01 SupCar
392 第 12 章 数据操作
## 2: M01 JeepX
## 3: M02 AircraftX
## 4: M03 Runner
此外,我们也可以轻松地生成一个替换原有列的新的 data.table:
product_info[, list(id, name, released = released == "yes")]
## id name released
## 1: T01 SupCar TRUE
## 2: T02 SupPlane FALSE
## 3: M01 JeepX TRUE
## 4: M02 AircraftX TRUE
## 5: M03 Runner TRUE
## 6: M04 Dancer FALSE
还可以利用原有列来创建新列,并生成新的 data.table:
product_stats[, list(id, material, size, weight, density = size / weight)]
## id material size weight density
## 1: T01 Metal 120 10.0 12.000000
## 2: T02 Metal 350 45.0 7.777778
## 3: M01 Plastics 50 NA NA
## 4: M02 Plastics 85 3.0 28.333333
## 5: M03 Wood 15 NA NA
## 6: M04 Wood 16 0.6 26.666667
为了简化,data.table 为 list( ) 提供了缩写.( ),即 .( ) 和 list( ) 是等价的:
product_info[, .(id, name, type, class)]
## id name type class
## 1: T01 SupCar toy vehicle
## 2: T02 SupPlane toy vehicle
## 3: M01 JeepX model vehicle
## 4: M02 AircraftX model vehicle
## 5: M03 Runner model people
## 6: M04 Dancer model people
product_info[released == "yes", .(id, name)]
## id name
## 1: T01 SupCar
## 2: M01 JeepX
## 3: M02 AircraftX
## 4: M03 Runner
通过提供排序索引,我们可以根据既定的要求对记录进行排序:
product_stats[order(size, decreasing = TRUE)]
## id material size weight
## 1: T02 Metal 350 45.0
## 2: T01 Metal 120 10.0
## 3: M02 Plastics 85 3.0
## 4: M01 Plastics 50 NA
## 5: M04 Wood 16 0.6
## 6: M03 Wood 15 NA
前面都是在构建子集之后,又创建了一个新的 data.table。data.table 包还提供
了一个对列进行原地赋值的符号:=。例如,product_stats 原始数据是这样的:
product_stats
## id material size weight
## 1: T01 Metal 120 10.0
## 2: T02 Metal 350 45.0
## 3: M01 Plastics 50 NA
## 4: M02 Plastics 85 3.0
## 5: M03 Wood 15 NA
## 6: M04 Wood 16 0.6
使用 :=,可以直接在 product_stats 中创建新列:
product_stats [, density := size / weight]
虽然并没有返回什么,但原始的 data.table 已经被修改了:
product_stats
## id material size weight density
## 1: T01 Metal 120 10.0 12.000000
## 2: T02 Metal 350 45.0 7.777778
## 3: M01 Plastics 50 NA NA
## 4: M02 Plastics 85 3.0 28.333333
## 5: M03 Wood 15 NA NA
## 6: M04 Wood 16 0.6 26.666667
使用 := 替换已有的列:
product_info[, released := released == "yes"]
product_info
## id name type class released
## 1: T01 SupCar toy vehicle TRUE
## 2: T02 SupPlane toy vehicle FALSE
## 3: M01 JeepX model vehicle TRUE
## 4: M02 AircraftX model vehicle TRUE
## 5: M03 Runner model people TRUE
## 6: M04 Dancer model people FALSE
data.table 包提供 := ,主要是因为原地修改的性能更高,避免了不必要的复制。

使用键获取行

对数据分组汇总

重塑 data.table

使用原地设置函数

data.table 中的动态作用域

使用 data.table 包操作数据的更多相关文章

  1. R语言数据分析利器data.table包 —— 数据框结构处理精讲

        R语言data.table包是自带包data.frame的升级版,用于数据框格式数据的处理,最大的特点快.包括两个方面,一方面是写的快,代码简洁,只要一行命令就可以完成诸多任务,另一方面是处理 ...

  2. data.table包简介

    data.table包主要特色是:设置keys.快速分组和滚得时序的快速合并.data.table主要通过二元检索法大大提高数据操作的效率,同时它也兼容适用于data.frame的向量检索法. req ...

  3. R︱高效数据操作——data.table包(实战心得、dplyr对比、key灵活用法、数据合并)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 由于业务中接触的数据量很大,于是不得不转战开始 ...

  4. R语言data.table包fread读取数据

    R语言处理大规模数据速度不算快,通过安装其他包比如data.table可以提升读取处理速度. 案例,分别用read.csv和data.table包的fread函数读取一个1.67万行.230列的表格数 ...

  5. R语言数据分析利器data.table包—数据框结构处理精讲

    R语言数据分析利器data.table包-数据框结构处理精讲 R语言data.table包是自带包data.frame的升级版,用于数据框格式数据的处理,最大的特点快.包括两个方面,一方面是写的快,代 ...

  6. data.table包

    data.table 1.生成一个data.table对象 生成一个data.table对象,记为DT. library(data.table) :],V3=round(rnorm(),),V4=:) ...

  7. data.table包使用应该注意的一些细节

    fread中nThread 参数的使用   注意默认nThread=getDTthreads(),即使用所有能用的核心,但并不是核心用的越多越好,本人亲自测试的情况下,其实单核具有较强的性能,只有在数 ...

  8. R读取大数据data.table包之fread

    >library(data.table)>data=fread("10000000.txt")>Read 9999999 rows and 71 (of 71) ...

  9. R语言学习笔记(十七):data.table包中melt与dcast函数的使用

    melt函数可以将宽数据转化为长数据 dcast函数可以将长数据转化为宽数据 > DT = fread("melt_default.csv") > DT family_ ...

随机推荐

  1. [LeetCode] 38. Count and Say_Easy

    The count-and-say sequence is the sequence of integers with the first five terms as following: 1. 1 ...

  2. [LeetCode] 458. Poor Pigs_Easy tag: Math

    There are 1000 buckets, one and only one of them contains poison, the rest are filled with water. Th ...

  3. redis的5种数据结构的使用场景介绍

    一.redis 数据结构使用场景 原来看过 redisbook 这本书,对 redis 的基本功能都已经熟悉了,从上周开始看 redis 的源码.目前目标是吃透 redis 的数据结构.我们都知道,在 ...

  4. js数组中indesOf方法的使用

    <html> <head> <title>数组的操作</title> <script type="text/javascript&quo ...

  5. 全文搜索引擎Xapian

    安装过程 安装xapian-core wget http://oligarchy.co.uk/xapian/1.0.13/xapian-core-1.0.13.tar.gztar zxvf xapia ...

  6. sql查询一列 重复的数据

    select * from 表 where num  in(select num  from 表 group by num having count(num)>1)

  7. mysql的Navicat查看数据库的ER图

    1.mysql数据库表间的关系图可以通过navicat查看.

  8. linux下如何进入单用户模式

    忘记密码时,我们可以通过进入单用户模式修改密码. 进入单用户模式的方式: 1. 启动服务器时,按 e 键进入引导选择界面.注意:可能需要多次按 e 键切换几个个界面后,才能进入选择界面. 2. 选择以 ...

  9. linux服务器文件索引inodes满了

    inode节点中,记录了文件的类型.大小.权限.所有者.文件连接的数目.创建时间与更新时间等重要的信息,还有一个比较重要的内容就是指向数据块的指针.一般情况不需要特殊配置,如果存放文件很多,需要配置. ...

  10. Kafka学习之(六)搭建kafka集群

    想要搭建kafka集群,必须具备zookeeper集群,关于zookeeper集群的搭建,在Kafka学习之(五)搭建kafka集群之Zookeeper集群搭建博客有说明.需要具备两台以上装有zook ...