028-R数据格式转换

刘小泽写于2018.8.27

我们日常使用R一般不会使用它的编程工作(即写R包的任务),许许多多的的生信函数、统计软件也都是现成的,我们要做的最繁琐、最耗时的工作就是对数据进行整理。我们要做的就是将数据转换成函数能够识别处理的格式。一般从.txt、.csv中读入的数据都需要对结构进行转换,例如:添加、删除、修改、排序、筛选

1 数据读入

  • 一般使用read.table读取.txt格式,用read.csv读取excel格式文件【前提将excel保存成csv】

    cars = read.csv(mtcars.csv) #这里就是做个演示,其实mtcars数据集是内置的,直接cars = mtcars就可以
    
  • 读入后用class判断类型,另外还可以用

    is.data.frame(cars)
    is.vector()
    is.array()
    is.na()
    is.null()#查看为空的内容
    methods(is)#查看全部关于is的内容
    
  • 转换数据格式

    #同样内置的数据集state.x77,先看一下他的类型
    class(state.x77) #是matrix
    #matrix转换成data.frame
    as.data.frame(state.x77)
    #注意:矩阵matrix转换成数据框没什么问题,但是反过来数据框要转位矩阵可能就有问题,因为矩阵必须要求数据同为字符串型或者同为数值型
    as.matrix(data.frame(state.region,state.x77))
    #结果就是这样:全变成了字符型              
    #state.region    Population Income Illiteracy Life.Exp Murder HS.Grad Frost
    #Alabama        "South"         " 3615"    "3624" "2.1"      "69.05"  "15.1" "41.3"  " 20"
    as.list() #转换成列表
    as.vector() #转换成因子
    

2 最基础的数据类型——向量

向量只需要添加一个维度就能转换成矩阵或者数组

class(state.name) # [1] "character"字符型向量
a=state.name #现在a就是一个向量
dim(a) #返回NULL空值,现在a还没有维度
length(a) #a这个向量有多少数据呢?结果有50
#为a添加一个维度
dim(a)=c(5,10) #结果a就是一个5行10列的矩阵
b=data.frame(a,state.abb) #矩阵a再加一列,组成一个数据框

#数据框取列可以直接b$列名,取行需要b[行号,]
#数据框去掉列名用unname()

3 取子集

有时数据框中信息量太大,我们需要取其中的一部分

  • 使用索引

    #假设c是一个数据框
    #连续提取
    c1=c[c(1:10),c(1:30)] # 取10行,30列
    #不连续提取
    c2=c[c(1,3,5),c(2,4,6)]
    
  • 使用逻辑判断

    #利用which函数
    c3=c[which(c$某一列==某个值),] #返回的就是这一列是这个值的全部行
    #注意:这里的判断是用两个=,如果是一个=意思是赋值
      
    #如果是搜索特定范围的行
    c4=c[which(c$1>value1 & c$1<=value1)]
    
  • 使用subset函数【比较简便】

    subset(x, subset, select ...)

    首先输入一个对象x,可以是向量、矩阵、数据框;

    然后subset设置逻辑判断,select设置范围

    c5=subset(c,c$1>value1 & c$1<=value1)
    
  • 随机抽样:sample函数

    可以设置有/无返回的随机抽样,可以设置样本大小,例如彩票36选7就是无返回抽样

    sample(x, size, replace = FALSE, prob = NULL)

    x是样本:一堆元素组成的向量;

    size:抽取元素个数;

    replace:有无放回的抽样

    #1. 利用sample抽取向量
    set.seed(123) #保证重复结果一致性
    d=1:200
    sort(sample(d,50,replace=T)) #设置放回抽样,排序后就会发现有数据重复
      
    #2.利用sample抽取数据框
    c[sample(c$1, size,replace=T/F),]
    
  • 数据框取子集

    c[1:5,] #取前5行
    c[,-1:-5] #取后5列
    
  • 变体应用:清空行/列

    c$1 = NULL #清空c的第一列子集 
    

4 合并

  • 按行/列进行合并(前提是相同的列/行数)

    cbind()、rbind()

  • 合并完之后去重复

    c[!duplicated(c)] duplicated函数是取出重复部分,加感叹号就是取相反

    或者使用uniq(c)

5 翻转

  • 针对数据框:将所有的行和列调换t()`

  • 针对向量/数据框的某一行/列:rev() 就是reverse的意思

    #例如将某个数据框按行名进行翻转,比如women数据框【两列:height、weight】
    women[rev(rownames(women)),]
    #先用rownames()获得行名
    #再用rev()将行名翻转,作为下一步提取的索引
    #从women中提取出来翻转后的数据
    

6 修改数据框中的值

transform函数可以方便修改数据框中任何列的值

#例如想修改women数据框中,weight的值,(假设)原来是斤,现在要改成公斤
#一种该法:【比较麻烦,并且大数据量不适用】
data.frame(height=women$height,weight=women$weight/2)
#使用transform【如果不写weight,而是用别的比如wei,那么就会在数据框最后新加一列】
transform(women,weight=women$weigh/2)

7 排序

  • sort排序后返回的是值,默认数字从小到大,字符串按ASCII码【若取相反,只需要加rev() 函数】–只能用于向量排序,不能直接用于数据框

但是,可以先对数据框中某一行/列进行排序,然后根据这个索引,调整数据框

mtcars[sort(rownames(mtcars))]
#上面只是按照行名(列名也可以)进行排序,如果想对其中某一列的数据进行排序后,再整理数据框,用下面的order比较方便
  • order 排序后返回的是索引

    #按照mtcars的mpg这一列的数据进行排序后,对数据框进行整理
    mtcars[order(mtcars$mpg),]
    #还支持多个条件进行排序
    mtcars[order(mtcars$mpg,mtcars$disp),] #意思就是:先对mpg进行排序,在同一个mpg的情况下,disp小的排在前面
    #要翻转也很简单
    mtcars[rev(order(mtcars$mpg)),]
    #或者更简单翻转
    mtcars[order(-mtcars$mpg),]
    

8 apply系列

#例如,对worldPhones这个数据集进行统计,求每一行的和、每一列的平均数
f=as.data.frame(WorldPhones)
rS=rowSums(f) #计算行的加和
cM=colMeans(f) #计算列的平均数
Sum=cbind(f,Sum=rS)
Mean=rbind(Sum,Mean=cM)

如果利用apply,就可以这样

apply(WorldPhones,MARGIN = 1, FUN=sum) #计算行的加和
apply(WorldPhones,MARGIN = 2, FUN=mean)  #计算列的平均数
#还可以新添加函数,比上面的方法拓展性更强【即便没有现有的函数,也可以自己创造】
apply(WorldPhones,MARGIN = 2, FUN=var) ##计算列的方差
apply(WorldPhones,MARGIN = 2, FUN=log) ##计算列的log

这个大家族,是R中解决循环遍历的核心,包括了tapply、apply、mapply、lapply、sapply、rapply、vapply、eapply这8大成员。利用它们几个可以方便实现数据循环、分组、过滤等操作。相比于自己写for循环,这种既便捷又高效1

  • **apply:**最常使用,作为for的替代工具。对矩阵、数据框、数组这样二维以上的数据,抽取其中的一个维度(行或列)进行遍历,并且加上函数计算得到结果

    apply(X, MARGIN, FUN, ...)
    #MARGIN:1为行,2为列
    #例如,一个矩阵
    >A=matrix(1:20,ncol=4)
         [,1] [,2] [,3] [,4]
    [1,]    1    6   11   16
    [2,]    2    7   12   17
    [3,]    3    8   13   18
    [4,]    4    9   14   19
    [5,]    5   10   15   20
    >apply(A,1,mean) #按行遍历求平均值
    [1]  8.5  9.5 10.5 11.5 12.5
    
  • lapply:(list) 对列表、数据框进行循环操作,即对X的每一个元素运用函数,结果生成一个与元素个数相同的列表。

    lapply(X,FUN, ...)
      
    > B=list(a=rnorm(5,2,3), b=1:5, c=c(F,T,F,T))
    $a
    [1] -3.060080  4.513361  2.460119 -1.414411  5.761445
    $b
    [1] 1 2 3 4 5
    $c
    [1] FALSE  TRUE FALSE  TRUE
    > lapply(B,length) #分别获得每个元素的长度
    $a
    [1] 5
    $b
    [1] 5
    $c
    [1] 4
    

    可以对数据框按列循环操作;但是对于矩阵,它会循环计算统计矩阵的每个值,而不是放在一起进行计算

    C=rbind(x=6,y=c(2:4))
    > C
      [,1] [,2] [,3]
    x    6    6    6
    y    2    3    4
    > class(C) #matrix
    > lapply(C,mean) #想求平均值
    [[1]]
    [1] 6
      
    [[2]]
    [1] 2
      
    [[3]]
    [1] 6
      
    [[4]]
    [1] 3
      
    [[5]]
    [1] 6
      
    [[6]]
    [1] 4
    #但是如果转换成数据框,就可以,并且还能看出是按列循环
    #因为lapply可以将数据框自动按列进行分组,然后进行统计
    > lapply(data.frame(C),mean)
    $V1
    [1] 4
      
    $V2
    [1] 4.5
      
    $V3
    [1] 5
    
  • sapply: (simple)可以理解为精简版的lapply,因为它的返回值是向量/矩阵,而不是列表,因此结果看起来更舒服

    sapply(X, FUN, ..., simplify = TRUE, USE.NAMES =TRUE)
    #默认simplify、USE.NAMES都是TRUE
    # simplify为array时,会按数组进行分组;
    # USE.NAMES为FALSE时,不设置数据名
    #因此,当这两者都是FALSE时,结果就是lapply
    
    > sapply(C,quantile)
         V1   V2  V3
    0%    2 3.00 4.0
    25%   3 3.75 4.5
    50%   4 4.50 5.0
    75%   5 5.25 5.5
    100%  6 6.00 6.0
    #对比下lapply与sapply
    > sapply(C,sum)
    V1 V2 V3 
     8  9 10 
    > lapply(C,sum)
    $V1
    [1] 8
      
    $V2
    [1] 9
      
    $V3
    [1] 10
    #使用apply检查数据集中每列的属性
    > sapply(mtcars,class)
          mpg       cyl      disp        hp      drat        wt      qsec        vs        am 
    "numeric" "numeric" "numeric" "numeric" "numeric" "numeric" "numeric" "numeric" "numeric" 
         gear      carb 
    "numeric" "numeric" 
    

    看一下USE.NAMES设置的问题

    > words=letters[1:4]
    > sapply(words,paste,USE.NAMES = F, 1:3)
         [,1]  [,2]  [,3]  [,4] 
    [1,] "a 1" "b 1" "c 1" "d 1"
    [2,] "a 2" "b 2" "c 2" "d 2"
    [3,] "a 3" "b 3" "c 3" "d 3"
    > sapply(words,paste,USE.NAMES = T, 1:3)
         a     b     c     d    
    [1,] "a 1" "b 1" "c 1" "d 1"
    [2,] "a 2" "b 2" "c 2" "d 2"
    [3,] "a 3" "b 3" "c 3" "d 3"
    
  • vapply: sapply基础上可以设定返回值

    vapply(X, FUN, FUN.VALUE, ..., USE.NAMES = TRUE)
    # X为列表或数据框
    # FUN.VALUE是新增内容,设定了返回值的行名row.names;不设置时,为默认的索引值
    
  • tapply: 分组统计使用

    tapply(X, INDEX, FUN, ..., simplify = TRUE)
    #通过index将数据集X分组,index可以是多个的集合
    #例如,通过mtcars数据集中的cyl气缸数对mpg耗油量进行分组,并且计算平均值
    > tapply(mtcars$mpg,mtcars$cyl,mean)
           4        6        8 
    26.66364 19.74286 15.10000 
    #又如:统计不同年龄的吸烟人数
    > age=c(24,26,57,13,56)
    > smoke=c("F","F","T","F","T")
    > tapply(age,smoke, sum)
      F   T 
     63 113 
    
  • mapply: 将函数 FUN 依次应用在第一个元素、第二个元素…上

    mapply(FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE,USE.NAMES = TRUE)
    #例如,循环比对每一列的数值大小,取最小值
    > x=1:6
    > y=8:-3
    > z=c(1,4,8,-4,1,6)
    > mapply(min,x,y,z)
    [1]  1  2  1 -4 -1 -2
    

9 数据优化

目的为了向数据中心靠拢,减小数据之间的差别。一般数据集都会有n列,并且各列之间有的单位都不同,显示的数字有的大有的小,如果直接拿来用,基本看不差什么差别。因此需要中心化和标准化,也就是对每一列进行等比例的缩小【因为比较时是对各列内部进行比较得到的结果,因此一列内同时缩小并不影响,但是好处就是数据大小接近了其他列】

  • 中心化:数据集的各个数据减去均值
  • 标准化:中心化后的数据除以标准差
#比如现在有一组数据,想看看他们之间的差别
X=c(1,3,6,8,3)
> X-mean(X) #中心化的结果,发现差别还是比较大,如3.8与-3.2
[1] -3.2 -1.2  1.8  3.8 -1.2
> (X-mean(X))/sd(X) #进行标准化,可以看到数据比较接近了
[1] -1.153200 -0.432450  0.648675  1.369425 -0.432450

上面是原理,当然实际用的时候,可以直接使用scale函数

scale(x, center = TRUE, scale = TRUE)
#center = TRUE进行中心化
#scale = TRUE 进行标准化
> scale(X)
          [,1]
[1,] -1.153200
[2,] -0.432450
[3,]  0.648675
[4,]  1.369425
[5,] -0.432450
attr(,"scaled:center")
[1] 4.2
attr(,"scaled:scale")
[1] 2.774887

一个实例数据集mtcars的处理前后

#mtcars是一个数据框,首先转换成矩阵,然后画热图
> y=as.matrix(mtcars)
> heatmap(y)
> y1=scale(y)
> heatmap(y1)

2

10 数据框变形——reshape2

install.packages("reshape2")
library(reshape2)
#原理想象一下炼钢的过程:将数据融化,然后注入模具,就能得到想要的形状
#melt函数将宽数据变成长数据,cast将长数据变为宽数据
> help(package="reshape2") #查看包的帮助信息
# 先看一下其中的melt.data.frame,帮助信息中有实例数据,帮助理解
> airquality
    Ozone Solar.R Wind Temp Month Day
1      41     190  7.4   67     5   1
2      36     118  8.0   72     5   2
#先将列名改为小写,就为了输入方便
> names(airquality) = tolower(names(airquality) )
> airquality
    ozone solar.r wind temp month day
1      41     190  7.4   67     5   1
2      36     118  8.0   72     5   2
# 再用melt融合数据,融合后的数据变成了3列,每一行都是唯一的;其中variable是因子,包含了之前的列名
> head(melt(airquality))
  variable value
1    ozone    41
2    ozone    36
3    ozone    12
4    ozone    18
5    ozone    NA
6    ozone    28
# variable其中包括了month、day,让他们当成id,其余的"ozone"   "solar.r" "wind"    "temp" 才作为观测名
> aq1 = melt(airquality,id=c("month","day"))
> head(aq1)
  month day variable value
1     5   1    ozone    41
2     5   2    ozone    36
3     5   3    ozone    12
4     5   4    ozone    18
5     5   5    ozone    NA
6     5   6    ozone    28
#然后可以进行重铸cast:reshape2包在reshape1的基础上将cast又重新细分,dcast处理数据框,acast返回向量、矩阵或数组
#dcast读取melt的结果后,根据提供的公式来融合数据。其中的formula参数就是融合后的数据格式【formula中使用波浪线~,表示二者相关联,但不是相等】
# 我们这里融合后的数据有4列:month、day、variable(其中又包括了4个变量)、value
> aqcast=dcast(aq1, month ~ variable, fun.aggregate = mean, na.rm=T)
#想看month和variable之间的关系,那么一个月有许多天,days不指定的话,R不知道怎么统计,于是我们可以使用fun.aggregate这个函数,指定一个统计函数,比如sum/mean等,再用na.rm去掉缺失值,就得到了每个月这四个变量的平均值
> head(aqcast)
  month    ozone  solar.r      wind     temp
1     5 23.61538 181.2963 11.622581 65.54839
2     6 29.44444 190.1667 10.266667 79.10000
3     7 59.11538 216.4839  8.941935 83.90323
4     8 59.96154 171.8571  8.793548 83.96774
5     9 31.44828 167.4333 10.180000 76.90000

11 tidyr

tidy整洁的,相比这个包的数据一定要求比较整洁的tidy data

什么才算整洁的数据呢?
  • 每一列代表一个变量
  • 每一行代表一个观测值
  • 一个观测和一个变量确定唯一的值
  • 【如果存在相同行名或列名就不算】
四个重要的函数:
  • gather:宽数据转为长数据【作用等于reshape2中的melt函数】
  • spread:长数据转位宽数据【作用等于reshape2中的cast函数】
  • unite:多列合并为一列
  • separate:一列分为多列

使用mtcars数据集,符合tidy data的要求

#取部分mtcars数据(前6行,前4列)
> mdata = mtcars[1:6,1:4] #发现car names是以行名存在的,我们在mdata的基础上新加一列names,赋值car names。也就是将mdata和新建的行名变量合并在一起,组成一个新的数据框
> mdata=data.frame(names=rownames(mdata),mdata)
> mdata
                              names  mpg cyl disp  hp
Mazda RX4                 Mazda RX4 21.0   6  160 110
Mazda RX4 Wag         Mazda RX4 Wag 21.0   6  160 110
Datsun 710               Datsun 710 22.8   4  108  93
Hornet 4 Drive       Hornet 4 Drive 21.4   6  258 110
Hornet Sportabout Hornet Sportabout 18.7   8  360 175
Valiant                     Valiant 18.1   6  225 105

## 宽数据得到了,接下来使用gather
#gather(data, key = "key", value = "value",...)
#data:像mdata这样的数据框
#key、value:处理后的
#...指定对哪些变量进行处理
> gdata=gather(mdata,key = "Key", value = "Value", mpg,cyl, disp,hp)
#这里的列名可以用列的编号代替,比如:mpg,cyl, disp,hp 对应2:4
               names  Key Value
1          Mazda RX4  mpg  21.0
2      Mazda RX4 Wag  mpg  21.0
3         Datsun 710  mpg  22.8
4     Hornet 4 Drive  mpg  21.4
5  Hornet Sportabout  mpg  18.7
6            Valiant  mpg  18.1
7          Mazda RX4  cyl   6.0
8      Mazda RX4 Wag  cyl   6.0
9         Datsun 710  cyl   4.0
10    Hornet 4 Drive  cyl   6.0
11 Hornet Sportabout  cyl   8.0
12           Valiant  cyl   6.0
13         Mazda RX4 disp 160.0
14     Mazda RX4 Wag disp 160.0
15        Datsun 710 disp 108.0
16    Hornet 4 Drive disp 258.0
17 Hornet Sportabout disp 360.0
18           Valiant disp 225.0
19         Mazda RX4   hp 110.0
20     Mazda RX4 Wag   hp 110.0
21        Datsun 710   hp  93.0
22    Hornet 4 Drive   hp 110.0
23 Hornet Sportabout   hp 175.0
24           Valiant   hp 105.0
## 使用spread又能将gdata打回原形
> spread(gdata,key = "Key", value = "Value")
## 使用seperate分隔
> tmp1=data.frame(x=c(NA,"1.b-c","2-c","3-d"))
> tmp2=separate(tmp1, col=x, into=c("X","Y"),sep="-")
     X    Y
1 <NA> <NA>
2  1.b    c
3    2    c
4    3    d
## 使用unite连接
#先输入要操作的数据框tmp2,然后设定拼接后的列名col,然后指定拼接tmp2中的哪些列,最后指定sep分隔符
> unite(tmp2,col="XY",X,Y,sep="-")
     XY
1 NA-NA
2 1.b-c
3   2-c
4   3-d

12 dplyr

> ls("package:dplyr") #查看一下这个包中的函数(共245个)
> help(package="dplyr") #查看包的帮助信息
## filter过滤功能
> dplyr::filter(iris,iris$Sepal.Width>4)
#这里调用函数的方式和一般的有点不太一样,因为dplyr中的函数太多,很大可能和其他包的函数名重合,因此使用dplyr::避免这个问题
 Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.7         4.4          1.5         0.4  setosa
2          5.2         4.1          1.5         0.1  setosa
3          5.5         4.2          1.4         0.2  setosa

## distinct去除重复,等于linux中uniq功能
> tmp3=iris[1:3,] #构建两个之间有重复行的数据tmp3、tmp4
> tmp4=iris[1:4,]
> dplyr::distinct(rbind(tmp3,tmp4)) #先将tmp3、4按行合并起来,再去重
 Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa

##slice:切片
> dplyr::slice(iris,3:6) #取出3-6行
 Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          4.7         3.2          1.3         0.2  setosa
2          4.6         3.1          1.5         0.2  setosa
3          5.0         3.6          1.4         0.2  setosa
4          5.4         3.9          1.7         0.4  setosa

##sample_n:随机取样
> dplyr::sample_n(iris,5)
  Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
34          5.5         4.2          1.4         0.2     setosa
57          6.3         3.3          4.7         1.6 versicolor
91          5.5         2.6          4.4         1.2 versicolor
52          6.4         3.2          4.5         1.5 versicolor
17          5.4         3.9          1.3         0.4     setosa

##sample_frac: 按比例取样
> dplyr::sample_frac(iris,0.02)
   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
3           5.5         3.5          1.3         0.2     setosa
10          5.7         2.8          4.1         1.3 versicolor
6           5.9         3.0          4.2         1.5 versicolor

##arrange:排序【这里对Sepal.Width这一列进行排序】
> head(dplyr::arrange(iris,iris$Sepal.Width))
 Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1          5.0         2.0          3.5         1.0 versicolor
2          6.0         2.2          4.0         1.0 versicolor
3          6.2         2.2          4.5         1.5 versicolor
4          6.0         2.2          5.0         1.5  virginica
5          4.5         2.3          1.3         0.3     setosa
6          5.5         2.3          4.0         1.3 versicolor
#要逆向排序(从大到小)
> head(dplyr::arrange(iris,desc(iris$Sepal.Width)))
 Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.7         4.4          1.5         0.4  setosa
2          5.5         4.2          1.4         0.2  setosa
3          5.2         4.1          1.5         0.1  setosa
4          5.8         4.0          1.2         0.2  setosa
5          5.4         3.9          1.7         0.4  setosa
6          5.4         3.9          1.3         0.4  setosa

##取子集select,可以直接根据列名选择,可以根据各种条件【如:以某些字符开头、结尾、包含固定字符等】,相比subset函数更强大
> select(iris,starts_with("Petal")) #取以xx开头的列
> select(iris,ends_with("Width")) #取以xx结尾的列
> select(iris,Species,everything()) #将原来的最后一列Species移到第一列
> select(df,X4:X6) #选择df数据框X4-X6这些列
#当然需要注意!X4-X6这中间可能不是按顺序编号的,可能X4和X6之间还有X1、X7、X9等等,那么如何只选出X4、X5、X6真正的X4-X6呢?
> select(df, num_range("X",4:6)) #给出了上面话的答案
> select(iris,-starts_with("Petal")) #反选
> select(mtcars, .data$cyl)#当数据集名字不想多次重复,可以用.data代替
> select(mtcars, .data$mpg : .data$disp) #使用.data多选几列
> select(iris,petal_length=Petal.Length) #对列重命名,并且结果只保留重命名的这一列
> rename(iris, petal_length = Petal.Length) # 也是重命名,但是所有列都保留
#想要重命名多列,可以这样:
> vars <- c(var1 = "cyl", var2 ="am") #先命名好,比如要把cyl更换为var1
> select(mtcars, !!vars) #与上面select效果一致
> rename(mtcars, !!vars) #与上面rename效果一致

##统计函数summarise
> summarise(mtcars, sum=sum(mpg))
   sum
1 642.9
#还包括summarise_all等
> summarise_all(mtcars, sum)
   mpg cyl   disp   hp   drat      wt   qsec vs am gear carb
1 642.9 198 7383.1 4694 115.09 102.952 571.16 14 13  118   90

##分组:group_by
> dplyr::group_by(iris,Species) #对iris数据集按照Species进行分组
# A tibble: 150 x 5
# Groups:   Species [3]

##添加新的变量mutate
> dplyr::mutate(iris, var1=iris$Sepal.Length+iris$Petal.Length) %>% head()
 Sepal.Length Sepal.Width Petal.Length Petal.Width Species var1
1          5.1         3.5          1.4         0.2  setosa  6.5
2          4.9         3.0          1.4         0.2  setosa  6.3
3          4.7         3.2          1.3         0.2  setosa  6.0
4          4.6         3.1          1.5         0.2  setosa  6.1
5          5.0         3.6          1.4         0.2  setosa  6.4
6          5.4         3.9          1.7         0.4  setosa  7.1

########################################################################## 上面都是对一个数据框进行操作,如何对两个操作呢?###########
###############################################################
#先造两个数据框
a=data.frame(m1=c("a","b","c"),m2=c(2,3,4));a
b=data.frame(m1=c("a","b","z"),m3=c(T,T,T));b

###关于集合的操作
#先进行左连接【left】【以a的m1为依据,但是b中m1没有c,所以它的第三行m3是NA】
> dplyr::left_join(a,b,by="m1")
 m1 m2   m3
1  a  2 TRUE
2  b  3 TRUE
3  c  4   NA
#再进行右连接【right】
> dplyr::right_join(a,b,by="m1")
 m1 m2   m3
1  a  2 TRUE
2  b  3 TRUE
3  z NA TRUE
#内连接【inner取交集】
> dplyr::inner_join(a,b,by="m1")
 m1 m2   m3
1  a  2 TRUE
2  b  3 TRUE
#全连接【full取并集】
> dplyr::full_join(a,b,by="m1")
 m1 m2   m3
1  a  2 TRUE
2  b  3 TRUE
3  c  4   NA
4  z NA TRUE
#半连接【semi】根据右侧表b的内容对左侧表a进行过滤,输出交集
#反连接【anti】也是根据右侧表b,但输出a、b的补集

###几个数据集的合并【其实原理也是利用了集合】
#先造两个数据集【他们之间是有交叉的行的】
> one=mutate(mtcars,Name=rownames(mtcars)) %>% slice(1:15)
> two=mutate(mtcars,Name=rownames(mtcars)) %>% slice(5:20)
> intersect(one,two)#取交集
> dplyr::union(one,two) #取并集
> setdiff(one,two) #求one的补集【相对于two的补集】;交换下顺序就是求two的补集了

13 链式操作符

相当于Linux中的管道符,R中使用%>%,实现一个函数的输出传给下一个函数,作为下一个的输入

使用ctrl + shift + M方便打出

#例如:取出第3-6行
> head(mtcars) %>% tail(3) 

##分组加统计:group_by + summarise
> iris %>% group_by(Species) %>% summarise(total=sum(Petal.Length)) %>% arrange()
# A tibble: 3 x 2 可以看到分成了setosa、versicolor、virginica 三组,另外每一组的Petal.Length总数也统计出来,最后使用arrange进行排序
  Species    total
  <fct>      <dbl>
1 setosa      73.1
2 versicolor 213  
3 virginica  278. 
Yunze Liu
Yunze Liu
Bioinformatics Sharer

Co-founder of Bioinfoplanet(生信星球)

Next
Previous

Related