R数据格式转换 您所在的位置:网站首页 文件格式怎么转换表格格式 R数据格式转换

R数据格式转换

2024-06-24 14:15| 来源: 网络整理| 查看: 265

刘小泽写于2018.8.27-28

我们日常使用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$列1value1 & c$列1A=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) 中心化、标准化 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 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 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 1 setosa 73.1 2 versicolor 213 3 virginica 278.

欢迎关注我们的公众号~_~   我们是两个农转生信的小硕,打造生信星球,想让它成为一个不拽术语、通俗易懂的生信知识平台。需要帮助或提出意见请后台留言或发送邮件到[email protected]

Welcome to our bioinfoplanet!



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有