Python 生信学习路线¶
面向2026届生信工程师面试 | 从零基础到项目实战
为什么生信要学 Python?(白话版)¶
Python 就像生信领域的"瑞士军刀"——数据清洗、流程自动化、机器学习、序列分析,啥都能干。2025-2026年的趋势是:Python 在新项目中的使用率已经超过 R,尤其在自动化流程和 AI/ML 方向。
一句话总结:R 擅长统计和可视化,Python 擅长"把所有东西串起来"。两个都要会,但 Python 是你的主力编程语言。
阶段一:Python 基础语法(2-3周)¶
目标:能写脚本处理文本文件,不依赖 IDE 的自动补全也能写
1.1 必学语法清单¶
# === 变量和数据类型 ===
gene_name = "BRCA1" # 字符串:基因名
gene_length = 81189 # 整数:基因长度(碱基对)
gc_content = 0.423 # 浮点数:GC含量
is_coding = True # 布尔值:是否编码蛋白
# === 列表(最常用的数据结构)===
samples = ["WT_1", "WT_2", "KO_1", "KO_2"] # 样本列表
expression = [12.3, 15.6, 3.2, 2.8] # 表达量列表
# 列表推导式(生信中超常用,一行代替 for 循环)
# 白话:从 expression 里挑出大于 10 的值
high_expr = [x for x in expression if x > 10] # 结果:[12.3, 15.6]
# === 字典(存储键值对,像查字典一样查数据)===
gene_info = {
"name": "BRCA1", # 基因名
"chr": "chr17", # 染色体位置
"length": 81189, # 长度
"function": "DNA repair" # 功能
}
print(gene_info["chr"]) # 输出:chr17
# === 函数(把重复的操作封装起来)===
def calc_gc_content(sequence):
"""计算DNA序列的GC含量"""
sequence = sequence.upper() # 统一转大写
gc_count = sequence.count("G") + sequence.count("C") # 数G和C的个数
return gc_count / len(sequence) # GC个数除以总长度
# 使用函数
seq = "ATCGATCGGGCC"
print(f"GC含量: {calc_gc_content(seq):.2%}") # 输出:GC含量: 58.33%
1.2 文件读写(生信天天用)¶
# === 读取 FASTA 文件(最基础的序列文件格式)===
def read_fasta(filepath):
"""读取FASTA文件,返回 {序列名: 序列} 的字典"""
sequences = {} # 空字典,准备存结果
current_name = "" # 当前序列名
current_seq = [] # 当前序列的片段列表
with open(filepath, "r") as f: # 打开文件
for line in f: # 逐行读取
line = line.strip() # 去掉行尾换行符
if line.startswith(">"): # 以 > 开头 = 序列名行
if current_name: # 如果之前有序列,先存起来
sequences[current_name] = "".join(current_seq)
current_name = line[1:] # 去掉 > 号,取序列名
current_seq = [] # 重置序列片段
else:
current_seq.append(line) # 拼接序列片段
if current_name: # 存最后一条序列
sequences[current_name] = "".join(current_seq)
return sequences
# === 读取 TSV/CSV 表格(基因表达矩阵等)===
# 方法1:纯 Python(不依赖第三方库)
with open("gene_counts.tsv", "r") as f:
header = f.readline().strip().split("\t") # 读表头
for line in f: # 逐行读数据
fields = line.strip().split("\t") # 按tab分割
gene = fields[0] # 第一列是基因名
counts = [int(x) for x in fields[1:]] # 后面的列是计数
1.3 推荐学习资源¶
| 资源 | 特点 | 链接 |
|---|---|---|
| Python for Biologists | 专为生物学背景写的入门书 | pythonforbiologists.com |
| Rosalind 刷题 | 用编程题学生信,边做边学 | rosalind.info |
| Biology Meets Programming | Coursera课程,可免费旁听 | coursera.org |
| Software Carpentry Python | 科研人员专属Python教程 | software-carpentry.org |
阶段二:数据分析三件套 pandas + numpy + matplotlib(3-4周)¶
目标:能用 pandas 处理基因表达矩阵,画基本的图
2.1 NumPy —— 数值计算的基石¶
import numpy as np # 导入numpy,约定俗成缩写为np
# === 创建数组(比列表快100倍的数值容器)===
expr_matrix = np.array([
[12.3, 15.6, 3.2, 2.8], # 基因1在4个样本的表达量
[45.1, 42.3, 44.8, 43.9], # 基因2
[0.5, 0.3, 28.7, 31.2], # 基因3
])
# === 常用操作 ===
print(expr_matrix.shape) # 查看矩阵大小:(3, 4) = 3个基因x4个样本
print(expr_matrix.mean(axis=1)) # 每个基因的平均表达量(axis=1 按行算)
print(expr_matrix.mean(axis=0)) # 每个样本的平均表达量(axis=0 按列算)
# log2转换(基因表达分析的标准操作)
log2_expr = np.log2(expr_matrix + 1) # +1 是为了避免 log2(0) 报错
# 标准化(Z-score,让不同基因可以比较)
mean_per_gene = expr_matrix.mean(axis=1, keepdims=True) # 每基因均值
std_per_gene = expr_matrix.std(axis=1, keepdims=True) # 每基因标准差
z_scores = (expr_matrix - mean_per_gene) / std_per_gene # Z-score标准化
2.2 Pandas —— 表格数据处理神器¶
import pandas as pd # 导入pandas,约定俗成缩写为pd
# === 读取基因表达矩阵 ===
# 假设文件格式:第一列基因名,后面是各样本的表达量
df = pd.read_csv("gene_expression.tsv", sep="\t", index_col=0)
# sep="\t" 表示tab分隔
# index_col=0 表示第一列作为行名(基因名)
# === 基本查看 ===
print(df.shape) # 多少基因 x 多少样本
print(df.head()) # 看前5行
print(df.describe()) # 基本统计:均值、标准差、最大最小等
# === 数据筛选(面试高频)===
# 筛选表达量大于10的基因(所有样本的均值 > 10)
high_expr_genes = df[df.mean(axis=1) > 10] # axis=1 按行(每个基因)算均值
# 筛选特定样本
wt_samples = df[["WT_1", "WT_2"]] # 只取WT组的列
ko_samples = df[["KO_1", "KO_2"]] # 只取KO组的列
# === 计算差异倍数(Fold Change)===
wt_mean = df[["WT_1", "WT_2"]].mean(axis=1) # WT组均值
ko_mean = df[["KO_1", "KO_2"]].mean(axis=1) # KO组均值
log2fc = np.log2(ko_mean / wt_mean) # log2 Fold Change
# === 合并数据 ===
# 把基因注释信息和表达矩阵合并
annotation = pd.read_csv("gene_annotation.tsv", sep="\t") # 读注释文件
merged = df.merge(annotation, left_index=True, right_on="gene_id") # 按基因ID合并
# === 分组统计 ===
# 按染色体分组,统计每条染色体有多少基因
gene_per_chr = annotation.groupby("chromosome").size() # 按chromosome列分组计数
2.3 Matplotlib + Seaborn —— 画图¶
import matplotlib.pyplot as plt # 画图基础库
import seaborn as sns # 更好看的统计图库
# === 火山图(Volcano Plot,差异分析必画)===
fig, ax = plt.subplots(figsize=(8, 6)) # 创建画布,8x6英寸
ax.scatter(
log2fc, # x轴:log2 Fold Change
-np.log10(pvalues), # y轴:-log10(p-value)
c=["red" if abs(fc) > 1 and p < 0.05 else "gray" # 显著的标红
for fc, p in zip(log2fc, pvalues)],
alpha=0.5, # 透明度
s=5 # 点的大小
)
ax.set_xlabel("log2 Fold Change") # x轴标签
ax.set_ylabel("-log10(P-value)") # y轴标签
ax.axhline(-np.log10(0.05), ls="--", color="gray") # p=0.05的阈值线
ax.axvline(-1, ls="--", color="gray") # FC=-2的阈值线
ax.axvline(1, ls="--", color="gray") # FC=2的阈值线
plt.tight_layout() # 自动调整布局
plt.savefig("volcano_plot.pdf", dpi=300) # 保存为PDF,300dpi
plt.close() # 关闭画布释放内存
# === 热图(Heatmap,聚类分析必画)===
sns.clustermap(
df.head(50), # 取前50个基因画
cmap="RdBu_r", # 红蓝配色(经典)
z_score=0, # 按行做Z-score标准化
figsize=(10, 12), # 图片大小
method="ward", # 聚类方法
metric="euclidean" # 距离度量
)
plt.savefig("heatmap.pdf", dpi=300)
plt.close()
# === 箱线图(比较分组差异)===
fig, ax = plt.subplots(figsize=(6, 4))
data = pd.DataFrame({
"Expression": list(wt_mean) + list(ko_mean), # 合并两组数据
"Group": ["WT"]*len(wt_mean) + ["KO"]*len(ko_mean) # 分组标签
})
sns.boxplot(data=data, x="Group", y="Expression", ax=ax)
ax.set_title("Gene Expression Comparison")
plt.tight_layout()
plt.savefig("boxplot.pdf", dpi=300)
plt.close()
阶段三:Biopython + pysam 序列处理(2-3周)¶
目标:能用 Python 处理 FASTA/FASTQ/BAM 等生信格式文件
3.1 Biopython —— 生信专用工具箱¶
from Bio import SeqIO # 序列文件读写模块
from Bio.Seq import Seq # 序列对象
from Bio import Entrez # NCBI数据库查询
# === 序列基本操作 ===
dna = Seq("ATGCGATCGATCG") # 创建DNA序列对象
print(dna.complement()) # 互补链:TACGCTAGCTAGC
print(dna.reverse_complement()) # 反向互补链
print(dna.transcribe()) # 转录为RNA:AUGCGAUCGAUCG
print(dna.translate()) # 翻译为蛋白质
# === 读取 FASTA 文件(比自己写的版本更专业)===
for record in SeqIO.parse("genes.fasta", "fasta"): # 逐条读取
print(f"ID: {record.id}") # 序列ID
print(f"长度: {len(record.seq)}") # 序列长度
print(f"描述: {record.description}") # 描述信息
gc = (record.seq.count("G") + record.seq.count("C")) / len(record.seq)
print(f"GC含量: {gc:.2%}") # GC含量
# === 读取 FASTQ 文件(测序原始数据)===
quality_scores = []
for record in SeqIO.parse("reads.fastq", "fastq"):
quals = record.letter_annotations["phred_quality"] # 质量分数列表
avg_qual = sum(quals) / len(quals) # 平均质量
quality_scores.append(avg_qual)
print(f"平均质量分数: {sum(quality_scores)/len(quality_scores):.1f}")
# === 查询 NCBI 数据库 ===
Entrez.email = "your@email.com" # NCBI要求提供邮箱
handle = Entrez.efetch(
db="nucleotide", # 查核酸数据库
id="NM_007294", # BRCA1的RefSeq ID
rettype="fasta", # 返回FASTA格式
retmode="text" # 文本模式
)
record = SeqIO.read(handle, "fasta") # 读取结果
print(f"BRCA1序列长度: {len(record.seq)}")
handle.close()
3.2 pysam —— 处理 BAM/SAM 比对文件¶
import pysam # 处理BAM/SAM/VCF等文件的库
# === 读取 BAM 文件 ===
bamfile = pysam.AlignmentFile("sample.bam", "rb") # rb = read binary(二进制读取)
# 统计比对到 chr17 区域的 reads
count = 0
for read in bamfile.fetch("chr17", 41196312, 41277500): # BRCA1区域
if not read.is_unmapped: # 排除未比对的reads
if read.mapping_quality >= 20: # 只要比对质量>=20的
count += 1
print(f"BRCA1区域的高质量reads数: {count}")
# === 统计比对率 ===
stats = pysam.idxstats(bamfile.filename.decode()) # 获取索引统计
total_mapped = 0 # 总比对reads数
total_unmapped = 0 # 总未比对reads数
for line in stats.strip().split("\n"):
fields = line.split("\t")
total_mapped += int(fields[2]) # 第3列:比对数
total_unmapped += int(fields[3]) # 第4列:未比对数
mapping_rate = total_mapped / (total_mapped + total_unmapped)
print(f"比对率: {mapping_rate:.2%}")
bamfile.close() # 用完要关闭
# === 读取 VCF 文件(变异信息)===
vcf = pysam.VariantFile("variants.vcf.gz") # 读取VCF文件
for record in vcf:
chrom = record.chrom # 染色体
pos = record.pos # 位置
ref = record.ref # 参考碱基
alt = record.alts[0] # 突变碱基
qual = record.qual # 质量分数
print(f"{chrom}:{pos} {ref}>{alt} (QUAL={qual})")
阶段四:机器学习 scikit-learn + 深度学习 PyTorch(3-4周)¶
目标:能用 ML 做生信分类/回归任务,面试能讲清楚原理
4.1 scikit-learn —— 经典机器学习¶
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split, cross_val_score # 数据分割和交叉验证
from sklearn.preprocessing import StandardScaler # 标准化
from sklearn.ensemble import RandomForestClassifier # 随机森林
from sklearn.metrics import (
classification_report, # 分类报告
roc_auc_score, # AUC分数
confusion_matrix # 混淆矩阵
)
# === 加载数据(以疾病分类为例)===
df = pd.read_csv("microbiome_features.tsv", sep="\t") # 微生物组特征
X = df.drop(columns=["sample_id", "group"]) # 特征矩阵(去掉ID和标签列)
y = df["group"] # 标签:T2D=1, Control=0
# === 数据分割 ===
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.2, # 20%作为测试集
random_state=42, # 随机种子(保证可重复)
stratify=y # 分层抽样(保证正负样本比例一致)
)
# === 标准化(让所有特征在同一数量级)===
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train) # 在训练集上拟合+转换
X_test_scaled = scaler.transform(X_test) # 在测试集上只转换(不能再fit!)
# === 训练随机森林 ===
rf = RandomForestClassifier(
n_estimators=100, # 100棵树
max_depth=10, # 最大深度10
random_state=42, # 随机种子
n_jobs=-1 # 用所有CPU核心
)
rf.fit(X_train_scaled, y_train) # 训练模型
# === 评估 ===
y_pred = rf.predict(X_test_scaled) # 预测
y_prob = rf.predict_proba(X_test_scaled)[:, 1] # 预测概率(取正类概率)
print(classification_report(y_test, y_pred)) # 精确率、召回率、F1
print(f"AUC: {roc_auc_score(y_test, y_prob):.3f}") # AUC分数
# === 交叉验证(更靠谱的评估方式)===
cv_scores = cross_val_score(rf, X_train_scaled, y_train, cv=5, scoring="roc_auc")
print(f"5折交叉验证 AUC: {cv_scores.mean():.3f} ± {cv_scores.std():.3f}")
# === 特征重要性(面试爱问)===
feature_importance = pd.Series(
rf.feature_importances_, # 每个特征的重要性分数
index=X.columns # 特征名
).sort_values(ascending=False)
print("Top 10 重要特征:")
print(feature_importance.head(10))
4.2 PyTorch —— 深度学习入门¶
import torch # PyTorch核心
import torch.nn as nn # 神经网络模块
from torch.utils.data import DataLoader, TensorDataset # 数据加载
# === 定义简单的分类网络 ===
class BioClassifier(nn.Module):
"""生信数据分类器:3层全连接网络"""
def __init__(self, input_dim):
super().__init__()
self.net = nn.Sequential(
nn.Linear(input_dim, 128), # 输入层 -> 128个神经元
nn.ReLU(), # 激活函数(给网络加非线性能力)
nn.Dropout(0.3), # 随机关闭30%的神经元(防过拟合)
nn.Linear(128, 64), # 128 -> 64
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(64, 1), # 64 -> 1(二分类输出)
nn.Sigmoid() # 压缩到0-1之间(概率)
)
def forward(self, x):
return self.net(x) # 前向传播
# === 准备数据 ===
X_tensor = torch.FloatTensor(X_train_scaled) # numpy转pytorch张量
y_tensor = torch.FloatTensor(y_train.values).unsqueeze(1) # 标签也转张量
dataset = TensorDataset(X_tensor, y_tensor) # 组合为数据集
loader = DataLoader(dataset, batch_size=32, shuffle=True) # 批量加载器
# === 训练 ===
model = BioClassifier(X_train_scaled.shape[1]) # 实例化模型
criterion = nn.BCELoss() # 二分类交叉熵损失
optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # Adam优化器
for epoch in range(50): # 训练50轮
model.train() # 训练模式
total_loss = 0
for batch_X, batch_y in loader: # 每批32个样本
pred = model(batch_X) # 前向传播
loss = criterion(pred, batch_y) # 计算损失
optimizer.zero_grad() # 清空梯度
loss.backward() # 反向传播
optimizer.step() # 更新参数
total_loss += loss.item()
if (epoch + 1) % 10 == 0: # 每10轮打印一次
print(f"Epoch {epoch+1}, Loss: {total_loss/len(loader):.4f}")
阶段五:项目实战与流程自动化(持续)¶
5.1 用 Snakemake 写分析流程(Python语法的流程管理器)¶
# Snakefile(Snakemake的流程定义文件,用Python语法写)
# 定义所有样本名
SAMPLES = ["WT_1", "WT_2", "KO_1", "KO_2"]
# 最终目标:生成多样本质控报告
rule all:
input:
"results/multiqc_report.html" # 最终要生成的文件
# 步骤1:质控
rule fastqc:
input:
"data/{sample}.fastq.gz" # 输入:原始测序数据
output:
"results/fastqc/{sample}_fastqc.html" # 输出:质控报告
shell:
"fastqc {input} -o results/fastqc/" # 运行fastqc命令
# 步骤2:汇总质控报告
rule multiqc:
input:
expand("results/fastqc/{sample}_fastqc.html", sample=SAMPLES) # 所有样本的质控
output:
"results/multiqc_report.html"
shell:
"multiqc results/fastqc/ -o results/"
5.2 常用 Python 生信库一览¶
| 库名 | 用途 | 安装命令 |
|---|---|---|
| Biopython | 序列处理、NCBI查询 | pip install biopython |
| pysam | BAM/VCF文件处理 | conda install -c bioconda pysam |
| pandas | 表格数据处理 | pip install pandas |
| numpy | 数值计算 | pip install numpy |
| scikit-learn | 经典机器学习 | pip install scikit-learn |
| PyTorch | 深度学习 | pip install torch |
| scanpy | 单细胞分析 | pip install scanpy |
| matplotlib/seaborn | 数据可视化 | pip install matplotlib seaborn |
| HTSeq | 高通量测序数据处理 | pip install HTSeq |
| pyGenomeTracks | 基因组区域可视化 | pip install pyGenomeTracks |
面试速查表¶
Python 基础高频问题¶
| 问题 | 答案要点 |
|---|---|
| 列表和元组的区别? | 列表可变(mutable),元组不可变(immutable);元组可做字典的key |
| 深拷贝和浅拷贝? | 浅拷贝共享内部对象引用,深拷贝完全独立(用copy.deepcopy) |
| 列表推导式的好处? | 比for循环快、代码更简洁、一行搞定筛选+转换 |
| with语句的作用? | 自动管理资源(文件读写完自动关闭,不怕忘close) |
| lambda函数? | 匿名函数,一行定义简单函数:lambda x: x*2 |
生信 Python 高频问题¶
| 问题 | 答案要点 |
|---|---|
| 为什么用pandas而不是Excel? | 能处理百万行数据、可编程自动化、可重复 |
| log2转换为什么加1? | 避免log2(0)=-inf,叫做pseudocount |
| 标准化fit和transform分开的原因? | 防止数据泄露:测试集不能影响训练集的统计量 |
| 随机森林的random_state是什么? | 随机种子,保证每次运行结果一样(可重复性) |
| stratify分层抽样为什么重要? | 保证训练集和测试集中正负样本比例一致 |
学习路线时间表¶
| 阶段 | 内容 | 时间 | 验证标准 |
|---|---|---|---|
| 基础语法 | 变量/循环/函数/文件读写 | 2-3周 | 能独立写FASTA解析脚本 |
| 数据分析 | pandas/numpy/matplotlib | 3-4周 | 能处理基因表达矩阵并画图 |
| 序列处理 | Biopython/pysam | 2-3周 | 能从BAM文件提取统计信息 |
| 机器学习 | scikit-learn/PyTorch | 3-4周 | 能完成一个分类项目 |
| 流程自动化 | Snakemake/argparse | 2周 | 能写可复用的分析流程 |
推荐学习资源(2025-2026最新)¶
| 资源 | 类型 | 推荐指数 |
|---|---|---|
| Rosalind (rosalind.info) | 刷题平台 | 必做 |
| Python for Biologists | 入门书 | 强推 |
| Bioinformatics Data Skills (Vince Buffalo) | 综合书 | 必读 |
| DataCamp Bioinformatics Track | 在线课程 | 适合练手 |
| Biology Meets Programming (Coursera) | 在线课程 | 免费旁听 |
| StatQuest ML视频 (YouTube) | 机器学习讲解 | 必看 |
| fast.ai 生物学家路线 | 深度学习 | 进阶用 |
最后更新:2026-05 | 适用于2026届生信工程师面试准备