R语言具有较强的数据分析能力,但作为一种解释型语言在面对较大型数据集 时,使用基础软件包的处理效率会变得非常低下。为了解决处理较大数据集的问题,R语言社区涌现了一系列数据处理的包,如data.table、dplyr等。其中,data.table 包是一个非常实用的包,它提供了一组高效的数据处理函数,可以方便地处理大型数据集。
R语言data.table包是自带包data.frame的升级版,用于数据框格式数据的处理,最大的特点是 快。它内部处理的步骤进行了程序上的优化,使用多线程,还有很多C编写的函数,大大加快数据运行速度。尤其当对一两百万甚至更大数据集进行修改或运算时,由于data.table直接对数据本身做运算,不创建副本,因此相较于基本的data.frame格式,data.table在面对大型数据集时,进行聚合排序以及分组运算的性能非常高 !
$\color{red}{注意:}$data.table和data.frame的主要格式区别是data.table格式没有行名,但可以通过设置键来指定索引列,根据索引列的值进行数据索引。
本文主要整理了下data.table对象的一些常用操作方法
1、 data.table的一般语法格式
data.table数据框结构处理语法 DT[ i , j , by]
- i 决定显示的行,可以是整型,可以是字符,可以是表达式,
- j 是对数据框进行求值,决定显示的列,
- by 对数据进行指定分组,除了by ,也可以添加其它的一系列参数:keyby,with,nomatch,mult,rollollends,which,.SDcols,on等
2、读写文件
读取文件的4种便捷操作:
data.table提供了基于C语言编写 fread()方法,能够非常高效地读取大型数据集,以下是用法示例:
- ① - nrows 参数指定读取多少行
fread("fileName", sep="\t",nrows = 10)
- ② - select 参数选择要导入的列或drop参数进行反向选择
fread("fileName", sep="\t",select = c("column_1", "column_2", 6 ))
fread("fileName", sep="\t",drop = c("column_3", "column_4", 5 ))
- ③- *colClasses 参数在加载文件时完成列属性指定
fread("fileName", sep="\t", colClasses = c("column_1" = "numeric"))
- ④ - cmd 参数配合使用Linux命令读取zip文件
fread(cmd = 'unzip -cq fileName.zip' ,sep="\t").
写出文件:
fwrite(out,"fileName",col.names=T,row.names=F,sep="\t",quote=F)
如果是写出一个字符串或vector形式的内容的话,需要提前转为list
数据结构,不然会报异常:Error in fwrite(unique(unique(DT[, y])), file = paste0(sampletag, "_arealst.tsv")) : 不是所有的is.list(x)都是TRUE
$\rightarrow$ 正确处理方式fwrite(list("a long string"),file = "here.txt")
3、数据框对象转换
as.data.table和setDT也可用于转换list和data.frame为data.table对象,不同的是前者会完全复制原对象,然后进行转换,而setDT方法以传地址的方式直接修改原对象,不拷贝直接操作原数据集,因此前者更加的耗时和耗内存。dt <- setDT(df,keep.rownames = T, key = "rn")
- keep.rownames 参数保留原data.frame的行名,默认新建一列"rn"存放原data.frame的行名
- key 参数设置dt对象的索引列,列的值可以重复。键值设置还可以通过
setkey(df,"rn")
。
4、常用对象操作方法示例
(1) 数据集的行记录过滤
DT = data.table(x=rep(c( "b", "a", "c" ),each=3), y=c(1,3,6), v=1:9)
DT[2] #取第二行
DT[2:3] #取第二到第三行
DT[order(x)] #将DT按照X列排序,简化操作,另外排序也可以setkey(DT,x),出来的DT就已经是按照x列排序的了。用haskey(DT)判断DT是否已经设置了key,可以设置多个列作为key
DT[y 2] # DT$y 2的行
DT[!2:4] #除了2到4行剩余的行
DT[ "a" ,on= "x" ] #on 参数,在x列取出值为"a"的行
DT[.( "a" ), on= "x" ] #和上面一样.()有类似与c()的作用
DT[ "a" , on=.( x )] #和上面一样
DT[ x == "a" ] # 和上面一样,和使用on一样,都是使用二分查找法,所以它们速度比用data.frame的快。
DT[x! = "b" | y != 3 ] #x列不等于 b 或者y列不等于3的行
DT[.( "b" , 3), on=.(x, v)] #取DT的x,v列上x= b ,v=3的行
(2) 数据框的求值操作
数据运算包括输出sum,max,min,tail
等基本函数的计算结果,还可以用n输出第n列,.N
(总列数,直接在j输入.N取最后一列),:=
(直接在data.table上新建列),.SD
(SubDadaColums)输出子集,.SD[n]
输出子集的第n列。
DT = data.table(x=rep(c( "b", "a", "c" ),each=3), y=c(1,3,6), v=1:9)
DT[,y] #返回vector格式的y列的值
DT[,.(y)] #返回data.table格式的y列的值
DT[, sum(y)] #对y列求和
DT[, .(sv=sum(v))] #对y列求和,输出sv列,列中的内容就是sum(v)
DT[, .(sum(y)), by=x] # 对x列进行分组后对各分组y列求总和
DT[, sum(y), keyby=x] #对x列进行分组后对各分组y列求和,并且结果按照x排序
DT[, sum(y), by=x][order(x)] #和上面一样,采取data.table的链接符合表达式
DT[v==1, sum(y), by=x] #对v列进行分组后,取各组中v==1的行出来,各组分别对定义的行中的y求和
DT[, .N, by=x] #用by对DT 用x分组后,取每个分组的总行数
DT[, .SD, .SDcols=x:y] #用.SDcols 定义SubDadaColums(子列数据),这里取出x到y之间的列作为子集,然后.SD 输出所有子集
DT[, .SD[1], by = x] #抽提x列分组后每个子集的第一行
DT[, .SD[.N], by = x] #抽提x列分组后每个子集的最后一行
DT[2:5, cat(y,"\n" )] #直接在j 用cat函数,输出2到5列的y值
DT[, plot(a,b), by=x] #直接在j用plot函数画图,对于每个x的分组画一张图
DT[, m:=mean(v), by=x] #对DT按x列分组,直接在DT上再添加一列m,m的内容是mean(v),直接修改并且不输出到屏幕上
DT[, m:=mean(v), by=x] [] #加[]将结果输出到屏幕上
DT[,c( m , n ):=list(mean(v),min(v)), by=x][] # 按x分组后同时添加m,n 两列,内容是分别是mean(v)和min(v),并且输出到屏幕
DT[,.(seq = min(y):max(v)), by=x] #输出seq列,内容是min(a)到max(b)
DT[, c(.(y=max(y)), lapply(.SD, min)), by=x, .SDcols=y:v] #对DT取y:v之间的列,按x分组,输出max(y),对y到v之间的列
(3)删除一列
DT[,x := NULL]
(4)列属性转换
DT[,b := as.integer(y)]
其它有如as.integer(), as.numeric(),as.character(), as.Date()等函数
(5)根据多列的值进行去重
unique(DT, by = c("x","y"))
(6)根据列重排序
setorder(DT, x, -y)
#x列升序,y列降序(-)
(7)配合使用lapply
示例
对DT根据x列进行分组,子集保留"v", "y"两列,对每个自己的这两列求取均值:DT[, lapply(.SD, mean), .SDcols = c("v", "y"),by = x ]
(8)分组计数
DT[, c := .N, by = x]
(9) 为特定的单元格赋值
将DT第五行的"y", "v"两列的值替换第二行"y", "v"的值DT[2, c("y", "v") := as.list(DT[5, c(y, v)])]
直接修改第一行x列的单元格值为MMMDT[1,x := "MMM"]
(10) 数据框链接
内联接,nomatch=0表示不返回不匹配的行,nomatch=NA表示以NA返回不匹配的值DT[X, on= .("x","y") , nomatch=0]
只通过一列公共列进行链接的话可以写成:
DT[X, on= "x" , nomatch=0]
或DT[X, on= .(x), nomatch=0]
(11) 内容搜索返回行号
设置参数which =NADT["a",on = .(x), which = TRUE ]
#在x列匹配值为"a"的记录的行号
(12) 随机抽取n行
DT[sample(.N,n)]
DT[sample(.N,0.5.N)]
#随机抽取全数据集50%的行
(13) 通过A,B列分组,保留C列中出现频率最高的值完成去重过程
DT[, .SD[which.max(table(C))], by = list(A,B)]
Reference
Rdatatable/data.table: R's data.table package extends data.frame: (github.com)
R语言数据分析利器data.table包 —— 数据框结构处理精讲-汗血宝马 (caotama.com)