R语言数据结构主要有以下四种:
2.数据框
四种数据结构,重点掌握 向量 和 数据框
Vector向量 :一维,数值型,字符型(加引号),逻辑型。
matrix矩阵:二维,只允许一种数据类型。
data.frame数据框 :二维,每列只允许一种数据类型,列与列之间的数据类型是否相同不管。
list列表:包罗万象,可以包含向量,矩阵,数据框等。
判断数据结构的函数:
class()
向量的详细讲解在上一篇文章,以下主要讲数据框,矩阵,列表:
2.数据框
2.1 数据框来源
(1)在R中新建:用代码生成。
(2)由已有数据转换或处理得到:向量组装,矩阵转换,或是从列表里提取。
(3)从文件中读取:把文件导入到R语言里头,一个常规的表格读入到R语言里就是一个数据框。
(4)内置数据集:安装某些R包是自带,有些直接就可以用,如irirs
2.2.1 新建数据框
df <- data.frame(gene = paste0("gene",1:4),
change = rep(c("up","down"),each = 2),
score = c(5,3,-2,-4))
# gene change score
# 1 gene1 up 5
# 2 gene2 up 3
# 3 gene3 down -2
# 4 gene4 down -4
##有多少个等号就有多少列,多少个变量名(向量)。
##向量的长度(元素个数)决定行数,每个向量的长度要一致。
以下大部分操作使用的数据框为df
2.2.2 从文件中读取数据框
df2 <- read.csv("gene.csv")
# gene change score
# 1 gene1 up 5
# 2 gene2 up 3
# 3 gene3 down -2
# 4 gene4 down -4
##简单的表格读取和赋值
##文件是之前用csv格式保存好,文件一定要放在当前工作目录下,小洁老师帮我们准备好的csv文件
2.2 数据框属性
几个重要的函数:查看数据框的行数和列数,行名和列名;以及单独查行的数量,列的数量
dim()#查数据框几行几列,维度。
rownames(df)#查看行名。
colnames(df)#查看列名。
nrow()#查数据框有几行。
ncol()#查数据框有几列。
df <- data.frame(gene = paste0("gene",1:4),
change = rep(c("up","down"),each = 2),
score = c(5,3,-2,-4))
##以df数据框演示
dim(df)#查数据框几行几列
#[1] 4 3
##返回数据框的维度,即行数和列数。df数据框4行3列
nrow(df)#数据框有几行
#[1] 4
##统计数据框有几行
ncol(df)#数据框有几列
#[1] 3
##统计数据框有几列
rownames(df)#行名
#[1] "1" "2" "3" "4"
##显示数据框的所有行名
colnames(df)#列名
#[1] "gene" "change" "score"
##显示数据框的所有列名
2.3 数据框取子集
数据框取子集有几种方法:$
符号,坐标,名字,逻辑值
在[,]
里,行在前面(左边),列在后面(右边),行与列用逗号,
隔开:[行,列]
2.3.1 使用$
取列
df$score
##取df数据框的score列
#删掉score,按tab键试试,使用tab键补全,避免拼写错误
mean(df$score)
#[1] 0.5
##求平均值,其实score列就是一个向量,可以进行运算
# 1 gene1 up 5
# 2 gene2 up 3
##对行进行筛选。把df$score>0看做一个整体,返回是一个逻辑值,筛选score列大于0的行。
##细节理解如下:
df$score
#[1] 5 3 -2 -4
df$score > 0
#[1] TRUE TRUE FALSE FALSE
df$score[df$score>0]
#[1] 5 3
##df$score看在是一个向量,现在是要把所在的行筛选出来,对数据框而言,行在左边,所以把筛选条件放在行的位置
df[df$score>0,]
# gene change score
#1 gene1 up 5
#2 gene2 up 3
数据框按照逻辑值取子集,TRUE对应的行/列留下,FALSE对应的行/列去掉。
筛选score对于0的基因:
df[df$score>0,1]
#[1] "gene1" "gene2"
##按数据框取子集,要知道基因是在哪一列,在第1列.
df$gene[df$score>0]
#[1] "gene1" "gene2"
##按照向量取子集,对基因所在的向量操作。
##类似y[x>0],x生成的逻辑值给y来用,现在的gene列和score列有对应关系。以前单独向量的y和x没有绑定关系,这是数据框带来隐藏的知识点。
变量赋值思维:
nn = c('gene','change')
df[,nn]##相当于代码df[,c('gene','change')],为嵌套代码
##用nn替代 c('gene','change'),以后会多次出现时避免写错和冗余,还有以后只在nn = c('gene','change')出修改,联想到ids的赋值。
##变量思想,赋值思想
df[,3]
#[1] 5 3 -2 -4
##取df的第三列
df[,ncol(df)]
#[1] 5 3 -2 -4
##ncol(df)返回为3,数据框只有3列,其实是取第ncol列,最后一列。
##以后联想到删减或是新增一列,关键信息永远都在最后一列ncol(df)。
df[,-ncol(df)]
# gene change
# 1 gene1 up
# 2 gene2 up
# 3 gene3 down
# 4 gene4 down
##-ncol(df)表示不要最后一列。
##好奇探索,提取最后一行和去掉最后一行
df[nrow(df),]
df[-nrow(df),]
##练习题:筛选test中,最后一列(Species)值为a或c的行(没有test数据框没法练习,test由生信技能树提供)
test2 <- test[test$Species%in%!="b",]
##这种做法适合向量里有3选2,如果是50选20比较麻烦
test2 <- test[test$Species %in% c('a','c'),]
##最优的做法,可适用于很多场景。不用==,因为a,c固定等位循环补齐不符合题目要求
##小洁老师出的题和答案思路广。
2.4 数据框修改
2.4.1 改一个格(值)
df[3,3]<- 5
##按坐标修改一个格子,把第三行和第三列的数字改为5
2.4.2 改一整列
df$score<-c(12,23,50,2)
##修改某一列,一列也是一个向量,修改记得长度一致
2.4.3 增加一列(一般默认放在最后的一列)
df$p.value <-c(0.01,0.02,0.07,0.05)
##增加某一列
##为什么不新增一行,一行里有字符型,数值型,不能以一个向量的形式存在,会把那一行的数值型弄成字符型。
##新增一列,因为列与列之间是可以相对独立运行的,数据框所有的操作都是围绕列来操作的。
##如果要新增行,把两个类似的表格用rbind()函数拼在一起。
2.4.4 修改行名和列名
nrow(df)##先看看有几行
rownames(df) <- c("r1","r2","r3","r4")
ncol(df)##先看看有几列
colnames(df) <- c('Gene','differ','point','P')
##行名和列名返回是向量,R语言里任何函数的返回结果,要符合R语言内部规则,了解R语言的数据结构和数据类型很重要。修改数据框行名或是列名,相当于对一个向量进行修改就相当于重新赋值。
2.4.5 只修改某一行/列的名
colnames(df)[2]="CHANGE"
##修改第二列的列名,相当于对向量取子集并赋值
修改第二列的列名,就是修改列名这个向量的第二个元素
2.5 两个数据框的连接
test1 <- data.frame(name = c('jimmy','nicker','Damon','Sophie'),
blood_type = c("A","B","O","AB"))
test1
test2 <- data.frame(name = c('Damon','jimmy','nicker','tony'),
group = c("group1","group1","group2","group2"),
vision = c(4.2,4.3,4.9,4.5))
test2
两个数据框"列名"不一样的连接:使用merge()函数
test1 <- data.frame(name = c('jimmy','nicker','Damon','Sophie'),
blood_type = c("A","B","O","AB"))
test1
test3 <- data.frame(NAME = c('Damon','jimmy','nicker','tony'),
weight = c(140,145,110,138))
test3
###列名不同的两个数据框第一种连接方式,把一个数据框的列名修改后再连接
colnames(test3)[1]="name"
##列名不同的两个数据框第二种方式:某一列有交集,但是列名不一样的连接
merge(test1,test3,by.x = "name",by.y = "NAME")
##注意代码里的数据与之对应列名的顺序不能搞错,原来的代码:
#merge(x=test1,y=test3,by.x = "name",by.y = "NAME")#把最前面的x=和y=省略
##要求:共同的一列且要存在交集
?merge
#查看帮助文档
https://blog.csdn.net/weixin_39718006/article/details/110516670
根据值匹配合并数据框:左连接、右连接、全连接、内连接、半连接、反连接
left_join(x, y, by)
right_join(x, y, by)
full_join(x, y, by)
inner_join(x, y, by)
semi_join(x, y, by)
anti_join(x, y, by)
后续的笔记会有详细介绍
3.1 矩阵新建和取子集
3.2.1 新建矩阵
m <- matrix(1:9, nrow = 3)
##1:9,1到9个数字,排成3行。参数nrow=3 或是 ncol=3都可以
# [,1] [,2] [,3]
# [1,] 1 4 7
# [2,] 2 5 8
# [3,] 3 6 9
##没有行名和列名的矩阵
3.2.2 矩阵取子集:[ ]
矩阵不能用$
符号取子集
m[2,]
m[,1]
m[2,3]
m[2:3,1:2]
3.2 矩阵的转置和转换
t():转置函数,行与列的互换
as.data.frame():转换,把矩阵变为数据框,用as.matrix()函数也能把数据框变为矩阵
colnames(m) <- c("a","b","c")
#行变列,列变行,t()转置函数
as.data.frame(m)
##把m矩阵转换为数据框
class(m)
##仍旧是矩阵,要赋值才真正发生保存的变化,df=as.data.frame(m)
as.matrix(df)
##把数据框df转换为矩阵
##as开头表示转换
3.3 矩阵画热图
# a b c
# [1,] 1 4 7
# [2,] 2 5 8
# [3,] 3 6 9
pheatmap::pheatmap(m)
聚类,相似的行,相似的列会聚在一起。热图自动聚类,行和列的相对位置发生了变化,只是列与列,行与行之间的变化规律。
热图默认聚类,修改参数,不让聚类,热图与表达矩阵对应。
pheatmap::pheatmap(m,cluster_rows = F,cluster_cols =F )
##热图默认为T,行聚类,列聚类,改为F就不聚类,使用tab键补全,参数不需要手打字。
$
有两个作用:数据框取子集和列表取子集。在矩阵和向量里不能用$
。
用class()
函数更能具体说明问题,判断数据结构和数据类型
df <- data.frame(gene = paste0("gene",1:4),
change = rep(c("up","down"),each = 2),
score = c(5,3,-2,-4))
class(df)
#[1] "data.frame"
class(df$gene)
#[1] "character"
class(df$score)
#[1] "numeric"
class(df$change)
#[1] "character"
5.补充知识
5.1元素的"名字" -names()
scores = c(100,59,73,95,45)
names(scores) = c("jimmy","nicker","Damon","Sophie","tony")
scores
# jimmy nicker Damon Sophie tony
# 100 59 73 95 45
##在一种简单的数据结构里容纳两种不同的信息,好处在向量里容纳不同的两种信息,但是名字仅仅是向量的一个属性,就是说,不会因为向量拥有名字而改变它本身是数值型向量的事实,有无名字都不会改变该向量为数值型向量。名字的用处是用于提子集,如下:
scores["jimmy"]
# jimmy
# 100
##提取单个元素的分数,等同于代码:scores[1]
scores[c("jimmy","nicker")]
# jimmy nicker
# 100 59
##提取多个元素的分数,用c()函数,等同于代码:scores[c(1,2)]
names(scores)[scores>60]
#[1] "jimmy" "Damon" "Sophie"
##以后应用在提取表达量大于多少的基因
scores[scores>60]
# jimmy Damon Sophie
# 100 73 95
5.2 删除变量
##每次赋值后环境里都会多一个变量,引进后再推出去,即删除。
rm(l)
##删除一个变量。
rm(df,m)
##删除多个
rm(list = ls())
##删除全部,常用,每次在分析数据(或是调试代码)第一句都会是这句代码。清空环境,后面实战反复出现。
control l
##按control 和 l键,清空控制台。