3.10 S4对象
S3系统允许创建行为依赖于其第一个参数的类的函数,但不考虑其他参数。另外,S3不允许自定义数据结构,S3系统中使用的变量是单一类型向量或列表。S4系统可以解决这些问题。S4系统与S3的主要区别在于,在S4中每个类都有正式定义,描述该类的对象中存储了什么数据(在S3中您可以将任何类分配给任何变量)。数据存储在具有名称和指定类型的插槽(slots)中,需要指定插槽来创建新类。
现在我们可以创建此类的变量:
> setClass("Person",
slots = c(
name = "character",
age = "numeric"
)
)
> john = new("Person", name = "John Smith", age = 30)
> class(john)
[1] "Person"
attr(,"package")
[1] ".GlobalEnv"
> typeof(john)
[1] "S4"
> john
An object of class "Person"
Slot "name":
[1] "John Smith"
Slot "age":
[1] 30
通常,槽可以通过特定函数访问和修改。对于我们上面指定的Person类,可以使用函数name
访问name。但是R允许使用运算符@
直接访问插槽:
> john@name
[1] "John Smith"
> slotNames(john)
[1] "name" "age"
> slot(john,'age')
[1] 30
> john@age
[1] 30
3.11 更多信息
可以在交互式会话中输入?function
来获取与这些数据类型相关的任何R命令的更多信息。
3.12 整洁数据(Tidy Data)
3.12.1 什么是整洁数据
整洁数据是一个由Hadley Wickham(Wickham, 2014)定义的概念。整洁数据具有以下三个特征:
- 每列代表一个变量。
- 每行代表一个观测。
- 每个单元格代表一个值。
以下是一些整洁数据的示例:
> data.frame(Students=c("Mark", "Jane", "Mohammed", "Tom", "Celia"),
Subject=c("Maths", "Biology", "Physics", "Maths", "Computing"),
Years=c(1,2,3,2,3),
Score=c(5,6,4,7,9))
Students Subject Years Score
1 Mark Maths 1 5
2 Jane Biology 2 6
3 Mohammed Physics 3 4
4 Tom Maths 2 7
5 Celia Computing 3 9
以下是一些混乱数据的示例:
> data.frame(Students=c("Matt", "Matt", "Ellie", "Ellie", "Tim", "Tim", "Louise", "Louise", "Kelly", "Kelly"),
Sport=c("Tennis","Tennis", "Rugby", "Rugby","Football", "Football","Swimming","Swimming", "Running", "Running"),
Category=c("Wins", "Losses", "Wins", "Losses", "Wins", "Losses", "Wins", "Losses", "Wins", "Losses"),
Counts=c(0,1,3,2,1,4,2,2,5,1))
Students Sport Category Counts
1 Matt Tennis Wins 0
2 Matt Tennis Losses 1
3 Ellie Rugby Wins 3
4 Ellie Rugby Losses 2
5 Tim Football Wins 1
6 Tim Football Losses 4
7 Louise Swimming Wins 2
8 Louise Swimming Losses 2
9 Kelly Running Wins 5
10 Kelly Running Losses 1
任务1:杂乱的数据在哪些方面是不整洁的?我们如何才能使杂乱的数据变得整洁?
整洁的数据通常比不整洁的数据更容易处理,特别是如果你使用诸如ggplot
之类的包。幸运的是,有包可以让不整洁的数据变得整洁。今天,我们将探讨tidyr
包中的几个可用函数,这些函数可用于整理杂乱的数据。如果你有兴趣了解更多关于整理数据的信息,我们推荐你阅读Garrett Grolemund和Hadley Wickham合著的《R for Data Science》。电子版可在此处获取:http://r4ds.had.co.nz/。
上面的杂乱数据之所以杂乱,是因为两个变量(Wins
和Losses
)存储在一列(Category
)中。这是数据杂乱的常见原因。为了整理这些数据,我们需要将Wins
和Losses
分成列,并将Counts
中的值存储在这些列中。tidyverse
包中有一个函数可以执行此操作。该函数名为spread
,它接受两个参数,key
和value
。将包含多个变量的列的名称传递给key
,将包含多个变量的值的列的名称传递给value
。
> library(tidyverse)
> sports<-data.frame(Students=c("Matt", "Matt", "Ellie", "Ellie", "Tim", "Tim", "Louise", "Louise", "Kelly", "Kelly"),
Sport=c("Tennis","Tennis", "Rugby", "Rugby","Football", "Football","Swimming","Swimming", "Running", "Running"),
Category=c("Wins", "Losses", "Wins", "Losses", "Wins", "Losses", "Wins", "Losses", "Wins", "Losses"),
Counts=c(0,1,3,2,1,4,2,2,5,1))
> sports
Students Sport Category Counts
1 Matt Tennis Wins 0
2 Matt Tennis Losses 1
3 Ellie Rugby Wins 3
4 Ellie Rugby Losses 2
5 Tim Football Wins 1
6 Tim Football Losses 4
7 Louise Swimming Wins 2
8 Louise Swimming Losses 2
9 Kelly Running Wins 5
10 Kelly Running Losses 1
> spread(sports, key=Category, value=Counts)
Students Sport Losses Wins
1 Ellie Rugby 2 3
2 Kelly Running 1 5
3 Louise Swimming 2 2
4 Matt Tennis 1 0
5 Tim Football 4 1
任务2:下面定义的数据框foods
很乱。找出原因并使用spread()
来整理它。
foods<-data.frame(student=c("Antoinette","Antoinette","Taylor", "Taylor", "Alexa", "Alexa"),
Category=c("Dinner", "Dessert", "Dinner", "Dessert", "Dinner","Dessert"),
Frequency=c(3,1,4,5,2,1))
数据混乱的另一种常见情况是列是值而不是变量。例如,下面的数据框显示了一些学生在5月和6月的测试中获得的百分比。数据很混乱,因为5月和6月的列是值,而不是变量。
percentages<-data.frame(student=c("Alejandro", "Pietro", "Jane"),
"May"=c(90,12,45),
"June"=c(80,30,100))
tidyverse
包中有一个函数可以解决这个问题。gather()
将列的名称、key
和value
作为参数。这一次,key
是以列名作为值的变量的名称,value
是分布在多列中的值的变量名称。
> gather(percentages, "May", "June", key="Month", value = "Percentage")
student Month Percentage
1 Alejandro May 90
2 Pietro May 12
3 Jane May 45
4 Alejandro June 80
5 Pietro June 30
6 Jane June 100
这些例子与单细胞RNA-seq分析没有太大关系,但旨在帮助说明整洁和不整洁数据的特征。如果您的数据以整洁的格式存储,您会发现分析单细胞RNA-seq数据变得更加容易。幸运的是,我们通常用于单细胞RNA-seq分析的数据结构鼓励以整洁的方式存储数据。
3.12.2 什么是Rich Data
如果你在Google上搜索“Rich Data”,你会发现这个术语有很多不同的定义。在本课程中,我们将使用“Rich Data”来表示通过组合来自多个来源的信息而生成的数据。例如,您可以通过在R中创建一个对象来制作Rich Data,该对象包含单细胞RNA测序实验中跨细胞的基因表达矩阵,还包含有关如何进行实验的信息。我们将在下面讨论的SingleCellExperiment类的对象就是Rich Data的一个例子。
3.12.3 SingleCellExperiment
类
SingleCellExperiment
(SCE)是一个S4类,用于存储单细胞实验的数据。这包括用于存储和检索峰值信息、每个细胞的降维坐标和尺度因子以及基因和文库的常用元数据的专门方法。
可以使用其构造函数创建此类的对象:
> library(SingleCellExperiment)
> counts <- matrix(rpois(100, lambda = 10), ncol=10, nrow=10)
> rownames(counts) <- paste("gene", 1:10, sep = "")
> colnames(counts) <- paste("cell", 1:10, sep = "")
> sce <- SingleCellExperiment(
assays = list(counts = counts),
rowData = data.frame(gene_names = paste("gene_name", 1:10, sep = "")),
colData = data.frame(cell_names = paste("cell_name", 1:10, sep = ""))
)
> sce
class: SingleCellExperiment
dim: 10 10
metadata(0):
assays(1): counts
rownames(10): gene1 gene2 ... gene9 gene10
rowData names(1): gene_names
colnames(10): cell1 cell2 ... cell9 cell10
colData names(1): cell_names
reducedDimNames(0):
altExpNames(0):
在SingleCellExperiment
中,用户可以为检测条目分配任意名称。为了协助包之间的互操作性,作者对特定类型数据的名称提供了一些建议:
- counts:原始计数数据,例如特定基因的read数或转录本数。
- normcounts:与原始计数具有相同尺度的标准化值。例如,计数除以以1为中心的细胞特异尺度因子。
- logcounts:对数转换计数或类似计数的值。在大多数情况下,定义为对数转换的normcounts,例如,使用以2为底的对数和伪计数1。
- cpm:每百万计数。这是每个细胞中每个基因的read计数,除以每个细胞的文库大小(以百万为单位)。
- tpm:每百万转录本数。这是每个细胞中每个基因的转录本数除以该细胞中的转录本总数(以百万为单位)。
每个建议的名称都有一个适当的访问/修改方法,以方便操作SingleCellExperiment
。例如,我们可以取counts
槽,对其进行标准化,然后将其分配给normcounts
:
> normcounts(sce) <- log2(counts(sce) + 1)
> sce
class: SingleCellExperiment
dim: 10 10
metadata(0):
assays(2): counts normcounts
rownames(10): gene1 gene2 ... gene9 gene10
rowData names(1): gene_names
colnames(10): cell1 cell2 ... cell9 cell10
colData names(1): cell_names
reducedDimNames(0):
altExpNames(0):
> dim(normcounts(sce))
[1] 10 10
> head(normcounts(sce))
cell1 cell2 cell3 cell4 cell5 cell6 cell7 cell8
gene1 2.584963 3.321928 3.906891 3.584963 3.807355 2.807355 3.807355 3.584963
gene2 3.584963 3.459432 4.392317 3.584963 2.321928 3.459432 3.169925 3.000000
gene3 3.700440 3.807355 4.087463 3.700440 3.000000 3.459432 3.000000 3.169925
gene4 3.459432 3.321928 3.459432 3.000000 3.584963 3.584963 3.169925 3.906891
gene5 3.321928 3.459432 2.807355 4.000000 3.321928 3.584963 3.321928 3.807355
gene6 3.584963 2.000000 3.584963 3.584963 3.169925 3.459432 2.807355 3.700440
cell9 cell10
gene1 3.584963 3.321928
gene2 3.584963 3.321928
gene3 3.584963 2.321928
gene4 3.584963 3.700440
gene5 3.584963 2.807355
gene6 3.459432 2.584963
3.12.4 scater
包
scater
是一个用于单细胞RNA测序分析的R包(McCarthy等,2017)。该软件包包含几种有用的方法,用于进一步下游分析之前的质量控制、可视化和数据预处理。
scater
具有以下功能:
- 自动计算QC指标
- 使用伪比对对read数据进行转录本定量
- 数据格式标准化
- 丰富的可视化功能,可用于探索性分析
- 无缝集成到Bioconductor
- 简单的标准化方法
我们强烈建议所有单细胞RNA-seq分析都使用scater
,scater
是本课程第一部分的基础。
如下图所示,scater
将帮助您对表达矩阵进行质量控制、过滤和标准化。请记住,此图代表了scater
的原始版本,其中使用了SCESet
类。在最新版本中,此图仍然正确,只是SCESet
可以用SingleCellExperiment
类替代。
往期内容:
重生之我在剑桥大学学习单细胞RNA-seq分析——2. scRNA-Seq原始测序数据处理(1)
重生之我在剑桥大学学习单细胞RNA-seq分析——2. scRNA-Seq原始测序数据处理(2)
重生之我在剑桥大学学习单细胞RNA-seq分析——3. 单细胞分析中的R/Bioconductor简介(1)
重生之我在剑桥大学学习单细胞RNA-seq分析——3. 单细胞分析中的R/Bioconductor简介(2)