单细胞分析做到轨迹推断这一步,装monocle3基本是绕不开的关。这个R包把聚类、UMAP降维、learn_graph轨迹构建、拟时分析都打包在一起,功能确实好用,但安装过程也是出了名的折腾——尤其放到服务器上时,缺系统库、R版本不匹配、Bioconductor版本对不上、编译到一半内存爆掉,各种问题都能冒出来。我在几台不同配置的服务器上都部署过,Ubuntu 22.04、24.04、CentOS 7.9都试过,踩过的坑基本能写一本小册子。这里就把我实际操作的完整流程整理出来,按照系统依赖、R环境、镜像配置、正式安装、报错排查、运行验证的顺序走,照做就行。适合三类人:需要在课题组服务器或云服务器上部署单细胞分析流程的分析人员,帮同门“救火”的生信工程师,以及刚入门Linux、对R包源码编译不熟的生物信息学新手。
1. 安装前先盘清楚三件事:R版本、Bioconductor版本、系统依赖
1.1 为什么monocle3在服务器上装起来比其他R包“暴躁”
monocle3本身不是那种install.packages("monocle3")就能秒装的纯R包。它的核心分析流程里,聚类用leidenAlg,轨迹推断依赖igraph和spdep,UMAP降维依赖RcppHNSW和uwot,差异表达和拟时检验依赖glmGamPoi,这些包有一个共性:全部包含需要本地编译的C/C++代码。你在Windows或者macOS的RStudio里装上就能用,是因为CRAN和Bioconductor把这些包预先编译成二进制再发出来;但到了服务器上,R安装源码包,编译器会现场把几十个包逐个编译一遍。这时候系统里缺哪个头文件、缺哪个动态库、gcc版本老不老,立刻变成红色报错。所以我每次在服务器上装monocle3,花在系统依赖上的时间永远比R包本身多。
还有一个容易被忽略的点:很多服务器的软件源里自带R包依赖库,但管理员默认不会装“-dev”或者“-devel”后缀的开发包。比如系统里可能已经有libgmp.so这个运行库,但缺gmp.h这个头文件,R包编译时照样会报错。这类问题在个人电脑上很少见,因为RStudio安装预编译包时根本不走本地编译;一上服务器,全部暴露。
1.2 R版本与Bioconductor版本匹配
先讲清楚版本对应关系。BiocManager::install()会根据当前R版本来匹配对应的Bioconductor版本,理论上不用你管。但服务器经常多个R并存,比如系统自带一个R 4.0,conda里又装了一个R 4.3,用户PATH指到哪个R,就直接决定了匹配哪个Bioconductor。这个不提前确认,后面会死得很惨。
安装前先跑这几行,把自己的环境打出来:
R --version | head -n 2 which R Rscript -e 'cat("R版本:", as.character(getRversion()), "\n")' Rscript -e 'if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager", repos = "https://mirrors.tuna.tsinghua.edu.cn/CRAN/"); cat("Bioc版本:", as.character(BiocManager::version()), "\n")'版本对应关系,直接看这张表:
| R版本 | 对应的Bioconductor版本 | 我的建议 |
|---|---|---|
| R 4.3.x | Bioc 3.18 | 推荐,monocle3 1.3.x 最稳 |
| R 4.4.x | Bioc 3.19 | 可用,部分依赖包新版本编译要求高 |
| R 4.5.x | Bioc 3.20 | 谨慎,源头包未必跟进最新快 |
我实测下来的结论是:服务器上别追新。monocle3新功能更新慢,它的基础依赖包却在不断升级,R和Bioc版本太新,反而会让monocle3某些老依赖(比如DDRTree、spdep)在新编译环境下出问题。后面第5章会专门讲这类报错。
1.3 摸清服务器家底:系统类型、权限、编译器
再往下走之前,先花一分钟确认服务器的基础情况:
cat /etc/os-release uname -m whoami sudo -n true 2>/dev/null && echo "有sudo权限" || echo "没有sudo权限" gcc --version | head -n 1 make --version | head -n 1 cmake --version | head -n 1不同情况下的选择逻辑我简单列一下:
- Debian/Ubuntu系:能sudo就用apt装依赖和R;不能sudo就走conda。
- CentOS/RHEL系:先配EPEL;CentOS 7自带gcc 4.8.5太老,强烈建议直接conda。
- aarch64架构(ARM服务器):不要指望apt里所有二进制包都齐,conda的linux-aarch64生态会好很多,优先conda。
还有一件事容易被忽略:搞清楚R到底是从哪里来的。which R的结果如果指向/usr/bin/R,多半是系统包管理器装的;如果指向~/miniconda3/envs/r43/bin/R,那就是conda环境里的R;如果指向/opt/R/4.3.3/bin/R,那是源码编译的。这三类R的library路径互不相同,装包时一定确认自己在哪个环境里,避免装完“人还在系统R里”的乌龙。
2. 系统级依赖库:80%安装失败都卡在这一步
2.1 先搞清楚每个系统库到底为谁服务
缺系统库不能“缺什么补什么”就完事,你得知道缺的东西是为哪个R包服务的。这张表是我在排障时反复对照的:
| 系统库/开发包 | 作用 | 对应R包(典型) |
|---|---|---|
| gmp / mpfr | GNU高精度整数和浮点运算 | Rmpfr、gmp,以及spdep相关数学计算 |
| udunits2 | 科学单位换算 | units、sf |
| gdal / geos / proj | 地理空间数据读写与计算 | sf、terra |
| cmake | 跨平台构建工具,编译C++时必备 | leidenAlg、RcppHNSW |
| fontconfig / freetype / fribidi / harfbuzz | 字体与文本布局渲染 | ggplot2、systemfonts、textshaping、ggwordcloud |
| curl / openssl / xml2 | 网络下载与XML解析 | curl、xml2、httr、BiocFileCache |
有的朋友会问,monocle3自己的文档里没提gdal,为什么我也装了?因为monocle3依赖spdep和leidenAlg,这两者又会牵扯到其他包,而单细胞分析的环境里经常还混着sf、units这些地理空间相关包。与其等某个包在装到一半才来问你要gdal,不如一开始就把这些基础底料备齐。尤其是ggwordcloud这个包,它在monocle3依赖树里不起眼,但编译时需要fontconfig和freetype,少一个就报错。
2.2 Debian/Ubuntu系服务器(22.04 / 24.04)
如果你的服务器是Ubuntu且能sudo,用apt一条龙装:
sudo apt update sudo apt install -y build-essential cmake libcurl4-openssl-dev libssl-dev libxml2-dev libgmp-dev libmpfr-dev libudunits2-dev libgdal-dev libgeos-dev libproj-dev libfontconfig1-dev libfreetype6-dev libfribidi-dev libharfbuzz-dev这条命令基本覆盖了后面可能踩到的所有系统依赖。Ubuntu 24.04的r-base软件包对应R 4.3.3,正好和我要推荐的版本合拍;Ubuntu 22.04的r-base是R 4.2.2,如果直接用apt装R,Bioc会匹配到3.16/3.17,也能装monocle3,但部分新依赖包的编译会麻烦一点。所以我建议22.04用户要么源码编译R 4.3.3,要么干脆用conda。系统库这一行命令不分R版本,都可以先装。
2.3 CentOS / RHEL 系服务器
CentOS 7.9还在用的不少,先给结论:系统包能装,但我更推荐conda,原因主要是gcc太老。命令如下:
sudo yum install -y epel-release sudo yum groupinstall -y "Development Tools" sudo yum install -y cmake gmp-devel mpfr-devel udunits2-devel gdal-devel geos-devel proj-devel openssl-devel libxml2-devel curl-devel fontconfig-devel freetype-devel fribidi-devel harfbuzz-devel需要强调一下:CentOS 7自带gcc是4.8.5,这个版本编译R 4.x或者一些新C++写的R包时,会直接报不识别-std=c++17之类。CentOS 7用户如果坚持用系统R,需要额外安装高版本gcc(比如scl的devtoolset-11);与其折腾这些,不如直接跳转到2.4节走conda方案,省下的时间足够你多跑一轮单细胞聚类。
2.4 没有root权限?用conda在用户目录补全整套依赖
这个方法适用于所有“无sudo”和“集群登录节点”场景,也是我给别人服务器“救火”时用得最多的方案。不需要系统管理员配合,所有东西都装在自己的home目录下:
conda create -n r43 -c conda-forge r-base=4.3.3 conda activate r43 conda install -c conda-forge gmp mpfr udunits2 gdal geos proj cmake make gxx_linux-64这里的gxx_linux-64是conda环境里的C++编译器,装R包时会优先被R使用,避免系统gcc和conda R之间ABI不一致。装完这些后,在conda环境里再执行R,然后正常装monocle3,pkg-config默认会去$CONDA_PREFIX/lib/pkgconfig找库,极大减少“configure找不到xx”的问题。如果你觉得conda默认源下载慢,可以给conda也配上国内镜像,或者先装mamba再用mamba创建环境,速度会快很多。权限受限的服务器上,这是我最推荐的路线。
3. R环境、镜像与编译参数:装包前把地基打牢
3.1 推荐的稳定组合:R 4.3.3 + Bioc 3.18 + monocle3 1.3.x
说了那么多系统变量,直接给一个我反复使用的“标准答案”:R 4.3.3、Bioconductor 3.18、monocle3 1.3.1。这三者搭配是我在Ubuntu 22.04、Ubuntu 24.04和conda环境下都验证过的,编译通过率高、加载稳定。如果服务器上还没有R,直接用conda建环境最省心;如果系统已经装好R但版本比较老(比如CentOS 7自带R 3.6),别指望在原基础上补,直接新建conda环境。
如果确实想用系统R源码编译升级,以Ubuntu为例可以这样:
sudo apt install -y libcurl4-openssl-dev libssl-dev libxml2-dev libreadline-dev libx11-dev libxt-dev wget https://cran.r-project.org/src/base/R-4/R-4.3.3.tar.gz tar xzf R-4.3.3.tar.gz cd R-4.3.3 ./configure --prefix=/opt/R/4.3.3 --enable-R-shlib --with-x=no make -j4 sudo make install export PATH=/opt/R/4.3.3/bin:$PATH编译时用--enable-R-shlib是因为有些流程需要用动态库方式调用R,加上这个选项后面会省很多麻烦。但源码编译R的坑也不少,时间和难度都不低,所以我个人更倾向conda。
3.2 把CRAN和Bioconductor镜像换成国内源
monocle3的依赖链有几十个包,每个都从官方源下载,在国内服务器上会非常慢,还容易超时。强烈建议先在R的配置文件中把镜像固定下来:
cat >> ~/.Rprofile << 'EOF' options(BioC_mirror = "https://mirrors.tuna.tsinghua.edu.cn/bioconductor") options(CRAN = "https://mirrors.tuna.tsinghua.edu.cn/CRAN/") options(Ncpus = 4) EOF然后新开R会话,或者source("~/.Rprofile")。如果清华源不稳定,可以换成中科大的https://mirrors.ustc.edu.cn/CRAN/和https://mirrors.ustc.edu.cn/bioconductor。注意不要两个镜像混着用,包和索引之间容易出现版本对不上的情况。Ncpus = 4表示R在安装依赖时最多同时编译4个源码包,能提速不少;内存特别小的服务器改成2甚至1更稳。
3.3 编译工具链与并发参数:防止把服务器跑死
镜像设置好之后,再检查一遍编译器:gcc --version、make --version、cmake --version。如果没有cmake,leidenAlg和RcppHNSW编译时会直接卡在“找不到cmake”这类错误上,所以我说系统依赖是地基,地基不牢后面全白搭。
服务器如果是多用户共用,装依赖包之前最好用free -h和htop看一眼内存余量,不要把别人的任务挤爆。R包源码编译本质上是把C++源码变成机器码,单包编译时内存占用就有1-2GB,如果同时并发编译4个包,8GB内存的机器很容易被压到临界点。所以小内存服务器一定要控制Ncpus的数值。编译期间也尽量别在同一台机器上跑高内存的单细胞数据处理任务,否则很容易出现第5章的“OOM被Killed”问题。
4. 正式安装monocle3:主流程与conda懒人路线
4.1 用BiocManager安装的完整命令
确认R和Bioc版本没问题、系统依赖装齐后,直接一条命令跑:
Rscript -e ' options(BioC_mirror = "https://mirrors.tuna.tsinghua.edu.cn/bioconductor") options(CRAN = "https://mirrors.tuna.tsinghua.edu.cn/CRAN/") if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager") BiocManager::install(version = "3.18", ask = FALSE, update = FALSE, checkBuilt = TRUE) BiocManager::install("monocle3", update = FALSE, ask = FALSE, Ncpus = 4) '这里有几个点必须说清楚:
- 如果当前R不是4.3,
BiocManager::install(version = "3.18")会直接报错,说明R版本不匹配,先切换R版本再执行。 - 第一次安装依赖包会比较多,网络好的情况下大概20到40分钟,网络慢或CPU弱可能要1到2小时。提前挂上tmux或screen再跑,防止SSH断开导致中断。
update = FALSE的意思是先不升级服务器上已有的其他R包,优先把monocle3及其缺失依赖装完。如果你后续用BiocManager::valid()检查,发现若干包版本偏旧,那是正常现象,不要手痒一次性全升,升完很可能把好不容易弄稳的环境又搞乱。
4.2 安装中断后的续装与已装包检查
SSH断连导致安装中断,在服务器上太常见了。重新跑上面同一段命令即可,R不会重复编译已完成的包,而是从断点继续装剩下那些。如果你想确认到底哪些包装好了:
Rscript -e 'ap <- rownames(installed.packages()); target <- c("monocle3","leidenAlg","spdep","glmGamPoi","uwot","RcppHNSW","DDRTree","RANN","pbmcapply"); print(setNames(target %in% ap, target))'输出全为TRUE,说明主要依赖已就位。如果某几个包一直装不上,先记下包名,到第5章按排查思路处理。
4.3 conda懒人路线:一条命令装完r-monocle3
前面反复说conda方案,其实还有更懒的:conda已经有人把monocle3打包好了,直接:
conda create -n monocle -c conda-forge -c bioconda r-monocle3实测下来大约10分钟能装完,所有系统依赖都由conda解决,非常适合“先跑通流程再说”的场景。代价是版本可能比Bioconductor官方发布的落后几个月甚至一年,而且conda-forge的依赖关系是固定好的,你想在conda环境里额外用BiocManager更新某个依赖包时,很可能破坏环境一致性。所以我的分工是:入门验证用conda懒人路线,生产复现用前面的BiocManager正式路线。
5. 我在服务器上踩过的五个编译坑:从现象到根因的完整排查链路
5.1 先学会定位“到底哪个包挂了”
满屏报错的时候,最忌讳复制一大段去群里问。先做两步。
第一步,拉到最后50行,找ERROR行。R安装依赖时,哪个包失败,结尾一定会有一行:
ERROR: compilation failed for package 'xxx'或者:
configure: error: ...(具体库名)第二步,拿到包名后单独重装这个包,不要整个流程重来:
Rscript -e 'BiocManager::install("xxx", update = FALSE, ask = FALSE)'如果重装后报错信息没变,再根据报错关键词(libgmp、udunits2、Killed、version等)定位是系统库、内存还是版本问题。这套顺序能省下一半排障时间。很多新手一看报错就以为monocle3本身坏了,其实绝大多数时候是它某个不起眼的依赖包出了问题。
5.2 案例一:configure: error: libgmp not found
现象:安装Rmpfr或gmp时,configure阶段就停下,提示找不到GMP库。
排查过程:先用ldconfig -p | grep gmp看系统有没有libgmp.so,再用ls /usr/lib/x86_64-linux-gnu/libgmp*找头文件。常见原因是只装了运行库没装开发包,也就是只有libgmp.so.10而没有libgmp.so这个软链和gmp.h。
解决方法:Ubuntu装libgmp-dev,CentOS装gmp-devel;如果本来就在conda里,就conda install -c conda-forge gmp mpfr,然后重新单独装对应R包。这个问题看起来小,但Rmpfr装不上,后面spdep相关计算就可能连带失败。
5.3 案例二:units/sf 装不上,cannot find -ludunits2
现象:安装units包时报cannot find -ludunits2,或者找不到udunits2.h头文件。
原因:units/sf在编译时要链接UNIDATA单位的C库,系统上没有udunits2的开发包。
解决方法:Ubuntu用libudunits2-dev;CentOS需要先装EPEL,再yum install udunits2-devel。CentOS源里如果还是没有,最后办法是conda install -c conda-forge udunits2,然后确保R的编译环境能找到它。还有一个细节:用conda装完后,如果R包还是找不到库,在同一个conda环境里手动把路径喂给编译器:
export PKG_CONFIG_PATH=$CONDA_PREFIX/lib/pkgconfig export CPATH=$CONDA_PREFIX/include export LIBRARY_PATH=$CONDA_PREFIX/lib再重新装units。这个方法对付“库明明在,但configure就是找不到”的情况特别有效。
5.4 案例三:编译到一半进程被Killed,日志没有具体编译器错误
现象:R CMD INSTALL跑了几分钟,终端几乎是直接被Killed干掉,往上翻也看不到gcc报错。
排查:这种十有八九是内存不够被系统OOM杀了。执行dmesg | tail -n 30,如果看到Out of memory: Kill process或Killed process,基本实锤。
解决:
- 降低并发:不用
Ncpus=4,改成Ncpus=1; - 同时把MAKEFLAGS设成
-j1,避免单个包内部多线程编译爆炸:export MAKEFLAGS="-j1"; - 再不行就加swap,或者换到内存更大的节点;
- 如果服务器上同时跑着其他单细胞分析任务,尽量错峰编译,编译峰值内存很容易和比对任务撞车。
不要硬扛,该找管理员要资源就要。
5.5 案例四:Bioconductor版本或R版本不满足依赖要求
现象一:安装时提示dependencies 'xxx' are not available for package 'monocle3',但你明明已经装了xxx。这种情况往往是xxx包版本太旧,或者安装在另一个R库路径里。检查当前library路径:Rscript -e 'print(.libPaths())',确保在conda环境里用的是conda的R库,不要和系统R库混在一起。
现象二:报错This package requires R (>= 4.x) but your R is 3.6。这个比较直观:monocle3新版要求R高版本,别想办法降级monocle3或依赖包,直接把R升到4.3。升级R会引入“之前装的一堆包要重装”的成本,但这类成本对单细胞分析环境来说是一次性的,别怕麻烦。
5.6 案例五:加载时报“package 'spdep' was built under R version 4.3.0”
现象:library(monocle3)能过,但随后加载某个依赖包时,提示package 'spdep' was built under R version 4.3.0,甚至直接Error。
原因:混用R版本。比如spdep装的时候用的是conda R,现在你换到系统R去加载;或者不同用户把包装到了不同的库路径,而当前R恰好读到了不兼容的那一份。
解决:统一一个R版本、一套library路径。最省事的操作是删掉这些依赖包,在当前R版本下重装一遍:
Rscript -e 'remove.packages(c("spdep","leidenAlg","monocle3"))' Rscript -e 'BiocManager::install("monocle3", update = FALSE, ask = FALSE)'多用户服务器上,建议把共享软件装在公共路径并设置R_LIBS_SITE环境变量,而不是各装各的,否则这种“版本漂移”会反复出现。
6. 装完别急着跑大任务:加载验证、最小流程与运行期排障
6.1 加载验证与依赖完整性检查
装完先加载,确认不是“安装成功但加载失败”:
Rscript -e 'library(monocle3); cat("monocle3版本:", as.character(packageVersion("monocle3")), "\n")'如果正常输出版本号,说明依赖树的绝大部分都正常。再检查几个容易出问题的底层包:
Rscript -e 'pks <- c("leidenAlg","spdep","glmGamPoi","uwot","RcppHNSW","DDRTree","RANN","pbmcapply","ggplot2"); print(setNames(sapply(pks, requireNamespace, quietly=TRUE), pks))'全为TRUE就可以放心进入下一步。
6.2 一个极简可跑的验证脚本
用模拟数据把monocle3主线流程走一遍:
library(monocle3) set.seed(1) counts <- matrix(rpois(30 * 50, lambda = 4), nrow = 30) # 30个基因 x 50个细胞 colnames(counts) <- paste0("cell_", 1:50) rownames(counts) <- paste0("gene_", 1:30) cell_meta <- data.frame(row.names = colnames(counts), sample = rep(c("A", "B"), length.out = 50)) gene_meta <- data.frame(row.names = rownames(counts), gene_short_name = rownames(counts)) cds <- new_cell_data_set(counts, cell_metadata = cell_meta, gene_metadata = gene_meta) cds <- preprocess_cds(cds, num_dim = 5) cds <- reduce_dimension(cds, preprocess_method = "PCA") cds <- cluster_cells(cds) cds <- learn_graph(cds) print(cds)如果脚本顺利跑完并打印出cell_data_set对象,说明从预处理、降维、聚类到轨迹图构建的主链路都正常。这个脚本故意把数据量做得很小,几十秒内能出结果,很适合用来区分“包坏了”和“我数据/流程写错了”。
6.3 运行期常见报错:UMAP、顺序问题、内存
运行期最容易被误导的坑:如果你装的monocle3是较早的版本(常见于1.0之前的遗留安装),reduce_dimension(cds)会通过reticulate去调Python的umap-learn,此时服务器上没有可用Python环境就会报类似Unable to import umap的错误。这时候要么给服务器装一个Python环境并pip install umap-learn,要么把monocle3升级到新版本,1.3.x在R侧通过uwot完成UMAP,不再强制依赖Python。怎么分辨?报错里如果包含reticulate、module、import这类关键词,基本就是这个原因。
第二个常见报错是调用顺序不对,比如还没preprocess_cds就cluster_cells,或者没reduce_dimension就learn_graph。monocle3的流程顺序是固定的:preprocess_cds→reduce_dimension→cluster_cells→learn_graph→ 再推断拟时,乱序会提示找不到对象。
第三个问题是内存。真实单细胞数据动辄几万细胞,全部塞进内存跑排序和UMAP非常吃资源。常规建议是先在数据导入阶段过滤掉低质量细胞,再对感兴趣的细胞亚群单独构建cds做轨迹分析,减少无效计算。如果确实需要全量跑,使用内存更大的节点,或者设置合理的R对象大小限制,否则炸内存不是第一次也不会是最后一次。
6.4 服务器上的长任务运行纪律
单细胞分析不是一次交互式R会话能跑完的,我的运行习惯是:
- 用tmux开一个长会话,SSH断了任务还在;
- 把分析脚本写成Rscript文件,
nohup Rscript run_monocle.R > run.log 2>&1 &后台运行; - 看到结果后先看run.log的尾部,确认有没有Error;
- 设置环境变量如
OPENBLAS_NUM_THREADS控制底层矩阵计算的线程数,避免把所有核占满。
这些习惯能减少很多“跑了一晚上,结果早上发现第二个小时就挂了”的遗憾。
最后分享一个我自己的习惯:每成功部署一次monocle3,我都会把R版本、Bioconductor版本、系统依赖包列表、镜像设置、安装命令存成一个environment.md,或者写成Dockerfile。因为单细胞分析最怕的就是环境不一致,半年后要重部署时,有一份记录,半小时就能复现;没有记录,又是一下午的排障。装包这事,真正决定成败的往往不是R包本身,而是你有没有把系统依赖和处理网络节奏仔细想清楚。希望这篇教程能帮你少踩几个坑,顺利把monocle3跑在服务器上。