使用 data.table 包操作数据
在第一节中,我们回顾了许多用于操作数据框的内置函数。然后,了解了 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 包操作数据的更多相关文章
- R语言数据分析利器data.table包 —— 数据框结构处理精讲
R语言data.table包是自带包data.frame的升级版,用于数据框格式数据的处理,最大的特点快.包括两个方面,一方面是写的快,代码简洁,只要一行命令就可以完成诸多任务,另一方面是处理 ...
- data.table包简介
data.table包主要特色是:设置keys.快速分组和滚得时序的快速合并.data.table主要通过二元检索法大大提高数据操作的效率,同时它也兼容适用于data.frame的向量检索法. req ...
- R︱高效数据操作——data.table包(实战心得、dplyr对比、key灵活用法、数据合并)
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 由于业务中接触的数据量很大,于是不得不转战开始 ...
- R语言data.table包fread读取数据
R语言处理大规模数据速度不算快,通过安装其他包比如data.table可以提升读取处理速度. 案例,分别用read.csv和data.table包的fread函数读取一个1.67万行.230列的表格数 ...
- R语言数据分析利器data.table包—数据框结构处理精讲
R语言数据分析利器data.table包-数据框结构处理精讲 R语言data.table包是自带包data.frame的升级版,用于数据框格式数据的处理,最大的特点快.包括两个方面,一方面是写的快,代 ...
- data.table包
data.table 1.生成一个data.table对象 生成一个data.table对象,记为DT. library(data.table) :],V3=round(rnorm(),),V4=:) ...
- data.table包使用应该注意的一些细节
fread中nThread 参数的使用 注意默认nThread=getDTthreads(),即使用所有能用的核心,但并不是核心用的越多越好,本人亲自测试的情况下,其实单核具有较强的性能,只有在数 ...
- R读取大数据data.table包之fread
>library(data.table)>data=fread("10000000.txt")>Read 9999999 rows and 71 (of 71) ...
- R语言学习笔记(十七):data.table包中melt与dcast函数的使用
melt函数可以将宽数据转化为长数据 dcast函数可以将长数据转化为宽数据 > DT = fread("melt_default.csv") > DT family_ ...
随机推荐
- matplotlib —— 调整坐标轴
import matplotlib.pyplot as plt import numpy as np # 绘制普通图像 x = np.linspace(-1, 1, 50) y1 = 2 * x + ...
- gerrit 使用教程(一)
原文地址:https://www.jianshu.com/p/b77fd16894b6 1, Gerrit是什么? Gerrit实际上一个Git服务器,它为在其服务器上托管的Git仓库提供一系列权限控 ...
- iOS 第三方框架-MJRefresh
MJRefresh是一款非常好用的上拉下拉第三方库,使用也很简单.github地址: https://github.com/CoderMJLee/MJRefresh . 下拉刷新 官方给过来的例子很简 ...
- Promise学习探究
学习熟知吧,原理还是继续吧 例子1: var isGeted; function getRet(){ return new Promise(function(resolve, reject) { // ...
- libsvm java版本使用心得(转)
http://blog.csdn.net/u010340854/article/details/19159883 https://github.com/cjlin1/libsvm 项目中要用到svm分 ...
- android实操--练习2
练习2是实现一个计算器的功能:可以加减乘除:可以倒退,可以清空文本. 下面是效果展示: -----------------------布局------------------------------- ...
- ROS知识(2)----理解ROS系统结构
学习新事物,方法高于技术本身,如果没有把握"BIG PICTURE"的话很难理解进去.通过以下几点进行理解ROS: ROS实际上不是操作系统,他只是一个通信的框架,一个代码管理的架 ...
- Python: TypeError: 'dict' object is not callable
问题: TypeError: 'dict' object is not callable 原因: dict()是python的一个内建函数,如果将dict自定义为一个python字典,在之后想调用 ...
- linux基础命令---umask
umask 指定创建文件时所需要的权限掩码,掩码的执行权限对于文件没有效果.如果模式以数字开头,则解释为八进制数字:否则解释为符号模式掩码,类似于chmod(1)所接受的模式掩码.如果省略模式,则打印 ...
- php json_decode() 如果想要强制生成PHP关联数组,json_decode()需要加一个参数true
php json_decode()该函数用于将json文本转换为相应的PHP数据结构.下面是一个例子:$json = '{"foo": 12345}';$obj = json_de ...