3. 蛋白质互作数据格式:基本文件格式与数据清洗
好,咱们进入实操环节。做蛋白质互作联合学习,第一个拦路虎就是数据格式。我见过太多人代码写得飞起,结果栽在数据解析上。说白了,这章就是教你怎么跟三种主流格式打交道——TSV、GML、PSI-MI XML。
3.1 三种格式的江湖地位
你想想看,做PPI研究,数据源五花八门。INTACT、BioGRID、HPRD……每个数据库输出的格式都带点自己的脾气。我个人习惯把它们分成三代:
- TSV/CSV:最朴实的表格格式,一列是蛋白A,一列是蛋白B,简单粗暴。像BioGRID就爱用它。
- GML(Graph Modeling Language):图形化格式,专门用来描述网络结构。节点和边分得很清楚,图算法用起来方便。
- PSI-MI XML:国际标准,信息最全。但XML嘛,你懂的,解析起来有点绕。
3.2 TSV格式:最直接的交互对
TSV是我用得最多的格式。原因很简单——不需要额外库就能读。每行代表一对互作关系,列之间用Tab分隔。
# BioGRID互作数据示例(简化版)
# interactor_A interactor_B experimental_system confidence_score
P01116 P01111 Two-hybrid 0.85
P04637 P04629 Co-crystal 0.92
P01116 P04637 Affinity Capture-MS 0.78
记住,不是所有TSV都这么清爽。我在项目中遇到过有些数据库把列顺序藏得特别深,得仔细读README。嗯,这里要注意——一定要检查表头行。有些文件带'#'注释,有些直接就是数据行。
解析小技巧
我个人习惯用Python的csv模块,指定delimiter='\t'。别用split('\t'),万一字段里嵌了引号就悲剧了。
import csv
def load_ppi_tsv(filepath):
interactions = []
with open(filepath, 'r', encoding='utf-8') as f:
# 跳过注释行
lines = [line for line in f if not line.startswith('#')]
reader = csv.reader(lines, delimiter='\t')
for row in reader:
if len(row) >= 2:
interactions.append((row[0].strip(), row[1].strip()))
return interactions
3.3 GML格式:把图结构读出来
GML的好处是节点和边都带属性。做过图神经网络的应该眼熟——节点特征、边权重,这些都能直接塞进GML里。
# 一个简单PPI网络的GML表示
graph [
directed 0
node [
id 0
label "P01116"
domain "RAS"
species "Human"
]
node [
id 1
label "P04637"
domain "p53"
species "Human"
]
edge [
source 0
target 1
interaction_type "physical"
confidence 0.88
]
]
解析GML,我推荐用networkx。它的read_gml()函数相当成熟,但有个坑——GML对数值和字符串很敏感。我曾经遇到一个文件,label字段用的双引号少了一个,整个图就读不进来。花了我半天排查。
import networkx as nx
def parse_ppi_gml(filepath):
# 注意:GML文件不能有中文注释,否则会报编码错误
try:
G = nx.read_gml(filepath, label='label')
print(f"节点数: {G.number_of_nodes()}")
print(f"边数: {G.number_of_edges()}")
return G
except Exception as e:
print(f"解析失败: {e}")
return None
3.4 PSI-MI XML:数据金矿,但挖起来累
PSI-MI XML是HUPO(人类蛋白质组组织)推的标准。信息量最大——参与互作的蛋白域、实验方法、引用文献、信心分数……全都塞进XML里了。
但问题也来了:层级太深。一个互作记录,光包裹它的标签就有四五层。看个片段你就懂了:
<?xml version="1.0" encoding="UTF-8"?>
<entrySet xmlns="net:sf:psidev:mi" level="3" version="4">
<entry>
<interactionList>
<interaction id="1">
<participantList>
<participant id="2">
<interactorRef>10</interactorRef>
<biologicalRole>
<names>
<shortLabel>enzyme</shortLabel>
</names>
</biologicalRole>
</participant>
<participant id="3">
<interactorRef>20</interactorRef>
</participant>
</participantList>
</interaction>
</interactionList>
</entry>
</entrySet>
解析这个?用Python标准库xml.etree.ElementTree能搞定,但代码会很长。我建议用专门的工具——有的数据库提供了REST API,可以直接拉JSON格式。如果一定要啃XML,记得先看schema。
三种格式对比
| 特性 | TSV | GML | PSI-MI XML |
|---|---|---|---|
| 存储内容 | 边列表 | 节点+边+属性 | 全量元数据 |
| 可读性 | ★★★★★ | ★★★☆☆ | ★★☆☆☆ |
| 解析难度 | 低 | 中 | 高 |
| 适合场景 | 快速原型 | 图分析 | 数据库集成 |
| 文件大小 | 小 | 中 | 大 |
| 标准化程度 | 低 | 中 | 高 |
3.5 数据清洗:别让脏数据毁了模型
数据格式搞定了?先别急。从数据库直接扒下来的数据,十个有九个是脏的。我自己处理过的最大一个数据集,2万条互作记录里,有30%需要清洗。
清洗流程
- 去除重复互作对:两个蛋白顺序调换不算新边。用集合判重,或者统一排序(蛋白A字典序<蛋白B字典序)再查重。
- 标准化蛋白ID:UniProt ID有长有短,还有带isoform的(比如P01116-2)。我习惯统一用UniProt AC,不要版本号,不要isoform后缀。
- 过滤自环:蛋白自己跟自己互作?生物学上意义不大,联合学习里还会造成自环影响。果断去掉。
- 处理缺失值:有些记录confidence_score是空的。看情况——如果只有少量缺失,填中位数;如果大面积缺失,干脆不用这个特征。
- 合并多源数据:从BioGRID和INTACT同时拉数据,ID形式可能不一样。一定要统一到同一个命名空间。比如都转UniProt AC。
一个完整的清洗管道示例
import pandas as pd
def clean_ppi_data(df):
# step 1: 去重(不区分方向)
df['sorted_pair'] = df.apply(
lambda x: tuple(sorted([x['protein_a'], x['protein_b']])), axis=1
)
df = df.drop_duplicates(subset='sorted_pair')
# step 2: 删除自环
df = df[df['protein_a'] != df['protein_b']]
# step 3: ID标准化(假设已有UniProt映射表)
id_map = {"P53_HUMAN": "P04637", "RAS_HUMAN": "P01116"} # 示例
df['protein_a'] = df['protein_a'].map(id_map).fillna(df['protein_a'])
df['protein_b'] = df['protein_b'].map(id_map).fillna(df['protein_b'])
# step 4: 缺失值处理
df['confidence_score'] = df['confidence_score'].fillna(df['confidence_score'].median())
return df[['protein_a', 'protein_b', 'confidence_score', 'experiment_type']]
3.6 一张图看清数据流转
下面我画了一张图,把从原始数据到干净特征的整体流程展示出来。你用这个图做参考,对照自己的项目流程,应该能少走很多弯路。
3.7 多源数据的统一之战
实际项目中你很少只用单一数据库。INTACT、BioGRID、HPRD、STRING……格式不同,ID不同,甚至互作定义也不同。怎么办?
我的经验是:先统一到UniProt AC,再检查互作方向。有些数据库会记录“A与B互作”,有些会标注“A是kinase,B是substrate”。如果你做的是无向图,直接把方向信息扔掉。但有些下游任务(比如预测互作类型)需要保留下文信息——这时候数据清洗就得多留个心眼。