R数据处理|data.table篇(一)
概述 data.table包是一个超高性能处理包,在数据处理上代码异常简洁,速度非常快。 由于data.table的语法主要基于[],有些用法和基础函数会不一致,所以没有放在前面两个专题中一起讲,而是单独拿出来讲。在这个系列里,我会详细说明data.table和基础函的差异,并系统地讲解data.table包的用法。 data.table的使用基本上是基于[]的,它不仅能覆盖基础函数[]的功能,还有许多强大的其他功能。比如它们都使用[]来提取,而data.table中分组、计算等全都是基于[]的。 下面列举一下这里的[]在与基础函数中的[]的重叠功能上,有什么区别,后面括号里会标注出他们在后文中的哪里出现。
本文包括如下内容
创建name1 <- c("Bob","Mary","Jane","Kim") name2 <- c("Bob","Kim","Jane") weight <- c(60,65,45,55) height <- c(170,165,140,135) birth <- c("1990-1","1980-2","1995-5","1996-4") accept <- c("no","ok","no") library(data.table) dft <- data.table(name1,weight,height,accept) 提取普通提取内容分为如下几种
根据坐标或列名的提取 # 提取点 dft[1,2] # 这里和data.frame是有区别的,这里返回的是一个data.table,而如果是data.frame则返回一个值 dft[[1,2]] # 返回一个值,data.table中drop不能用 dft[c(1,3),3] dft[c(1,weight] dft[c(1,"weight"] # 提取行 dft[1] # 注意这里和基础的不一样,只接一个数是提取行 dft[1:2,] # 也可以加一个逗号 # 提取列 dft[,2] # 这里返回的是一个DT,与基础函数中的向量不同 dft[[3]] # 这样只接一个数时提取列,返回一个向量 dft[["weight"]] dft$weight # 以上都是返回一个向量 dft[,"weight"] dft[,weight] # 注意区别,配合下面例子做出解释 dft[,c("weight","height")] dft[,weight:accept] # 返回一个数据框 dft[,c(weight,height)] # 如果使用字符串,则会输出数据框 # 如果直接使用列名表达式(没有括号的),则会输出向量; # 如果取多列,则会自动把多列拼接成一个向量输出。 # 使用表达式就和使用功能$是一样的,这是数据的降维 # 如果想使用expression,而数据不降维,用list(weight) dft[,list(weight)] dft[,.(weight)] # .是list的简写 dft[,.(weight,accept)] 当列名字符串放在一个变量中,想要使用这个变量进行提取时,因为data.table的[]提取时,可以接受一个不加引号的对象,所以会把这个表示列名的变量直接引用,这时需要使用with参数 dft <- data.table(name1,accept) name1 <- "weight" dft[,name1] # 提取出来的是name1列 dft[,(name1)] # 提取出来的是name1列 dft[,name1,with=F] # 提取出来的是weight列 k <- "weight" # 如果使用的变量名不是dft中的列名 # dft[,k] # 报错,因为此处默认寻找变量名空间为这个dft dft[,k,with=F] # 提取出来的是weight列 dft[[name1]] # 除了使用with参数,还可以这样 # dft[[weight]] # 报错,使用双括号时,是不允许直接使用变量名不加引号的 name1 <- c("Bob","Kim") # 不要干扰到后面的代码 这里with参数其实相当于基础的with函数,当with=T时,就相当于基础函数使用了with函数,在这里面使用列名不需要data$,直接当成变量名就可以了,也就不用加引号,如果不想这样,想让使用的变量代表一个外面定义的字符串向量,则让with=F,相当于不使用with函数。 提取习惯 上面我们知道,提取时可以根据坐标位置或者列名,推荐使用的是列名,坐标位置虽然方便一些,但是当你的代码要给别人来读,或者给未来的你自己来读时,每次提取都要去找第5列是哪一列。除此之外,一旦列的顺序改变,我们的代码将会是错误的。所以应该在平时就养成习惯,使用列名来提取。 根据逻辑值提取 # 根据逻辑值提取 dft[weight > 40] # 不需要dft$weight dft[weight>40&height<170] dft[dft$weight>40&dft$height<170] dft[c(T,F,T,T)] dft[,c(T,F)] # 列不可以根据逻辑值提取 # 使用on参数提取某一列是某一个值的行(相当于用逻辑值) dft["Bob",on="name1"] dft["Bob",on=.(name1)] dft[name1=="Bob"] # 等价于用逻辑值筛选 dft[c("Bob","Mary"),on="name1"] # 一列选择多种 dft[!"Bob",on="name1"] # 一列剔除某类 dft[.("Bob",60),on=.(name1,weight)] # 按照多列查找 dft[.("Bob",c(55,60)),weight)] # 找不到这样的行则创造一个满足这两列,其他列设为NA dft[.("Bob",weight),nomatch=0] # 找不到也不返回缺失值 dft[.("Mary",c(65,55)),roll=-Inf] # 填充 提取的衍生物
删除行列
普通计算
普通用法 dft[,weight%*%t(weight)] # 只返回一个时 dft[,.(weight%*%t(weight),height%*%t(height))] # 返回两个,使用list,但会每个自动转换成向量 dft[,c(weight%*%t(weight),height%*%t(height))] # 使用c,就会全部都转换成一个向量 使用{} # 使用大括号运行多条命令,不过只能返回最后一条结果,像函数的返回值一样 dft[,{weight%*%t(weight) ?height%*%t(height)}] # 但是中间可以用print打印出来,不过只能展示,无法调用 dft[,{print(weight%*%t(weight)) height%*%t(height)}] # 如果再里面用 <- 赋值,变量在外面的环境中找不到,要用 <<- 才可以 dft[,{u1 <- weight%*%t(weight) ?u2 <<- height%*%t(height)}] # u1;u2 # u2可以调用,u1不可以 使用多层list嵌套的方法 (l <- dft[,.(.(weight%*%t(weight)),.(height%*%t(height)))]) l[[1]] 我们可以发现矩阵被list折叠到一个元素之中,可以通过索引调用,这一点data.frame就无法做到,下面解释在这一点上DF和DT的区别 ma <- cbind(1:3,1) # 一个矩阵 ma data.frame(a=1,b=ma) data.table(a=1,b=ma) # 和data.frame相同 data.frame(a=1,b=list(ma)) # 上面三个都返回的是3列的数据框 (d <- data.table(a=1,b=list(ma))) # 返回两列的,即data.table形式的数据框中的元素可以是list d[[1,2]] # 虽然创建时将ma转化成了list,但是输出时仍是matrix # 数据框中的list #注意里面使用了I,使data.frame()把列表看作一个单元 df<-data.frame(x=1:3,y=I(list(1:2,1:3,1:4))) # 元素个数必须和行数相同 df df$m <- list(1:4,3:5,5:6) # 这样建立不需要I df$y # 这一整列是一个 list df$y[[1]][1] dft1 <- data.table(x=1:3,y=list(list(1:2),list(1:3),list(1:4))) # 三个元素分别放在三行上 dft1[[1,2]] dft2 <- data.table(x=1,y=list(list(list(1:2),list(1:4)))) # 变成一个元素,往外嵌套多少层都没问题 dft2[[1,2]] df<-data.table(x=1:3,1:4))) # data.table 也可以像df一样使用 df 分组计算 按照多列分组DT = data.table(x=rep(c("b","a","c"),each=6),y=c(1,3,6),v=1:18) DT[,sum(v),by=x] DT[,by=y] DT[,by=.(x,y)] DT[,by=c("x","y")] DT[,y)][,sum(V1),by=x]
这些内容涉及到data.table的一些特殊用法,之后我会按照特殊用法的顺序来实现这些功能 专栏信息专栏主页:Data Analysis(https://zhuanlan.zhihu.com/Data-AnalysisR) 文末彩蛋这里介绍一下fix和edit两个函数的作用和区别。 当我们使用这两个函数作用在数据框上时,会出现一个窗口,我们用鼠标点击就可以对数据框进行修改,初学者可能会很喜欢用这个方便的方法,下面就介绍一下使用方法和二者的区别。
df <- data.frame(a=1:5,b=letters[1:5]) df fix(df) # 点击直接修改,之后关闭窗口 df # 发现原数据框已经被改变 edit(df) # 点击直接修改,之后关闭窗口 df # 发现原数据框未被改变 df1 <- edit(df) df;df1 # 原数据框未被改变,新数据框是改变之后的结果 但是为了操作可复制性,建议不要使用这两个函数。因为这样你的代码中没有显示你所做的全部修改,别人无法复制你的结果;同时,当你自己某一步出错需要重来,这样的鼠标操作还需要重来一次,莫不如之前就使用代码,一劳永逸。 Dwzb?,?R语言中文社区专栏作者,厦门大学统计专业学生。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |