今天我们来聊一个vibe coding时代药化同学迟早会遇到的东西:Data Parsing,数据解析。我愿意称之为数据高级定制听起来很高级,好像一打开就要召唤计算机大神。其实说白了,它就是:> 把乱七八糟的 Excel 数据,整理成机器能看懂的一张干净大表。1. 药物的物理化学性质
2. 药物对细胞系的 IC50
3. 细胞系的 mutation 信息
你想做 Random Forest,预测药物对不同细胞系的效果。问题是,这些信息一开始不在一张表里。就像实验室里三个人各拿一半真相:B 同学说:“我知道这个药物对 A549 的 IC50。”C 同学说:“我知道 A549 有哪些 mutation。”> “你们能不能先把话说完整?一行里面同时告诉我 cellline、drug name、IC50、mutation、分子描述符,不然我怎么学习?” 一、为什么 AI 会写代码,我们还要手搓?
> “AI,帮我把三个 Excel merge 一下,再训练 Random Forest。”```pythonKeyError: 'drug_name'```
这就像你让学生帮你配 buffer,他说“老师我配好了”,结果 pH 是 14。尤其是 Python 和 Pandas,刚开始一定要 **手搓**。```pythonKeyError: 'drug_name'```
> 哦,不是 Python 坏了,是我的表里没有叫 `drug_name` 的 column。## 二、我们的真实问题:column 名字不一致
```pythonlearning["drug_name"]```
因为真实的 `learning` 表里 column 是:```python['cellline', 'drug', 'ic50(ln)']```
而另一个药物描述符表 `drug_desc` 里面叫:这就像一个人身份证上叫“张三”,另一个表里叫“老张”。你让 Python 按“张三”找“老张”,它当然说: 三、第一步:导入工具
```python#导入 pandas,用来处理表格数据#可以把 pandas 理解成 Python 版的 Excel,但是更适合自动化和大规模数据处理import pandas as pd#导入 numpy,用来处理数字、矩阵、缺失值等#后面做机器学习时也经常会用到import numpy as np```
如果你还没有安装这些包,在 Mac Terminal 里运行:```bashpython3 -m pip install pandas numpy openpyxl scikit-learn```
如果你在 Jupyter Notebook 里运行,可以写:```python!pip install pandas numpy openpyxl scikit-learn```
四、第二步:读取三个 Excel
```python#读取药物描述符数据#这个表里通常有 drug_name、ALogP、ALogP2、nAcid 等分子物理化学特征drug_desc = pd.read_excel("2d_str_PADEL_norm_modify_GDSC_final.xlsx")#读取学习数据#这个表里有 cellline、drug、IC50 信息learning = pd.read_excel("learning_data.xlsx")#读取 mutation 数据#这个表里有 mutation 信息,列名通常是不同 cell linemutation = pd.read_excel("match_count2.xlsx")```
```python#查看每个表的大小#shape 会返回:多少行,多少列print("drug_desc:", drug_desc.shape)print("learning:", learning.shape)print("mutation:", mutation.shape)#查看每个表前 5 行print(drug_desc.head())print(learning.head())print(mutation.head())```
五、第三步:清理 column 名字
```textDrug nameDrug Namedrug namedrug name```
```python#定义一个函数,用来清理表格的 column 名字def clean_columns(df):#df.columns 表示这个表的所有列名df.columns = (df.columns.astype(str)#把所有列名转成字符串,避免有些列名是数字或 NaN.str.strip()#去掉列名前后的空格.str.lower()#全部变成小写.str.replace(" ", "_")#把空格变成下划线.str.replace("-", "_")#把短横线变成下划线.str.replace(".", "_", regex=False)#把点号变成下划线)return df```
```python#清理三个表的 column 名字drug_desc = clean_columns(drug_desc)learning = clean_columns(learning)mutation = clean_columns(mutation)```
```python#打印 learning 表的所有列名print("learning columns:")print(learning.columns.tolist())#打印 drug_desc 表前 10 个列名print("drug_desc columns:")print(drug_desc.columns[:10].tolist())#打印 mutation 表前 10 个列名print("mutation columns:")print(mutation.columns[:10].tolist())```
其实 80% 的情况只是 column 名字没对上。六、第四步:把 learning 表的列名改成统一格式
```pythonlearning.columns.tolist()```
```python['cellline', 'drug', 'ic50(ln)']```
```pythoncelllinedrug_nameic50```
```pythonrename learning columns#把 learning 表里的 drug 改成 drug_name#把 ic50(ln) 改成 ic50#这样后面 merge 和建模更方便learning = learning.rename(columns={"drug": "drug_name","ic50(ln)": "ic50"})```#检查一下:```pythonprint(learning.columns.tolist())```
```python['cellline', 'drug_name', 'ic50']```
七、第五步:清理关键列里的文字
```textGefitinib Gefitinibgefitinib```
这些对人来说一样,对 Python 来说可能不一样。所以我们要处理 `drug_name` 和 `cellline`。```pythonclean key values#把 drug_name 转成字符串,然后去掉前后空格learning["drug_name"] = learning["drug_name"].astype(str).str.strip()#把 cellline 转成字符串,然后去掉前后空格learning["cellline"] = learning["cellline"].astype(str).str.strip()#drug_desc 表里的 drug_name 也要做同样处理drug_desc["drug_name"] = drug_desc["drug_name"].astype(str).str.strip()```
八、第六步:第一次 merge,给 IC50 配上药物性质
learning 表
```textcellline | drug_name | ic50```
drug_desc 表
```textdrug_name | nacid | alogp | alogp2 | ...```
```pythonfirst merge#以 learning 为主表#根据 drug_name 去 drug_desc 里找对应的分子描述符merge1 = pd.merge(learning,#左边主表,保留所有 learning 里的行drug_desc,#右边表,提供药物 descriptoron="drug_name",#按 drug_name 这一列进行匹配how="left"#左连接,learning 里的数据全部保留)```
> learning 表里的每一条 IC50 数据都保留,然后去 drug_desc 表里找药物特征。九、第七步:检查第一次 merge 是否成功
```python打印三个表的大小print("learning:", learning.shape)print("drug_desc:", drug_desc.shape)print("merge1:", merge1.shape)```
```python查看 merge 后的结果如果能看到 nacid、alogp、alogp2,说明药物 descriptor 已经成功加进来了print(merge1[["cellline", "drug_name", "ic50", "nacid", "alogp", "alogp2"]].head())```
```textcellline drug_name ic50 nacid alogp alogp2A549 Gefitinib 1.23 0 3.1 9.61H1975 Erlotinib 0.89 0 2.8 7.84```
```text这个药物对这个细胞的 IC50```
```text这个药物对这个细胞的 IC50,同时这个药物有哪些物理化学性质```
十、完整代码,适合初学者复制运行
# =========================# Step 1. Import libraries# =========================# pandas 用来处理表格import pandas as pd# numpy 用来处理数字和矩阵import numpy as np# =========================# Step 2. Read Excel files# =========================# 药物物理化学描述符表drug_desc = pd.read_excel("2d_str_PADEL_norm_modify_GDSC_final.xlsx")# IC50 学习数据learning = pd.read_excel("learning_data.xlsx")# mutation 数据mutation = pd.read_excel("match_count2.xlsx")# =========================# Step 3. Clean column names# =========================def clean_columns(df): """ 这个函数用来清理 column 名字。 目的: 1. 去掉前后空格 2. 全部变小写 3. 把空格、横线、点号换成下划线 这样可以减少 KeyError。 """ df.columns = ( df.columns .astype(str) .str.strip() .str.lower() .str.replace(" ", "_") .str.replace("-", "_") .str.replace(".", "_", regex=False) ) return df# 对三个表都进行 column 清理drug_desc = clean_columns(drug_desc)learning = clean_columns(learning)mutation = clean_columns(mutation)# =========================# Step 4. Check real columns# =========================# 打印真实列名# 初学者一定要养成这个习惯print("learning columns:")print(learning.columns.tolist())print("drug_desc first 10 columns:")print(drug_desc.columns[:10].tolist())print("mutation first 10 columns:")print(mutation.columns[:10].tolist())# =========================# Step 5. Rename learning columns# =========================# 你的 learning 表真实列名是:# cellline, drug, ic50(ln)# 但是为了后面统一处理,我们改成:# cellline, drug_name, ic50learning = learning.rename(columns={ "drug": "drug_name", "ic50(ln)": "ic50"})# 再检查一次,确认改名成功print("learning columns after rename:")print(learning.columns.tolist())# =========================# Step 6. Clean key values# =========================# 清理 drug_name 里的空格learning["drug_name"] = learning["drug_name"].astype(str).str.strip()# 清理 cellline 里的空格learning["cellline"] = learning["cellline"].astype(str).str.strip()# 清理 drug_desc 表里的 drug_namedrug_desc["drug_name"] = drug_desc["drug_name"].astype(str).str.strip()# =========================# Step 7. First merge# =========================# 把 learning 和 drug_desc 按 drug_name 合并# learning 提供 cellline、drug_name、ic50# drug_desc 提供 nacid、alogp、alogp2 等药物描述符merge1 = pd.merge( learning, drug_desc, on="drug_name", how="left")# =========================# Step 8. Check merge result# =========================print("learning:", learning.shape)print("drug_desc:", drug_desc.shape)print("merge1:", merge1.shape)# 查看前几行,确认 descriptor 已经合并进来print( merge1[ ["cellline", "drug_name", "ic50", "nacid", "alogp", "alogp2"] ].head())
## 十一、这段代码背后的药化意义
```text药物结构信息 + 细胞背景信息 + 活性数据```
比如 Random Forest 后面可能会学到:```text高 ALogP 的药物,在某些 mutation 背景下 IC50 更低```
```text某类 PubChem fingerprint 特征和某些细胞系敏感性有关```
```textfeature importancedrug response predictioncell line sensitivity analysismutation based drug response model```
```pythonpd.merge(...)```
很多 AI 项目不是死在模型上,而是死在数据没拼对。十二、给 0 基础学生的一句话
> “老师,这个 column 名字我真没找到。”```pythonprint(df.columns.tolist())```
就像药化里 AI 可以帮你生成分子,但你还是要知道这个结构能不能合成,会不会太油,会不会像一块会走路的凡士林。今天你学会的其实不只是 `rename` 和 `merge`,而是一个科研数据处理的基本姿势:> 先看清数据,再统一名字,再清理内容,最后合并。