Best packages for data manipulation in R
dplyr and data.table are amazing packages that make data manipulation in R fun. Both packages have their strengths. While dplyr is more elegant and resembles natural language, data.table is succinct and we can do a lot withdata.table in just a single line. Further, data.table is, in some cases, faster (see benchmark here) and it may be a go-to package when performance and memory are constraints. You can read comparison of dplyr and data.tablefrom Stack Overflow and Quora.
You can get reference manual and vignettes for data.table here and for dplyrhere. You can read other tutorial about dplyr published at DataScience+
Background
I am a long time dplyr and data.table user for my data manipulation tasks. For someone who knows one of these packages, I thought it could help to show codes that perform the same tasks in both packages to help them quickly study the other. If you know either package and have interest to study the other, this post is for you.
dplyr
dplyr has 5 verbs which make up the majority of the data manipulation tasks we perform. Select: used to select one or more columns; Filter: used to select some rows based on specific criteria; Arrange: used to sort data based on one or more columns in ascending or descending order; Mutate: used to add new columns to our data; Summarise: used to create chunks from our data.
data.table
data.table has a very succinct general format: DT[i, j, by], which is interpreted as: Take DT, subset rows using i, then calculate j grouped by by.
Data manipulation
First we will install some packages for our project.
library(dplyr)
library(data.table)
library(lubridate)
library(jsonlite)
library(tidyr)
library(ggplot2)
library(compare)
The data we will use here is from DATA.GOV. It is Medicare Hospital Spending by Claim and it can be downloaded from here. Let’s download the data in JSONformat using the fromJSON function from the jsonlite package. Since JSON is a very common data format used for asynchronous browser/server communication, it is good if you understand the lines of code below used to get the data. You can get an introductory tutorial on how to use the jsonlite package to work with JSON data here and here. However, if you want to focus only on the data.table and dplyr commands, you can safely just run the codes in the two cells below and ignore the details.
spending=fromJSON("https://data.medicare.gov/api/views/nrth-mfg3/rows.json?accessType=DOWNLOAD")
names(spending)
"meta" "data"
meta=spending$meta
hospital_spending=data.frame(spending$data)
colnames(hospital_spending)=make.names(meta$view$columns$name)
hospital_spending=select(hospital_spending,-c(sid:meta))
glimpse(hospital_spending)
Observations: 70598
Variables:
$ Hospital.Name (fctr) SOUTHEAST ALABAMA MEDICAL CENT...
$ Provider.Number. (fctr) 010001, 010001, 010001, 010001...
$ State (fctr) AL, AL, AL, AL, AL, AL, AL, AL...
$ Period (fctr) 1 to 3 days Prior to Index Hos...
$ Claim.Type (fctr) Home Health Agency, Hospice, I...
$ Avg.Spending.Per.Episode..Hospital. (fctr) 12, 1, 6, 160, 1, 6, 462, 0, 0...
$ Avg.Spending.Per.Episode..State. (fctr) 14, 1, 6, 85, 2, 9, 492, 0, 0,...
$ Avg.Spending.Per.Episode..Nation. (fctr) 13, 1, 5, 117, 2, 9, 532, 0, 0...
$ Percent.of.Spending..Hospital. (fctr) 0.06, 0.01, 0.03, 0.84, 0.01, ...
$ Percent.of.Spending..State. (fctr) 0.07, 0.01, 0.03, 0.46, 0.01, ...
$ Percent.of.Spending..Nation. (fctr) 0.07, 0.00, 0.03, 0.58, 0.01, ...
$ Measure.Start.Date (fctr) 2014-01-01T00:00:00, 2014-01-0...
$ Measure.End.Date (fctr) 2014-12-31T00:00:00, 2014-12-3...
As shown above, all columns are imported as factors and let’s change the columns that contain numeric values to numeric.
cols = 6:11; # These are the columns to be changed to numeric.
hospital_spending[,cols] <- lapply(hospital_spending[,cols], as.numeric)
The last two columns are measure start date and measure end date. So, let’s use the lubridate package to correct the classes of these columns.
cols = 12:13; # These are the columns to be changed to dates.
hospital_spending[,cols] <- lapply(hospital_spending[,cols], ymd_hms)
Now, let’s check if the columns have the classes we want.
sapply(hospital_spending, class)
$Hospital.Name
"factor"
$Provider.Number.
"factor"
$State
"factor"
$Period
"factor"
$Claim.Type
"factor"
$Avg.Spending.Per.Episode..Hospital.
"numeric"
$Avg.Spending.Per.Episode..State.
"numeric"
$Avg.Spending.Per.Episode..Nation.
"numeric"
$Percent.of.Spending..Hospital.
"numeric"
$Percent.of.Spending..State.
"numeric"
$Percent.of.Spending..Nation.
"numeric"
$Measure.Start.Date
"POSIXct" "POSIXt"
$Measure.End.Date
"POSIXct" "POSIXt"
Create data table
We can create a data.table using the data.table() function.
hospital_spending_DT = data.table(hospital_spending)
class(hospital_spending_DT)
"data.table" "data.frame"
Select certain columns of data
To select columns, we use the verb select in dplyr. In data.table, on the other hand, we can specify the column names.
Selecting one variable
Let’s selet the “Hospital Name” variable
from_dplyr = select(hospital_spending, Hospital.Name)
from_data_table = hospital_spending_DT[,.(Hospital.Name)]
Now, let’s compare if the results from dplyr and data.table are the same.
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
Removing one variable
from_dplyr = select(hospital_spending, -Hospital.Name)
from_data_table = hospital_spending_DT[,!c("Hospital.Name"),with=FALSE]
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
we can also use := function which modifies the input data.table by reference.
We will use the copy() function, which deep copies the input object and therefore any subsequent update by reference operations performed on the copied object will not affect the original object.
DT=copy(hospital_spending_DT)
DT=DT[,Hospital.Name:=NULL]
"Hospital.Name"%in%names(DT)FALSE
We can also remove many variables at once similarly:
DT=copy(hospital_spending_DT)
DT=DT[,c("Hospital.Name","State","Measure.Start.Date","Measure.End.Date"):=NULL]
c("Hospital.Name","State","Measure.Start.Date","Measure.End.Date")%in%names(DT)
FALSE FALSE FALSE FALSE
Selecting multiple variables
Let’s select the variables:
Hospital.Name,State,Measure.Start.Date,and Measure.End.Date.
from_dplyr = select(hospital_spending, Hospital.Name,State,Measure.Start.Date,Measure.End.Date)
from_data_table = hospital_spending_DT[,.(Hospital.Name,State,Measure.Start.Date,Measure.End.Date)]
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
Dropping multiple variables
Now, let’s remove the variables Hospital.Name,State,Measure.Start.Date,and Measure.End.Date from the original data frame hospital_spending and the data.table hospital_spending_DT.
from_dplyr = select(hospital_spending, -c(Hospital.Name,State,Measure.Start.Date,Measure.End.Date))
from_data_table = hospital_spending_DT[,!c("Hospital.Name","State","Measure.Start.Date","Measure.End.Date"),with=FALSE]
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
dplyr has functions contains(), starts_with() and, ends_with() which we can use with the verb select. In data.table, we can use regular expressions. Let’s select columns that contain the word Date to demonstrate by example.
from_dplyr = select(hospital_spending,contains("Date"))
from_data_table = subset(hospital_spending_DT,select=grep("Date",names(hospital_spending_DT)))
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
names(from_dplyr)
"Measure.Start.Date" "Measure.End.Date"
Rename columns
setnames(hospital_spending_DT,c("Hospital.Name", "Measure.Start.Date","Measure.End.Date"), c("Hospital","Start_Date","End_Date"))
names(hospital_spending_DT)
"Hospital" "Provider.Number." "State" "Period" "Claim.Type" "Avg.Spending.Per.Episode..Hospital." "Avg.Spending.Per.Episode..State." "Avg.Spending.Per.Episode..Nation." "Percent.of.Spending..Hospital." "Percent.of.Spending..State." "Percent.of.Spending..Nation." "Start_Date" "End_Date"
hospital_spending = rename(hospital_spending,Hospital= Hospital.Name, Start_Date=Measure.Start.Date,End_Date=Measure.End.Date)
compare(hospital_spending,hospital_spending_DT, allowAll=TRUE)
TRUE
dropped attributes
Filtering data to select certain rows
To filter data to select specific rows, we use the verb filter from dplyr with logical statements that could include regular expressions. In data.table, we need the logical statements only.
Filter based on one variable
from_dplyr = filter(hospital_spending,State=='CA') # selecting rows for California
from_data_table = hospital_spending_DT[State=='CA']
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
Filter based on multiple variables
from_dplyr = filter(hospital_spending,State=='CA' & Claim.Type!="Hospice")
from_data_table = hospital_spending_DT[State=='CA' & Claim.Type!="Hospice"]
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
from_dplyr = filter(hospital_spending,State %in% c('CA','MA',"TX"))
from_data_table = hospital_spending_DT[State %in% c('CA','MA',"TX")]
unique(from_dplyr$State)
CA MA TX
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
Order data
We use the verb arrange in dplyr to order the rows of data. We can order the rows by one or more variables. If we want descending, we have to use desc()as shown in the examples.The examples are self-explanatory on how to sort in ascending and descending order. Let’s sort using one variable.
Ascending
from_dplyr = arrange(hospital_spending, State)
from_data_table = setorder(hospital_spending_DT, State)
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
Descending
from_dplyr = arrange(hospital_spending, desc(State))
from_data_table = setorder(hospital_spending_DT, -State)
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
Sorting with multiple variables
Let’s sort with State in ascending order and End_Date in descending order.
from_dplyr = arrange(hospital_spending, State,desc(End_Date))
from_data_table = setorder(hospital_spending_DT, State,-End_Date)
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
Adding/updating column(s)
In dplyr we use the function mutate() to add columns. In data.table, we can Add/update a column by reference using := in one line.
from_dplyr = mutate(hospital_spending, diff=Avg.Spending.Per.Episode..State. - Avg.Spending.Per.Episode..Nation.)
from_data_table = copy(hospital_spending_DT)
from_data_table = from_data_table[,diff := Avg.Spending.Per.Episode..State. - Avg.Spending.Per.Episode..Nation.]
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
sorted
renamed rows
dropped row names
dropped attributes
from_dplyr = mutate(hospital_spending, diff1=Avg.Spending.Per.Episode..State. - Avg.Spending.Per.Episode..Nation.,diff2=End_Date-Start_Date)
from_data_table = copy(hospital_spending_DT)
from_data_table = from_data_table[,c("diff1","diff2") := list(Avg.Spending.Per.Episode..State. - Avg.Spending.Per.Episode..Nation.,diff2=End_Date-Start_Date)]
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
dropped attributes
Summarizing columns
We can use the summarize() function from dplyr to create summary statistics.
summarize(hospital_spending,mean=mean(Avg.Spending.Per.Episode..Nation.))
mean 8.772727 hospital_spending_DT[,.(mean=mean(Avg.Spending.Per.Episode..Nation.))]
mean 8.772727 summarize(hospital_spending,mean=mean(Avg.Spending.Per.Episode..Nation.),
maximum=max(Avg.Spending.Per.Episode..Nation.),
minimum=min(Avg.Spending.Per.Episode..Nation.),
median=median(Avg.Spending.Per.Episode..Nation.))
mean maximum minimum median
8.77 19 1 8.5 hospital_spending_DT[,.(mean=mean(Avg.Spending.Per.Episode..Nation.),
maximum=max(Avg.Spending.Per.Episode..Nation.),
minimum=min(Avg.Spending.Per.Episode..Nation.),
median=median(Avg.Spending.Per.Episode..Nation.))]
mean maximum minimum median
8.77 19 1 8.5
We can calculate our summary statistics for some chunks separately. We use the function group_by() in dplyr and in data.table, we simply provide by.
head(hospital_spending_DT[,.(mean=mean(Avg.Spending.Per.Episode..Hospital.)),by=.(Hospital)])

mygroup= group_by(hospital_spending,Hospital)
from_dplyr = summarize(mygroup,mean=mean(Avg.Spending.Per.Episode..Hospital.))
from_data_table=hospital_spending_DT[,.(mean=mean(Avg.Spending.Per.Episode..Hospital.)), by=.(Hospital)]
compare(from_dplyr,from_data_table, allowAll=TRUE) TRUE
sorted
renamed rows
dropped row names
dropped attributes
We can also provide more than one grouping condition.
head(hospital_spending_DT[,.(mean=mean(Avg.Spending.Per.Episode..Hospital.)),
by=.(Hospital,State)])

mygroup= group_by(hospital_spending,Hospital,State)
from_dplyr = summarize(mygroup,mean=mean(Avg.Spending.Per.Episode..Hospital.))
from_data_table=hospital_spending_DT[,.(mean=mean(Avg.Spending.Per.Episode..Hospital.)), by=.(Hospital,State)]
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
sorted
renamed rows
dropped row names
dropped attributes
Chaining
With both dplyr and data.table, we can chain functions in succession. In dplyr, we use pipes from the magrittr package with %>% which is really cool. %>% takes the output from one function and feeds it to the first argument of the next function. In data.table, we can use %>% or [ for chaining.
from_dplyr=hospital_spending%>%group_by(Hospital,State)%>%summarize(mean=mean(Avg.Spending.Per.Episode..Hospital.))
from_data_table=hospital_spending_DT[,.(mean=mean(Avg.Spending.Per.Episode..Hospital.)), by=.(Hospital,State)]
compare(from_dplyr,from_data_table, allowAll=TRUE)
TRUE
sorted
renamed rows
dropped row names
dropped attributes
hospital_spending%>%group_by(State)%>%summarize(mean=mean(Avg.Spending.Per.Episode..Hospital.))%>%
arrange(desc(mean))%>%head(10)%>%
mutate(State = factor(State,levels = State[order(mean,decreasing =TRUE)]))%>%
ggplot(aes(x=State,y=mean))+geom_bar(stat='identity',color='darkred',fill='skyblue')+
xlab("")+ggtitle('Average Spending Per Episode by State')+
ylab('Average')+ coord_cartesian(ylim = c(3800, 4000))

hospital_spending_DT[,.(mean=mean(Avg.Spending.Per.Episode..Hospital.)),
by=.(State)][order(-mean)][1:10]%>%
mutate(State = factor(State,levels = State[order(mean,decreasing =TRUE)]))%>%
ggplot(aes(x=State,y=mean))+geom_bar(stat='identity',color='darkred',fill='skyblue')+
xlab("")+ggtitle('Average Spending Per Episode by State')+
ylab('Average')+ coord_cartesian(ylim = c(3800, 4000))

Summary
In this blog post, we saw how we can perform the same tasks using data.tableand dplyr packages. Both packages have their strengths. While dplyr is more elegant and resembles natural language, data.table is succinct and we can do a lot with data.table in just a single line. Further, data.table is, in some cases, faster and it may be a go-to package when performance and memory are the constraints.
You can get the code for this blog post at my GitHub account.
This is enough for this post. If you have any questions or feedback, feel free to leave a comment.
转自:http://datascienceplus.com/best-packages-for-data-manipulation-in-r/
Best packages for data manipulation in R的更多相关文章
- Data manipulation primitives in R and Python
Data manipulation primitives in R and Python Both R and Python are incredibly good tools to manipula ...
- Data Manipulation with dplyr in R
目录 select The filter and arrange verbs arrange filter Filtering and arranging Mutate The count verb ...
- The dplyr package has been updated with new data manipulation commands for filters, joins and set operations.(转)
dplyr 0.4.0 January 9, 2015 in Uncategorized I’m very pleased to announce that dplyr 0.4.0 is now av ...
- An Introduction to Stock Market Data Analysis with R (Part 1)
Around September of 2016 I wrote two articles on using Python for accessing, visualizing, and evalua ...
- 7 Tools for Data Visualization in R, Python, and Julia
7 Tools for Data Visualization in R, Python, and Julia Last week, some examples of creating visualiz ...
- java.sql.SQLException: Can not issue data manipulation statements with executeQuery().
1.错误描写叙述 java.sql.SQLException: Can not issue data manipulation statements with executeQuery(). at c ...
- Can not issue data manipulation statements with executeQuery()错误解决
转: Can not issue data manipulation statements with executeQuery()错误解决 2012年03月27日 15:47:52 katalya 阅 ...
- 数据库原理及应用-SQL数据操纵语言(Data Manipulation Language)和嵌入式SQL&存储过程
2018-02-19 18:03:54 一.数据操纵语言(Data Manipulation Language) 数据操纵语言是指插入,删除和更新语言. 二.视图(View) 数据库三级模式,两级映射 ...
- Can not issue data manipulation statements with executeQuery().解决方案
这个错误提示是说无法发行sql语句到指定的位置 错误写法: 正确写法: excuteQuery是查询语句,而我要调用的是更新的语句,所以这样数据库很为难到底要干嘛,实际我想用的是更新,但是我写成了查询 ...
随机推荐
- C/C++中数组与指针的关系探究
数组与指针 长期以来,在C/C++中,数组名和指向数组首元素的指针常量到底是以一种什么关系,一直困扰着很多人.很多地方,甚至是一些教科书中都在说,"数组名就是一个指向数组首元素的指针常量&q ...
- How To Use ggplot in ggplot2?
1.What is ggplot2 ggplot2基本要素 数据(Data)和映射(Mapping) 几何对象(Geometric) 标尺(Scale) 统计变换(Statistics) 坐标系统(C ...
- less补充函数
1.ceil():向上取整2.floor():向下取整3.percentage():将浮点数转换成百分比3.round():四舍五入4.sqrt():平方根5.abs():绝对值6.pow():乘方运 ...
- Spring BeanFactoryPostProcessor
使用场景:当在配置文件中需要配置Bean(参数不同,class相同,id不同时)冗余的情况 继承 BeanFactoryPostProcessor 覆盖 postProcessBeanFactory( ...
- JS获取URL中参数值(QueryString)的4种方法
方法一:正则法 function getQueryString(name) { var reg = new RegExp('(^|&)' + name + '=([^&]*)(& ...
- 想询问一个职业规划的问题,前端开发 or nodejs?
先说说个人情况,目前个人定位于初中级前端吧,工作近两年,目前前端开发和nodejs都有一定的了解,水平感觉可以搭一些小型的网站.作为前端开发,目前掌握的技术是javascript,平时更多的是用jqu ...
- java构造代码块,构造函数和普通函数的区别和调用时间
在这里我们谈论一下构造代码块,构造函数和普通函数的区别和调用时间.构造代码块:最早运行,比构造函数运行的时间好要提前,和构造函数一样,只在对象初始化的时候运行.构造函数:运行时间比构造代码块时间晚,也 ...
- 推送一个已有的代码到新的 gerrit 服务器
1.指定项目代码库中迭代列出全部ProductList(.git)到pro.log文件中 repo forall -c 'echo $REPO_PROJECT' | tee pro.log pro.l ...
- [CTSC1999]【网络流24题】星际转移
Description 由于人类对自然资源的消耗,人们意识到大约在2300 年之后,地球就不能再居住了.于是在月球上建立了新的绿地,以便在需要时移民.令人意想不到的是,2177 年冬由于未知的原因,地 ...
- Linux Shell——函数的使用
文/一介书生,一枚码农. scripts are for lazy people. 函数是存在内存里的一组代码的命名的元素.函数创建于脚本运行环境之中,并且可以执行. 函数的语法结构为: functi ...