projectLSI:将你的单细胞或bulk转录组数据映射到参考数据集中

简介

在单细胞数据分析过程中,我们经常会遇到不同样本之间整合的批次效应和细胞类型注释的困难,projectLSI包利用term frequency–inverse document frequency (TF-IDF) transformation and latent semantic indexing (LSI)算法进行数据降维转换,可以将query的单细胞或bulk转录组数据集映射到reference参考数据集中以消除潜在的批次效应,同时也可以利用bulk转录组数据验证单细胞注释分群的结果。

R包安装

devtools::install_github("sajuukLyu/projectLSI")

实例演示

接下来,我们将使用两个单细胞转录组数据集pbmc3k和pbmc4k,以及一个bulk转录组数据集bulk.data进行实例演示projectLSI包的使用流程。我们将以pbmc3k数据集作为参考数据集,使用projectLSI程序将pbmc4k和bulk.data数据集映射到参考数据集中。

加载所需R包和示例数据集

pbmc3k and pbmc4k datasets are from package TENxPBMCData, and bulk.data is part of GSE74246.

library(Seurat)
library(projectLSI)
library(patchwork)

data(pbmc3k)
data(pbmc4k)
data(bulk.data)

pbmc3k
## An object of class Seurat 
## 32738 features across 2700 samples within 1 assay 
## Active assay: RNA (32738 features)
pbmc4k
## An object of class Seurat 
## 33694 features across 4340 samples within 1 assay 
## Active assay: RNA (33694 features)

bulk.data[1:5,1:5]
 #        CD4T_1 CD4T_2 CD4T_3 CD4T_4 CD8T_1
#A1BG          0      3      7      4      0
#A1BG-AS1      3      1      1      3      0
#A1CF         10     15      3      0      1
#A2M         141    273    870     92    351
#A2M-AS1      14     23    154     18     31
dim(bulk.data)
## [1] 25498    20
names(bulk.data)
# [1] "CD4T_1" "CD4T_2" "CD4T_3" "CD4T_4" "CD8T_1" "CD8T_2" "CD8T_3" "CD8T_4"
# [9] "NK_1"   "NK_2"   "NK_3"   "NK_4"   "B_1"    "B_2"    "B_3"    "B_4"
# [17] "Mono_1" "Mono_2" "Mono_3" "Mono_4"

单细胞数据预处理

# for pbmc3k
# 计算线粒体含量
pbmc3k$pct.mt <- PercentageFeatureSet(pbmc3k, pattern = "^MT-")
# 数据质控
FeatureScatter(pbmc3k, feature1 = "nCount_RNA", feature2 = "pct.mt") +
FeatureScatter(pbmc3k, feature1 = "nCount_RNA", feature2 = "nFeature_RNA")
image.png
# 质控过滤
pbmc3k <- subset(pbmc3k, subset = nFeature_RNA > 200 & nFeature_RNA < 2500 & pct.mt < 5)
# 数据标准化
pbmc3k <- NormalizeData(pbmc3k)
## Performing log-normalization
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
# 筛选高变异基因
pbmc3k <- FindVariableFeatures(pbmc3k, nfeatures = 2000)
## Calculating gene variances
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
## Calculating feature variances of standardized and clipped values
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|

# for pbmc4k
pbmc4k$pct.mt <- PercentageFeatureSet(pbmc4k, pattern = "^MT-")
FeatureScatter(pbmc4k, feature1 = "nCount_RNA", feature2 = "pct.mt") +
FeatureScatter(pbmc4k, feature1 = "nCount_RNA", feature2 = "nFeature_RNA")
image.png
pbmc4k <- subset(pbmc4k, subset = nFeature_RNA > 200 & nFeature_RNA < 3500 & pct.mt < 8)
pbmc4k <- NormalizeData(pbmc4k)
## Performing log-normalization
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
pbmc4k <- FindVariableFeatures(pbmc4k, nfeatures = 2000)
## Calculating gene variances
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
## Calculating feature variances of standardized and clipped values
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|

进行线性降维处理

这里,我们将使用projectLSI包对标准化的数据进行TF-IDF和LSI线性降维处理。注意,我们使用筛选出的高变异基因作为输入。

# 使用calcLSI函数进行线性降维
pbmc3k.lsi <- calcLSI(pbmc3k[["RNA"]]@data[VariableFeatures(pbmc3k), ])
pbmc3k.lsi$matSVD[1:5,1:5]
 #                          PC_1          PC_2          PC_3         PC_4
#3k_AAACATACAACCAC-1 -0.03787607 -1.038326e-02 -0.0009909208  0.005607445
#3k_AAACATTGAGCTAC-1 -0.03799807 -4.920159e-05  0.0066228430 -0.018501420
#3k_AAACATTGATCAGC-1 -0.03885814 -8.351669e-03 -0.0021662553  0.005449835

# 将LSI降维信息添加到seurat对象中
pbmc3k[["pca"]] <- CreateDimReducObject(
  embeddings = pbmc3k.lsi$matSVD,
  loadings = pbmc3k.lsi$fLoad,
  assay = "RNA",
  stdev = pbmc3k.lsi$sdev,
  key = "PC_")

ElbowPlot(pbmc3k)
image.png

细胞聚类分群

pbmc3k <- FindNeighbors(pbmc3k, dims = 1:10)
## Computing nearest neighbor graph
## Computing SNN

pbmc3k <- FindClusters(pbmc3k, resolution = 0.6)
## Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
## 
## Number of nodes: 2638
## Number of edges: 97177
## 
## Running Louvain algorithm...
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
## Maximum modularity in 10 random starts: 0.8542
## Number of communities: 9
## Elapsed time: 0 seconds

UMAP降维可视化

Notice that ret_model parameter should be TRUE for later projection.

set.seed(42)
umap.pbmc3k <- uwot::umap(pbmc3k.lsi$matSVD[, 1:10],
                          n_neighbors = 30,
                          min_dist = 0.5,
                          metric = "euclidean",
                          ret_model = T,
                          verbose = T)
## 00:58:06 UMAP embedding parameters a = 0.583 b = 1.334
## 00:58:06 Read 2638 rows and found 10 numeric columns
## 00:58:06 Using Annoy for neighbor search, n_neighbors = 30
## 00:58:06 Building Annoy index with metric = euclidean, n_trees = 50
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
## 00:58:06 Writing NN index file to temp file /tmp/RtmpbWcqgH/file17b95ca52051
## 00:58:06 Searching Annoy index using 8 threads, search_k = 3000
## 00:58:06 Annoy recall = 100%
## 00:58:07 Commencing smooth kNN distance calibration using 8 threads
## 00:58:07 Initializing from normalized Laplacian + noise
## Spectral initialization failed to converge, using random initialization instead
## 00:58:07 Commencing optimization for 500 epochs, with 110674 positive edges
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
## 00:58:12 Optimization finished

# 提取UMAP降维信息
umap.pbmc3k.emb <- umap.pbmc3k$embedding
rownames(umap.pbmc3k.emb) <- colnames(pbmc3k)
colnames(umap.pbmc3k.emb) <- paste0("UMAP_", seq_len(ncol(umap.pbmc3k.emb)))
head(umap.pbmc3k.emb)
#                       UMAP_1    UMAP_2
#3k_AAACATACAACCAC-1   4.462377  1.675100
#3k_AAACATTGAGCTAC-1  -1.583569 -9.764045
#3k_AAACATTGATCAGC-1   7.612832  1.880275

# 将UMAP降维信息添加到seurat对象中
pbmc3k[["umap"]] <- CreateDimReducObject(
  embeddings = umap.pbmc3k.emb,
  assay = "RNA",
  key = "UMAP_")

DimPlot(pbmc3k, label = T)
image.png
# 查看marker基因的表达情况
FeaturePlot(pbmc3k, c("MS4A1", "GNLY", "CD3E",
                      "CD14", "FCER1A", "FCGR3A",
                      "LYZ", "PPBP", "CD8A"), order = T)
image.png

细胞类型注释

image.png
new.cluster.ids <- c("Naive CD4 T", "Memory CD4 T", "CD14+ Mono",
                     "B", "NK", "FCGR3A+ Mono",
                     "CD8 T", "DC", "Platelet")
names(new.cluster.ids) <- levels(pbmc3k)
pbmc3k <- RenameIdents(pbmc3k, new.cluster.ids)

DimPlot(pbmc3k, label = T) + NoLegend()
image.png

将query单细胞数据集映射到参考数据集中

接下来,我们将使用projectLSI函数将pbmc4k查询数据集映射到参考数据集pbmc3k中。

matSVD.pbmc4k <- projectLSI(pbmc4k[["RNA"]]@data, pbmc3k.lsi)
head(matSVD.pbmc4k)
#                            PC_1        PC_2          PC_3        PC_4
#4k_AAACCTGAGAAGGCCT-1 -0.03410563  0.02377144  0.0002275122 0.001904910
#4k_AAACCTGAGACAGACC-1 -0.03532231  0.02358280  0.0023570705 0.001242694
#4k_AAACCTGAGATAGTCA-1 -0.03497681  0.02380977  0.0012423880 0.002034311

pbmc4k[["pca"]] <- CreateDimReducObject(
  embeddings = matSVD.pbmc4k,
  loadings = pbmc3k.lsi$fLoad,
  assay = "RNA",
  key = "PC_")

# cluster cells using projected LSI
pbmc4k <- FindNeighbors(pbmc4k, dims = 1:10)
## Computing nearest neighbor graph
## Computing SNN
pbmc4k <- FindClusters(pbmc4k, resolution = 0.6)
## Modularity Optimizer version 1.3.0 by Ludo Waltman and Nees Jan van Eck
## 
## Number of nodes: 4284
## Number of edges: 154662
## 
## Running Louvain algorithm...
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
## Maximum modularity in 10 random starts: 0.8670
## Number of communities: 10
## Elapsed time: 0 seconds

# perform UMAP using first 10 PCs, just like pbmc3k
umap.pbmc4k.proj <- uwot::umap_transform(matSVD.pbmc4k[, 1:10], umap.pbmc3k, verbose = T)
## 01:37:48 Read 4284 rows and found 10 numeric columns
## 01:37:48 Processing block 1 of 1
## 01:37:48 Writing NN index file to temp file /tmp/RtmpbWcqgH/file17b933607747
## 01:37:48 Searching Annoy index using 8 threads, search_k = 3000
## 01:37:48 Commencing smooth kNN distance calibration using 8 threads
## 01:37:48 Initializing by weighted average of neighbor coordinates using 8 threads
## 01:37:48 Commencing optimization for 167 epochs, with 128520 positive edges
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
## 01:37:50 Finished

head(umap.pbmc4k.proj)
#          [,1]       [,2]
#[1,] -11.620971  1.3273895
#[2,] -12.708588 -0.8110412
#[3,] -12.193903 -0.9287748
rownames(umap.pbmc4k.proj) <- colnames(pbmc4k)
colnames(umap.pbmc4k.proj) <- paste0("UMAP_", seq_len(ncol(umap.pbmc4k.proj)))

pbmc4k[["umap"]] <- CreateDimReducObject(
  embeddings = umap.pbmc4k.proj,
  assay = "RNA",
  key = "UMAP_")

DimPlot(pbmc4k, label = T)
image.png
FeaturePlot(pbmc4k, c("MS4A1", "GNLY", "CD3E",
                      "CD14", "FCER1A", "FCGR3A",
                      "LYZ", "PPBP", "CD8A"), order = T)
image.png
new.cluster.ids <- c("Naive CD4 T", "CD14+ Mono", "B", "Memory CD4 T",
                     "CD8 T", "CD14+ Mono", "NK", "FCGR3A+ Mono",
                     "DC", "Platelet")
names(new.cluster.ids) <- levels(pbmc4k)
pbmc4k <- RenameIdents(pbmc4k, new.cluster.ids)

DimPlot(pbmc4k, label = T) + NoLegend()
image.png

接下来,我们将映射好的pbmc4k和pbmc3k数据集合并到一起进行展示

pbmc7k <- merge(pbmc3k, pbmc4k)

pbmc7k[["umap"]] <- CreateDimReducObject(
  embeddings = rbind(pbmc3k[["umap"]]@cell.embeddings,
                     pbmc4k[["umap"]]@cell.embeddings),
  assay = "RNA", key = "UMAP_")

DimPlot(pbmc7k, label = T) + NoLegend()
image.png
pbmc7k$celltype <- Idents(pbmc7k)
Idents(pbmc7k) <- pbmc7k$orig.ident
DimPlot(pbmc7k)
image.png

可以看到,pbmc4k和参考数据集pbmc3k的细胞类型重叠的很好,不存在明显的批次效应。

将bulk转录组数据映射到参考数据集中

接下来,我们将使用projectLSI包将bulk转录组数据映射到单细胞参考数据集中。首先,我们将使用psudoSC函数将bulk转录组数据进行down-sampleing重取样构建psudo-single-cell数据。

# 设置n=100每个样本重取样100次
psudo.all <- psudoSC(bulk.data, n = 100, depth = 3000)
## downsampling counts...
## merging all samples...
dim(psudo.all)
## [1] 25498  2000

psudo.all[1:5,1:5]
#5 x 5 sparse Matrix of class "dgCMatrix"
#         CD4T_1_1 CD4T_1_2 CD4T_1_3 CD4T_1_4 CD4T_1_5
#A1BG            .        .        .        .        .
#A1BG-AS1        .        .        .        .        .
#A1CF            .        .        .        .        .
# 构建seurat对象
psudo.so <- CreateSeuratObject(psudo.all, project = "bulk")
# 数据标准化
psudo.so <- NormalizeData(psudo.so)
## Performing log-normalization
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
Idents(psudo.so) <- rep(c("CD4T.bulk", "CD8T.bulk", "NK.bulk", "B.bulk", "Mono.bulk"), rep(400, 5))
table(Idents(psudo.so))
#CD4T.bulk CD8T.bulk   NK.bulk    B.bulk Mono.bulk
#      400       400       400       400       400

# 使用projectLSI函数进行数据映射
bulk.matSVD <- projectLSI(psudo.so[["RNA"]]@data, pbmc3k.lsi)
head(bulk.matSVD)
#                PC_1        PC_2          PC_3          PC_4        PC_5
#CD4T_1_1 -0.03980147 -0.01410879 -0.0014396458  5.488960e-04 0.011402060
#CD4T_1_2 -0.04032496 -0.01581425  0.0003935543  1.469935e-03 0.009831236
#CD4T_1_3 -0.04006459 -0.01520021  0.0001330849  4.762865e-04 0.009996544

umap.bulk.proj <- uwot::umap_transform(bulk.matSVD[, 1:10], umap.pbmc3k, verbose = T)
## 13:16:17 Read 2000 rows and found 10 numeric columns
## 13:16:17 Processing block 1 of 1
## 13:16:17 Writing NN index file to temp file /tmp/RtmplGf1gl/file1a6a91b3753
## 13:16:17 Searching Annoy index using 8 threads, search_k = 3000
## 13:16:17 Commencing smooth kNN distance calibration using 8 threads
## 13:16:17 Initializing by weighted average of neighbor coordinates using 8 threads
## 13:16:17 Commencing optimization for 167 epochs, with 60000 positive edges
## 0%   10   20   30   40   50   60   70   80   90   100%
## [----|----|----|----|----|----|----|----|----|----|
## **************************************************|
## 13:16:18 Finished
rownames(umap.bulk.proj) <- colnames(psudo.so)
colnames(umap.bulk.proj) <- paste0("UMAP_", seq_len(ncol(umap.bulk.proj)))
psudo.so[["umap"]] <- CreateDimReducObject(
  embeddings = umap.bulk.proj,
  assay = "RNA",
  key = "UMAP_")

DimPlot(psudo.so, label = T)
image.png

接下来,我们将映射好的bulk转录组数据和pbmc3k参考数据集合并到一起进行展示

pbmc.mix <- merge(pbmc3k, psudo.so)

pbmc.mix[["umap"]] <- CreateDimReducObject(
  embeddings = rbind(pbmc3k[["umap"]]@cell.embeddings,
                     psudo.so[["umap"]]@cell.embeddings),
  assay = "RNA", key = "UMAP_")

DimPlot(pbmc.mix, label = T) + NoLegend()
image.png

可以看到,bulk转录数据与单细胞参考数据集的细胞类型可以很好的重叠在一起,虽然bulk转录组数据中的CD8 T细胞与单细胞数据中存在一定的偏差,但其他的细胞类型注释的很好。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容