mcpField
M
maxquant-proteomics

maxquant-proteomics

github.com/jaechang-hits数据与数据库38474 次安装6 天前更新
代码仓库

关于 maxquant-proteomics

该流程面向蛋白质组学研究者,结合 MaxQuant 和 Python,对 LC-MS/MS 数据进行蛋白鉴定、定量及差异分析。它以 MaxQuant 输出为输入,并用可复现的脚本完成缺失值处理、统计检验和富集分析。

主要功能

  1. 01使用 MaxQuant 搜索和定量蛋白质
  2. 02处理 LFQ、SILAC 和标记定量
  3. 03过滤并归一化蛋白组数据
  4. 04执行缺失值填补和差异检验
  5. 05进行 GO 与通路富集分析
  6. 06生成火山图输入数据

适用场景

  1. 01比较多个生物条件下的蛋白丰度
  2. 02分析 SILAC 或 TMT 实验结果
  3. 03在 Python 中替代 Perseus 进行统计分析
  4. 04从显著蛋白中开展通路富集

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill maxquant-proteomics

安装后在 Claude Code 中输入/maxquant-proteomics确认已加载。

详细介绍

MaxQuant + Perseus — 蛋白质组学分析流程

概述

MaxQuant 是用于无标记定量(LFQ)和 SILAC 蛋白质组学的社区标准软件。它会从原始 LC-MS/MS 文件中执行数据库检索、蛋白质分组和基于强度的定量,并生成 proteinGroups.txt 作为主要输出。下游统计分析——筛选、归一化、插补、差异丰度检验和可视化——使用 pandas、scipy 和 matplotlib/seaborn 在 Python 中完成,在可复现的脚本环境中复现 Perseus 工作流。

适用场景

  • 对多个生物学条件下的蛋白质执行无标记定量(LFQ)——MaxQuant 的 MaxLFQ 算法是社区基准
  • 运行采用轻/重或三标记设计的 SILAC(稳定同位素标记)实验
  • 通过 MaxQuant 的报告离子定量处理 iTRAQ 或 TMT 等压标记实验
  • 在需要广泛引用的 MaxQuant 输出格式(proteinGroups.txt)以便与已发表数据集比较时,鉴定和定量蛋白质
  • 无需安装 Perseus(仅提供 Windows 图形界面)即可对 MaxQuant 输出执行差异丰度统计分析
  • 在可复现的 Python 工作流中,基于蛋白质组学数据生成适用于发表的火山图和 GO 富集分析
  • 处理需要仪器原生处理或 Sequest HT 的 Thermo 原始文件时,改用 Proteome Discoverer
  • 需要 GPU 加速数据库检索(快 3–10×)或处理 DIA(数据非依赖采集)数据时,改用 FragPipe/MSFragger
  • 差异丰度分析或 GSEA 后,使用 omics-plotting SKILL 生成适用于发表的图表

前提条件

  • MaxQuant:Windows 软件;从 https://maxquant.org/ 下载(v2.4+);需要 .NET 6 运行时
  • Python 包:pandas、numpy、scipy、matplotlib、seaborn、statsmodels、gseapy
  • 数据要求:Thermo .raw 文件或转换为 mzML 的文件;FASTA 蛋白质数据库(UniProt reviewed + 污染物数据库)
  • 环境:MaxQuant 在 Windows 上运行(图形界面或命令行);Python 分析可跨平台运行
pip install pandas numpy scipy matplotlib seaborn statsmodels gseapy
# Install pyMaxQuant for programmatic mqpar.xml configuration
pip install pymaxquant

预先访谈

编写任何分析代码前,先与用户确认以下事项。

decisions:
  - id: D1
    param: quantificationStrategy
    kind: required
    source: user
    ask: "How were samples quantified - label-free, SILAC, or isobaric tags?"
    default: null

  - id: D2
    param: proteinSequenceDatabase
    kind: required
    source: user
    ask: "Which organism's protein FASTA, and which release, should spectra be searched against?"
    default: null

  - id: D3
    param: digestionEnzyme
    kind: required
    source: user
    ask: "Which protease was used, and how many missed cleavages should be allowed?"
    default: "trypsin, up to 2 missed cleavages"

  - id: D4
    param: modifications
    kind: required
    source: user
    ask: "Which modifications are fixed, and which variable - and is there an enrichment such as phospho to search for?"
    default: "fixed carbamidomethyl on cysteine; variable oxidation and N-terminal acetylation"

  - id: D5
    param: falseDiscoveryRates
    kind: required
    source: user
    ask: "What false-discovery rate should peptide and protein identifications be held to?"
    default: "1% at both levels"

  - id: D6
    param: matchBetweenRuns
    kind: required
    source: user
    depends_on: [D1]
    ask: "Should identifications be transferred between runs by retention time, recovering more proteins at the cost of some transferred errors?"
    default: "off"

  - id: D7
    param: lfqMinRatioCount
    kind: optional
    source: user
    depends_on: [D1]
    ask: "How many shared peptides must two samples have before their abundances are normalized against each other?"
    default: 2
    skip_if: "labelled quantification"

  - id: D8
    param: missingValueImputation
    kind: required
    source: user
    ask: "How should proteins missing from a sample be treated - left missing, or imputed as below the detection limit?"
    default: "imputed from a downshifted distribution"

  - id: D9
    param: differentialThresholds
    kind: required
    source: user
    ask: "What significance and fold-change cuts define a changed protein?"
    default: "FDR 0.05, log2 fold change 1.0"

D8 是蛋白质组学区别于 RNA-seq 的地方,也是结果最常因未经审视的默认设置而发生变化的地方。某个蛋白质在所有对照样本中都未检出、却在所有处理样本中都存在,可能是最有力的结果,也可能是检测限造成的伪象;插补方式决定了火山图会呈现哪一种情况。D6 与之相互影响:转移的鉴定结果恰好会填补原本需要插补的数值。

快速开始

import pandas as pd
import numpy as np

# Load MaxQuant output
df = pd.read_csv("combined/txt/proteinGroups.txt", sep="\t", low_memory=False)
print(f"Raw protein groups: {len(df)}")

# Filter contaminants, reverse decoys, only-by-site
mask = (
    (df["Potential contaminant"] != "+") &
    (df["Reverse"] != "+") &
    (df["Only identified by site"] != "+")
)
df = df[mask].copy()
print(f"After filtering: {len(df)} protein groups")

# Extract LFQ intensity columns
lfq_cols = [c for c in df.columns if c.startswith("LFQ intensity ")]
print(f"LFQ columns: {lfq_cols}")

# Log2-transform (0 → NaN)
lfq = df[lfq_cols].replace(0, np.nan)
lfq = np.log2(lfq)
print(f"Valid values per sample:\n{lfq.notna().sum()}")

工作流

步骤 1:通过 mqpar.xml 配置 MaxQuant 参数

MaxQuant 通过 XML 参数文件(mqpar.xml)控制。运行检索前,以编程方式编辑该文件,设置文件路径、酶、修饰和定量类型。

import xml.etree.ElementTree as ET

def update_mqpar(template_path: str, output_path: str,
                 raw_files: list[str], fasta_path: str,
                 experiment_names: list[str]) -> None:
    """Update mqpar.xml with sample-specific file paths."""
    tree = ET.parse(template_path)
    root = tree.getroot()

    # Set raw file paths
    file_paths_node = root.find(".//filePaths")
    file_paths_node.clear()
    for rf in raw_files:
        elem = ET.SubElement(file_paths_node, "string")
        elem.text = rf

    # Set experiment names (maps files to conditions)
    experiments_node = root.find(".//experiments")
    experiments_node.clear()
    for name in experiment_names:
        elem = ET.SubElement(experiments_node, "string")
        elem.text = name

    # Set FASTA database
    fasta_node = root.find(".//fastaFiles/FastaFileInfo/fastaFilePath")
    fasta_node.text = fasta_path

    tree.write(output_path, xml_declaration=True, encoding="utf-8")
    print(f"Written: {output_path}")

# Example usage
raw_files = [
    r"C:\Data\ctrl_rep1.raw",
    r"C:\Data\ctrl_rep2.raw",
    r"C:\Data\treat_rep1.raw",
    r"C:\Data\treat_rep2.raw",
]
update_mqpar(
    template_path="mqpar_template.xml",
    output_path="mqpar.xml",
    raw_files=raw_files,
    fasta_path=r"C:\Databases\human_uniprot_contaminants.fasta",
    experiment_names=["ctrl", "ctrl", "treat", "treat"],
)

mqpar.xml 的关键参数(在模板中设置或直接编辑):


<enzymes>
  <string>Trypsin/P</string>
</enzymes>
<maxMissedCleavages>2</maxMissedCleavages>
<variableModifications>
  <string>Oxidation (M)</string>
  <string>Acetyl (Protein N-term)</string>
</variableModifications>
<fixedModifications>
  <string>Carbamidomethyl (C)</string>
</fixedModifications>


<lfqMode>1</lfqMode>                     
<lfqMinRatioCount>2</lfqMinRatioCount>   
<matchBetweenRuns>True</matchBetweenRuns>


<peptideFdr>0.01</peptideFdr>
<proteinFdr>0.01</proteinFdr>
步骤 2:从命令行运行 MaxQuant(Windows)

MaxQuant 可通过捆绑的 MaxQuantCmd.exe 从 Windows 命令提示符以无界面方式运行。

REM Windows Command Prompt — run MaxQuant with configured mqpar.xml
REM Adjust path to match your MaxQuant installation directory

set MQ_PATH=C:\Program Files\MaxQuant\bin\MaxQuantCmd.exe
set MQPAR=C:\Projects\proteomics\mqpar.xml

"%MQ_PATH%" "%MQPAR%"

REM For specific workflow steps only (useful for reruns):
REM Step IDs: 0=write tables, 1=feature detection, 7=peptide identification
"%MQ_PATH%" "%MQPAR%" --steps 1,7,11
# Cross-platform: run MaxQuant under Wine on Linux/macOS (CI/server use)
wine MaxQuantCmd.exe mqpar.xml

# Monitor progress log
tail -f combined/proc/#runningTimes.txt
步骤 3:加载并筛选 proteinGroups.txt

筛除反向诱饵、潜在污染物以及仅通过修饰位点鉴定的蛋白质。

import pandas as pd
import numpy as np

def load_protein_groups(path: str) -> pd.DataFrame:
    """Load MaxQuant proteinGroups.txt with quality filters applied."""
    df = pd.read_csv(path, sep="\t", low_memory=False)
    print(f"Total protein groups: {len(df)}")

    # Remove reverse decoys, contaminants, and only-by-site hits
    n_before = len(df)
    df = df[
        (df.get("Reverse", pd.Series("")) != "+") &
        (df.get("Potential contaminant", pd.Series("")) != "+") &
        (df.get("Only identified by site", pd.Series("")) != "+")
    ].copy()
    print(f"After quality filter: {len(df)} ({n_before - len(df)} removed)")

    # Parse gene names (take first entry for multi-gene groups)
    df["Gene names"] = df["Gene names"].fillna("Unknown").str.split(";").str[0]

    # Set unique index on majority protein ID
    df = df.set_index("Majority protein IDs")
    return df

# Load output
pg = load_protein_groups("combined/txt/proteinGroups.txt")

# Identify LFQ intensity columns
lfq_cols = [c for c in pg.columns if c.startswith("LFQ intensity ")]
print(f"LFQ samples ({len(lfq_cols)}): {lfq_cols}")
# Output: LFQ samples (6): ['LFQ intensity ctrl_1', 'LFQ intensity ctrl_2', ...]
步骤 4:对 LFQ 强度进行 Log2 转换和中位数归一化

将强度为零的值替换为 NaN(MaxQuant 将缺失值导出为 0),进行 log2 转换,然后按样本执行中位数中心化。

def prepare_lfq_matrix(df: pd.DataFrame, lfq_cols: list[str]) -> pd.DataFrame:
    """Extract, transform, and normalize LFQ intensity matrix."""
    # Extract and rename columns (strip 'LFQ intensity ' prefix)
    lfq = df[lfq_cols].copy()
    lfq.columns = [c.replace("LFQ intensity ", "") for c in lfq_cols]

    # Replace 0 with NaN (MaxQuant encodes missing as 0)
    lfq = lfq.replace(0, np.nan)

    # Log2 transform
    lfq = np.log2(lfq)

    # Median centering per sample (subtract per-column median of valid values)
    col_medians = lfq.median(axis=0)
    global_median = col_medians.median()
    lfq = lfq.subtract(col_medians, axis=1).add(global_median)

    print(f"Matrix shape: {lfq.shape}")
    print(f"Missing values per sample:\n{lfq.isna().sum()}")
    print(f"Valid values per sample:\n{lfq.notna().sum()}")
    return lfq

lfq_matrix = prepare_lfq_matrix(pg, lfq_cols)
# Matrix shape: (3241, 6)
# Missing values per sample: ctrl_1: 421, ctrl_2: 389, ...
步骤 5:插补缺失值(MNAR 策略)

非随机缺失(MNAR)值来自低于检测限的蛋白质。从观测到的强度分布低端进行插补——这是标准的 Perseus 方法。

def impute_mnar(lfq: pd.DataFrame,
                width: float = 0.3,
                downshift: float = 1.8,
                random_state: int = 42) -> pd.DataFrame:
    """
    Impute MNAR missing values from a downshifted Gaussian.

    Parameters
    ----------
    width      : std of imputation distribution (fraction of sample std)
    downshift  : downshift in units of sample std below mean
    random_state : for reproducibility
    """
    rng = np.random.default_rng(random_state)
    lfq_imp = lfq.copy()

    for col in lfq_imp.columns:
        col_data = lfq_imp[col].dropna()
        col_mean = col_data.mean()
        col_std = col_data.std()

        n_missing = lfq_imp[col].isna().sum()
        if n_missing > 0:
            imputed = rng.normal(
                loc=col_mean - downshift * col_std,
                scale=width * col_std,
                size=n_missing,
            )
            lfq_imp.loc[lfq_imp[col].isna(), col] = imputed

    print(f"Imputed {lfq.isna().sum().sum()} missing values")
    return lfq_imp

lfq_imputed = impute_mnar(lfq_matrix)
# Imputed 2847 missing values
第 6 步:统计检验——带 FDR 校正的 t 检验

对不同条件下的每种蛋白质执行双样本 t 检验,然后进行 Benjamini-Hochberg FDR 校正。

from scipy import stats
from statsmodels.stats.multitest import multipletests

def differential_abundance(lfq: pd.DataFrame,
                            group_a: list[str],
                            group_b: list[str],
                            alpha: float = 0.05) -> pd.DataFrame:
    """
    Two-sample t-test + BH FDR correction for all proteins.

    Parameters
    ----------
    group_a, group_b : sample name lists for each condition
    alpha : FDR threshold
    """
    results = []
    for protein_id, row in lfq.iterrows():
        a_vals = row[group_a].dropna().values
        b_vals = row[group_b].dropna().values

        if len(a_vals) >= 2 and len(b_vals) >= 2:
            t_stat, p_val = stats.ttest_ind(a_vals, b_vals, equal_var=False)
            log2fc = b_vals.mean() - a_vals.mean()
        else:
            t_stat, p_val, log2fc = np.nan, np.nan, np.nan

        results.append({
            "protein_id": protein_id,
            "log2FC": log2fc,
            "pvalue": p_val,
            "t_stat": t_stat,
        })

    res_df = pd.DataFrame(results).set_index("protein_id")

    # BH FDR correction on valid p-values
    valid = res_df["pvalue"].notna()
    _, padj, _, _ = multipletests(res_df.loc[valid, "pvalue"], method="fdr_bh")
    res_df.loc[valid, "padj"] = padj

    # Add significance flag
    res_df["significant"] = (res_df["padj"] < alpha) & (res_df["pvalue"].notna())
    sig_count = res_df["significant"].sum()
    print(f"Significant proteins (FDR < {alpha}): {sig_count}")

    return res_df.sort_values("padj")

# Define sample groups
group_ctrl  = ["ctrl_1",  "ctrl_2",  "ctrl_3"]
group_treat = ["treat_1", "treat_2", "treat_3"]

results = differential_abundance(lfq_imputed, group_ctrl, group_treat)
print(results[results["significant"]].head(10))
# Significant proteins (FDR < 0.05): 312
第 7 步:火山图可视化

绘图:计算 DEG 表,然后阅读 skills/data-visualization/omics-plotting/SKILL.md 并遵循其中的「火山图」配方,处理导出的 CSV(→ figures/volcano_plot.png)。

# Volcano input: log2FC vs padj + protein labels; render with the omics-plotting SKILL (`skills/data-visualization/omics-plotting/SKILL.md`) "Volcano" recipe.
volcano_df = results[["log2FC", "padj"]].copy()
volcano_df["gene"] = pg["Gene names"].reindex(results.index)
volcano_df.dropna(subset=["log2FC", "padj"]).to_csv("volcano_input.csv")
print(f"Volcano input: {int(volcano_df['padj'].notna().sum())} proteins -> volcano_input.csv")
# -> figures/volcano_plot.png via omics-plotting (map log2FC -> log2FoldChange)
第 8 步:显著蛋白质的 GO/通路富集分析

使用 gseapy 的 Enrichr API,对显著上调和下调的蛋白质执行过度代表分析(ORA)。

import gseapy as gp

def run_enrichment(results: pd.DataFrame,
                   gene_names: pd.Series,
                   gene_sets: list[str] | None = None,
                   top_n: int = 20) -> dict[str, pd.DataFrame]:
    """
    ORA enrichment for up- and down-regulated proteins via Enrichr.

    Parameters
    ----------
    gene_sets : Enrichr gene set libraries (default: GO BP + KEGG)
    top_n     : top results to display per direction
    """
    if gene_sets is None:
        gene_sets = ["GO_Biological_Process_2023", "KEGG_2021_Human"]

    results_out = {}
    gene_map = gene_names.reindex(results.index).fillna("Unknown")

    for direction in ("up", "down"):
        sig = results[
            (results["significant"]) &
            (results["log2FC"] > 0 if direction == "up" else results["log2FC"] < 0)
        ]
        gene_list = gene_map.reindex(sig.index).tolist()
        print(f"{direction.capitalize()}-regulated: {len(gene_list)} proteins")

        if len(gene_list) < 5:
            print(f"  Too few proteins for enrichment (n={len(gene_list)}), skipping")
            continue

        enr = gp.enrichr(
            gene_list=gene_list,
            gene_sets=gene_sets,
            organism="Human",
            outdir=f"enrichment_{direction}",
            cutoff=0.05,
        )
        top_results = enr.results.sort_values("Adjusted P-value").head(top_n)
        results_out[direction] = top_results
        print(top_results[["Term", "Adjusted P-value", "Overlap"]].to_string(index=False))

    return results_out

enr_results = run_enrichment(results, pg["Gene names"])

关键参数

参数默认值范围 / 选项作用
matchBetweenRunsFalseTrue / False通过保留时间匹配,在不同运行之间转移鉴定结果;使定量蛋白质数量增加 10–30%
lfqMinRatioCount21–5LFQ 归一化所需的最少肽段对数量;较低的值可提高覆盖率,但会降低准确性
maxMissedCleavages20–4允许的胰蛋白酶漏切数;消化效果较差的样本可调高此值
peptideFdr / proteinFdr0.010.001–0.05肽段和蛋白质鉴定的 FDR 阈值
MNAR downshift1.81.5–2.5以列标准差为单位,将插补分布下移至检测限以下;值越大,插补越保守
MNAR width0.30.1–0.5插补分布相对于列标准差的宽度
t 检验 alpha0.050.01–0.1差异丰度的 FDR 显著性阈值
火山图 fc_threshold1.00.5–2.0火山图中标记为「显著」的 log2 倍数变化截断值

关键概念

MaxQuant 输出文件
文件内容
proteinGroups.txt主要输出:每个蛋白质组一行,包含 LFQ/SILAC 强度、肽段计数和序列覆盖率
peptides.txt肽段级定量,包含电荷态和修饰
evidence.txt单条 MS/MS 鉴定结果(每个肽段-谱图匹配一行)
msms.txt完整的 MS/MS 扫描数据,包含碎片离子和评分
summary.txt每个原始文件的统计信息:鉴定结果、MS/MS 计数和校准信息
LFQ 强度与 iBAQ
  • LFQ(非标记定量):MaxLFQ 算法基于 razor 肽段和唯一肽段的比值,对不同样本的强度进行归一化。用于跨样本比较(倍数变化)。存储在 LFQ intensity <sample> 列中。
  • iBAQ(基于强度的绝对定量):将肽段强度总和除以理论上可观测的肽段数量。用于估算拷贝数,以及比较同一样本中不同蛋白质的绝对丰度。存储在 iBAQ 列中。
  • SILAC 比值:来自同位素标记配对的直接 H/L 比值。对于较小的倍数变化,其准确性高于 LFQ。
Perseus 在 Python 中的等效操作
Perseus 步骤Python 等效操作
按分类列筛选行df[df["Reverse"] != "+"]
将 0 替换为 NaNdf.replace(0, np.nan)
Log2 转换np.log2(df)
中位数归一化df.subtract(df.median()).add(global_median)
MNAR 插补(正态分布)上面的 impute_mnar() 函数
双样本 t 检验scipy.stats.ttest_ind() + multipletests()
火山图使用 matplotlib.pyplot 散点图和阈值线
层次聚类seaborn.clustermap()

常用配方

配方:SILAC 比值分析

适用场景:使用 H/L 或 H/M/L 标记而非 LFQ 的 SILAC 实验。

import pandas as pd
import numpy as np

# Load proteinGroups.txt for SILAC experiment
df = pd.read_csv("combined/txt/proteinGroups.txt", sep="\t", low_memory=False)

# Filter contaminants and decoys
df = df[(df["Reverse"] != "+") & (df["Potential contaminant"] != "+")].copy()

# Extract H/L ratio columns (log2-transformed)
ratio_cols = [c for c in df.columns if c.startswith("Ratio H/L ") and "normalized" in c.lower()]
if not ratio_cols:
    # Fall back to non-normalized
    ratio_cols = [c for c in df.columns if c.startswith("Ratio H/L")]

print(f"SILAC ratio columns: {ratio_cols}")
ratios = df[ratio_cols].copy().replace(0, np.nan)

# Log2 transform ratios
log2_ratios = np.log2(ratios)
log2_ratios.columns = [c.replace("Ratio H/L normalized ", "") for c in ratio_cols]

# Summary statistics per sample
print(log2_ratios.describe().round(3))
配方:层次聚类热图

适用场景:同时可视化所有显著蛋白质的模式。计算下面的 z 分数矩阵,然后阅读 skills/data-visualization/omics-plotting/SKILL.md 并遵循其中的「聚类表达热图」配方(→ figures/heatmap.pdf)。

import pandas as pd

def prep_heatmap_matrix(lfq_imputed: pd.DataFrame,
                        results: pd.DataFrame,
                        gene_names: pd.Series,
                        top_n: int = 50,
                        out_path: str = "heatmap_matrix.csv") -> pd.DataFrame:
    """Z-scored expression matrix of the top significant proteins, for the omics-plotting heatmap."""
    sig_proteins = results[results["significant"]].nsmallest(top_n, "padj").index
    heatmap_data = lfq_imputed.loc[sig_proteins].copy()
    heatmap_data.index = gene_names.reindex(sig_proteins).fillna(sig_proteins)
    # Z-score per row
    heatmap_z = heatmap_data.subtract(heatmap_data.mean(axis=1), axis=0).divide(
        heatmap_data.std(axis=1).replace(0, 1), axis=0
    )
    heatmap_z.to_csv(out_path)
    return heatmap_z

mat = prep_heatmap_matrix(lfq_imputed, results, pg["Gene names"])
print(f"Heatmap matrix: {mat.shape} -> heatmap_matrix.csv")
# Render with the omics-plotting SKILL (`skills/data-visualization/omics-plotting/SKILL.md`) "Clustered expression heatmap" recipe -> figures/heatmap.pdf
配方:对显著蛋白进行 STRING-db 网络富集分析

适用场景:无需在本地下载基因集,即可进行蛋白质-蛋白质相互作用网络分析和富集分析。

import requests
import pandas as pd

def string_enrichment(gene_list: list[str],
                      species: int = 9606,
                      fdr_threshold: float = 0.05) -> pd.DataFrame:
    """Query STRING /enrichment endpoint for GO/KEGG enrichment."""
    url = "https://string-db.org/api/json/enrichment"
    params = {
        "identifiers": "\r".join(gene_list),
        "species": species,
        "caller_identity": "maxquant_proteomics_skill",
    }
    response = requests.post(url, data=params)
    response.raise_for_status()

    enr_df = pd.DataFrame(response.json())
    if enr_df.empty:
        print("No enrichment results returned")
        return enr_df

    enr_df = enr_df[enr_df["fdr"].astype(float) < fdr_threshold]
    enr_df = enr_df.sort_values("fdr")
    print(f"Enriched terms (FDR < {fdr_threshold}): {len(enr_df)}")
    print(enr_df[["category", "term", "description", "fdr", "number_of_genes"]].head(15).to_string(index=False))
    return enr_df

# Significant up-regulated gene names
up_genes = pg.loc[
    results[(results["significant"]) & (results["log2FC"] > 1)].index, "Gene names"
].tolist()

string_enr = string_enrichment(up_genes)
配方:使用 pyMaxQuant 解析 MaxQuant 输出

适用场景:使用更高级别的 API 读取和筛选 MaxQuant 文本文件。

# pyMaxQuant provides typed accessors for MaxQuant output files
# Install: pip install pymaxquant
from maxquant.io import read_protein_groups

# Load with built-in contaminant filtering
pg_clean = read_protein_groups(
    "combined/txt/proteinGroups.txt",
    filter_invalid=True,      # removes reverse, contaminant, only-by-site
)
print(f"Loaded {len(pg_clean)} filtered protein groups")

# Access LFQ columns via helper
lfq_df = pg_clean.filter(like="LFQ intensity")
print(f"LFQ matrix: {lfq_df.shape}")

预期输出

文件描述
combined/txt/proteinGroups.txtMaxQuant 主要输出:包含 LFQ 强度、肽段计数、唯一肽段和 iBAQ 的蛋白组
combined/txt/peptides.txt肽段水平的定量结果,包含修饰和电荷状态
combined/txt/summary.txt每个原始文件的 QC 统计:鉴定率、MS/MS 计数
results_differential.csv差异丰度表:每种蛋白对应的 log2FC、pvalue、padj、significant
volcano_plot.pdf火山图:用颜色区分上调/下调蛋白,并标注排名靠前的蛋白
heatmap.pdf显著性最高的蛋白的层次聚类热图(经 Z-score 归一化)
enrichment_up/gseapy 输出目录:上调蛋白的 GO/KEGG 富集结果
enrichment_down/gseapy 输出目录:下调蛋白的 GO/KEGG 富集结果

故障排除

问题原因解决方案
MaxQuant 未鉴定出任何蛋白FASTA 数据库或酶设置错误;未找到原始文件路径检查 mqpar.xml 中的 .raw 文件路径是否为绝对 Windows 路径;确认酶设置与实验相符(Trypsin/P 或 Trypsin);查看 summary.txt 中的鉴定率
筛选后所有 LFQ 强度均为 0matchBetweenRuns 未启用且数据稀疏,或列选择错误直接检查 combined/txt/proteinGroups.txt;使用 pg.filter(like="LFQ intensity") 确认列名;将 lfqMinRatioCount 降至 1
log2 转换后缺失值过多重复样本不足、样本上样量不一致,或肽段未被检测到启用 matchBetweenRuns;确认蛋白上样量相等(Bradford/BCA);在填补前考虑采用更严格的有效值筛选条件(要求每组 3/3 个有效值)
加载 proteinGroups.txt 时发生内存错误文件较大(DDA 且样本较多时超过 500 MB)使用 pd.read_csv(..., low_memory=False, usecols=[...]) 仅选取所需列;或使用 pd.read_csv(..., chunksize=...)
gseapy Enrichr 返回空结果无法识别基因符号或网络超时确保基因列表使用 HGNC 符号(而非 UniProt ID);检查网络连接;使用 gp.enrichr(..., timeout=60)
火山图中所有蛋白都标为“ns”FDR 阈值过严或未计算 padj确认 multipletests 返回了有效的 FDR 值;尝试将 alpha 放宽至 0.1;检查样本组别分配是否正确
MaxQuant 运行卡在“Feature detection”阶段内存不足(每 3–4 个原始文件需要 4–8 GB RAM)分批处理文件;增加系统 RAM;关闭其他应用程序
填补导致假阳性增多填补过于激进(downshift 值过低)将 downshift 增至 2.0–2.5;也可以在检验前筛选出每组有 ≥ 2 个有效值的蛋白

参考资料

评论

支持 Markdown