3、环境搭建:安装 Scanpy 并加载示例数据集(pbmc3k)

好,咱们正式迈入实战环节。第一步就是把环境配好。做单细胞分析,环境配置往往是新手最早碰壁的地方。我个人习惯用 conda 管理虚拟环境,因为包依赖实在太容易打架了——尤其当你同时装了 tensorflow 和 pytorch 的时候,那叫一个酸爽。你想想看,Scanpy 底层的核心依赖是 anndata、numpy、pandas 这些,版本不对直接报错。所以别嫌我啰嗦,先把环境搭稳,后面才能顺畅。

3.1 创建干净的环境

我不建议直接在 base 环境里装。为什么?因为 base 环境通常已经被你装了一堆乱七八糟的包了,依赖冲突概率高。我建议新建一个环境,比如叫 scanpy_env,Python 版本用 3.9 或 3.10 都行,Scanpy 目前对这两个版本支持最好。

conda create -n scanpy_env python=3.9 -y
conda activate scanpy_env

这里 -y 是自动确认,省得每次手动打 y。嗯,小技巧。环境激活后,命令行开头会出现 (scanpy_env),说明你已经在虚拟环境里了。

💡 提示:如果你机器上没装 conda,建议直接装 Miniconda,轻量级,够用。别装 Anaconda,太大,里面很多包你根本用不上。

3.2 安装 Scanpy 及核心依赖

安装 Scanpy 最简单的方式就是用 pip。但需要注意,Scanpy 在 PyPI 上的版本和 conda-forge 上的版本有时会差几个小版本。我推荐先用 conda 装,因为 conda 能自动帮你处理底层二进制依赖(比如 h5py、blas),省心。

方式一:conda 安装(推荐)

conda install -c conda-forge scanpy python-igraph leidenalg -y

这里我顺手装了两个额外包:python-igraph 和 leidenalg。它们是用来跑社区检测(比如 Louvain、Leiden 聚类)的底层库。不装的话也能跑,但会慢很多。我之前在一个 10 万细胞的 dataset 上因为没装 leidenalg,跑聚类跑了 20 分钟还没出结果……加上之后 2 分钟就搞定了。

方式二:pip 安装

如果你喜欢用 pip,也可以这样:

pip install scanpy[leiden]

[leiden] 是个可选依赖标签,它会把 leidenalg 和 python-igraph 一并装上。注意,pip 安装前最好先把 numpy 和 cython 升到最新版,否则容易编译报错。

安装方式优点缺点
conda (conda-forge)依赖自动解决,二进制包稳定库更新较慢,少数包没有 conda 版本
pip (PyPI)版本最新,生态广有时需要手动装编译工具
⚠️ 注意:千万不要同时用 conda 和 pip 混装同一个包的不同分支,否则环境会变成“脏环境”,后面 import 时可能报一些奇奇怪怪的 AttributeError。我曾经因为这个折腾了一个下午,最后只能删掉整个环境从头来。

3.3 验证安装

装完之后,咱们快速验证一下。在终端输入:

python -c "import scanpy as sc; print(sc.__version__)"

如果输出版本号(比如 1.9.8 或 1.10.0),那说明安装成功。如果报错说找不到模块,那就检查一下是否激活了正确的环境,或者 pip list 看看有没有 scanpy。

3.4 加载示例数据集(pbmc3k)

好了,环境搭好了,现在咱们用它来加载一个经典数据集:pbmc3k。这是 10x Genomics 公开的 2700 个 PBMC 单细胞测序数据,经过标准化预处理后打包在 Scanpy 里面,拿来做入门练习再合适不过了。

加载代码很简单:

import scanpy as sc
adata = sc.datasets.pbmc3k()

如果网络没问题,它会自动从 remote 下载到本地缓存目录(~/.cache/scanpy/)。数据大概 30MB,网速好的话几秒就下完了。我第一次跑的时候公司网络特别慢,等了快两分钟才下好,真的急死人……后来我学乖了,提前把常用数据集下载好,放到内网共享盘,省得每次都要等。

下载完后,咱们来看看 adata 长什么样:

print(adata)

输出类似这样:

AnnData object with n_obs × n_vars = 2700 × 32738
    var: 'gene_ids'
    obs: 'n_genes', 'n_genes_by_counts', 'total_counts', 'total_counts_mt', 'pct_counts_mt'

看到没?一个标准的 AnnData 对象,2700 个细胞(行),32738 个基因(列)。obs 里已经有了一些 QC 指标,比如每个细胞检测到的基因数、总 UMI 计数、线粒体占比等。这些都是自动预计算好的,咱们后面可以直接用。

🔑 关键理解:AnnData 是 Scanpy 的核心数据结构,它把表达矩阵(X)、观测信息(obs)、特征信息(var)以及非结构化数据(uns)整合在一个对象里。你之后所有的操作——过滤、归一化、降维、聚类——都会围绕这个 adata 展开。

3.5 初步探索数据

加载完后,我习惯先看一眼表达矩阵的分布。调用 sc.pl.highest_expr_genes() 可以快速看到哪些基因表达量最高:

sc.pl.highest_expr_genes(adata, n_top=20)

这会弹出一个条形图,显示在全部细胞中平均表达量最高的 20 个基因。你可能会看到 MALAT1、B2M、EEF1A1 等管家基因排在最前面,这是正常的。

如果你想了解数据的基本统计量,也可以直接看 adata.obs 的摘要:

print(adata.obs.describe())

它会给出每个 obs 列的最小值、最大值、均值等。我一般会注意 n_genes 的最小值和最大值——如果某个细胞只检测到几十个基因,那大概率是空液滴或者死细胞,后续该过滤掉。

3.6 常见错误与解决

接下来我把部署过程中经常踩的坑列出来,省得你绕路。

  • ModuleNotFoundError: No module named 'igraph' —— 没装 python-igraph。装一下:conda install python-igraph -c conda-forge 或 pip install python-igraph。
  • ImportError: cannot import name 'leiden' from 'scanpy.tl' —— 没装 leidenalg。装一下:pip install leidenalg。注意,leidenalg 底层依赖 C++,Windows 上有时需要预编译 wheel,建议用 conda 装。
  • OSError: [Errno 28] No space left on device —— 下载缓存把磁盘塞满了。去 ~/.cache/scanpy/ 里删掉不需要的 h5ad 文件,或者设置环境变量 SCANPY_CACHE_DIR 指向一个大盘。
  • ValueError: Found array with 0 sample(s) —— 数据加载时网络断连导致文件不完整。删掉缓存文件重新下载:
import scanpy as sc, os, shutil
cache_dir = sc.settings.cachedir
shutil.rmtree(cache_dir, ignore_errors=True)
adata = sc.datasets.pbmc3k()
⚠️ 注意:删除整个缓存目录会清掉所有已下载的数据集,如果你有其他项目依赖之前的缓存,建议只删 pbmc3k 对应的文件(在 cache_dir 下找 pbmc3k.h5ad 或类似名称)。

整体流程示意

下面我用一张图把环境搭建到数据加载的整个脉络画出来,你跟着走就不会迷路。

环境搭建 → 数据加载 一体化流程图 创建 conda 环境 安装 Scanpy + 依赖 验证 import scanpy 加载 pbmc3k 数据集 print(adata) 初步探索 💡 注意事项: · 激活环境后再安装 · 不要混用 conda / pip · 缓存路径可设置

3.7 小总结:环境搭建的核心理念

说白了,环境搭建就是三件事:隔离、装核心、验证。隔离用 conda,核心装 scanpy+leiden,验证用 import 测试。后面的所有实战都得依赖这一步。嗯,我通常会在每个项目开始前都跑一遍 conda list 确认版本,省得半路发现依赖不对。你养成这个习惯后,会发现踩坑概率直线下降。