跳转到正文
官方

化学数据清洗组合

使用 RDKit 校验并规范化 SMILES,保留原始行、标记重复项,并可选使用 PubChem 补全合法条目的标识。

难度: 中等 费用: 免费 隐私: 取决于配置 ~30 分钟
开始安装

你将能够

  • 保留原数据,标注非法及缺失 SMILES。
  • 标记标准结构重复,可选保留 PubChem CID。

你将构建什么

范围

使用 Python 3.11、RDKit 2025.3.1,可选 PubChemPy 1.0.5。附带脚本保留原字段,新增标准异构 SMILES、校验状态、源行号与重复指向;不删除非法行,不自动去盐、中和电荷或做互变异构标准化。标准 SMILES 代表表述规则,不能证明所有结构在科学上等价。

隐私与输出

基线清洗在本地执行;--pubchem 会向外部 PubChem 发送合法的标准 SMILES,启用前确认数据保密要求。脚本拒绝覆盖已有输出,并在单次运行中缓存重复查询,保留多个 CID 与查询错误,不任意选择匹配。外部查询可能缓慢或限流,不承诺运行耗时。

SMILES 校验与标准表述

RDKit

可选 PubChem 数据补全

PubChemPy

组合组件

RDKit

SMILES 校验与标准表述 · ==2025.3.1

保留立体、电荷与不相连片段;原始输入列不丢失。

费用与许可请核对上游及客户端、服务账号条款。

查看资源

PubChemPy

可选 PubChem 数据补全 · ==1.0.5

仅在 --pubchem 时启用,会向 PubChem 发送合法 SMILES,保留全部返回 CID。

费用与许可请核对上游及客户端、服务账号条款。

查看资源

兼容环境

客户端操作系统架构版本要求
Python macOS不限>= 3.11
Python Windows不限>= 3.11
Python Linux不限>= 3.11

安装与测试

1. 准备小型 CSV 与 Python

全部平台

安装 Python 3.11,使用数据集副本,确保存在唯一 smiles 列并选择新输出文件名;明确是否允许外部 PubChem 补全。

官方来源

预期结果

准备好输入副本与未使用的输出路径。

2. 安装独立 Python 依赖

macOS

在新的工作目录执行。此命令适用于 macOS/Linux,Windows 使用单独步骤。

python3.11 -m venv .venv
.venv/bin/python -m pip install rdkit==2025.3.1 pubchempy==1.0.5
.venv/bin/python -m pip freeze
官方来源

预期结果

依赖安装完成,记录实际解析版本。

3. 安装独立 Python 依赖

Linux

在新的工作目录执行。此命令适用于 macOS/Linux,Windows 使用单独步骤。

python3.11 -m venv .venv
.venv/bin/python -m pip install rdkit==2025.3.1 pubchempy==1.0.5
.venv/bin/python -m pip freeze
官方来源

预期结果

依赖安装完成,记录实际解析版本。

4. 在 Windows 安装 Python 依赖

Windows

使用 PowerShell,直接调用虚拟环境解释器。

py -3.11 -m venv .venv
.\.venv\Scripts\python.exe -m pip install rdkit==2025.3.1 pubchempy==1.0.5
.\.venv\Scripts\python.exe -m pip freeze
官方来源

预期结果

依赖安装完成,记录实际解析版本。

5. 保存清洗脚本

全部平台

保存为 clean_chemical_data.py,检查输出字段,只在明确需要时启用 --pubchem。

"""Preserve original CSV rows while adding RDKit identifiers and optional CIDs.

Sources: https://www.rdkit.org/docs/GettingStartedInPython.html
         https://docs.pubchempy.org/en/latest/guide/searching.html
Source-reviewed example; not executed. No salt removal or charge normalization.
"""
import argparse
import csv
import json
import time
from pathlib import Path

from rdkit import Chem, rdBase


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("input", type=Path)
    parser.add_argument("output", type=Path)
    parser.add_argument("--pubchem", action="store_true")
    args = parser.parse_args()
    added = ["source_row", "canonical_isomeric_smiles", "validation_status",
             "duplicate_of_row", "rdkit_version", "pubchem_cids", "lookup_status", "lookup_error"]
    with args.input.open(encoding="utf-8-sig", newline="") as source:
        reader = csv.DictReader(source)
        fields = reader.fieldnames or []
        if "smiles" not in fields or len(fields) != len(set(fields)) or set(fields).intersection(added):
            parser.error("Require a unique smiles column and no collisions with output columns.")
        seen = {}
        lookup_cache = {}
        # Exclusive creation prevents overwriting either source or existing output.
        with args.output.open("x", encoding="utf-8", newline="") as target:
            writer = csv.DictWriter(target, fieldnames=fields + added)
            writer.writeheader()
            for row_number, row in enumerate(reader, start=2):
                if None in row:
                    parser.error("Malformed CSV row; partial output was retained for inspection.")
                result = dict(row, source_row=row_number, canonical_isomeric_smiles="",
                              validation_status="", duplicate_of_row="", rdkit_version=rdBase.rdkitVersion,
                              pubchem_cids="[]", lookup_status="not_requested", lookup_error="")
                smiles = (row.get("smiles") or "").strip()
                molecule = Chem.MolFromSmiles(smiles) if smiles else None
                if molecule is None:
                    result["validation_status"] = "empty" if not smiles else "invalid"
                else:
                    canonical = Chem.MolToSmiles(molecule, canonical=True, isomericSmiles=True)
                    result["canonical_isomeric_smiles"] = canonical
                    result["validation_status"] = "valid"
                    if canonical in seen:
                        result["duplicate_of_row"] = seen[canonical]
                    else:
                        seen[canonical] = row_number
                    if args.pubchem:
                        if canonical not in lookup_cache:
                            import pubchempy as pcp
                            try:
                                compounds = pcp.get_compounds(canonical, "smiles")
                                cids = sorted({item.cid for item in compounds if item.cid is not None})
                                lookup_cache[canonical] = (json.dumps(cids), "matched" if cids else "not_found", "")
                            except (pcp.PubChemPyError, OSError, ValueError) as error:
                                lookup_cache[canonical] = ("[]", "error", str(error))
                            time.sleep(0.3)
                        result["pubchem_cids"], result["lookup_status"], result["lookup_error"] = lookup_cache[canonical]
                writer.writerow(result)


if __name__ == "__main__":
    main()
官方来源

预期结果

脚本与 .venv 位于同一目录,输入行尚未修改。

6. 保存验收样例

全部平台

保存为 input.csv,包含重复、非法 SMILES、空值与盐结构。

id,smiles
ethanol-a,CCO
ethanol-b,OCC
invalid,not-a-smiles
empty,
salt,CC(=O)[O-].[Na+]
官方来源

预期结果

包含五条数据行。

7. 运行本地清洗

全部平台

Windows 将解释器替换为 ..venv\Scripts\python.exe。本地确定性验收先不添加 --pubchem。

.venv/bin/python clean_chemical_data.py input.csv cleaned.csv
官方来源

预期结果

保留五行:三行合法、一行非法、一行空值;ethanol-b 的重复指向源行 2,盐仍保留点号分隔的钠阳离子与乙酸根;lookup_status 均为 not_requested,输入文件未改动。

8. 按提示词核对输出

全部平台

可作为人工核对清单,或只把公开小样例交给可选助手;上传云端会改变基线隐私边界。

请检查生成的 cleaned.csv,保留原始 id 与 smiles 行,统计合法、非法、空值及重复行。解释 ethanol-a 与 ethanol-b 表示同一分子,检查 salt 行是否保留两个带电片段。不删除原始行、不自动中和或去盐、不推测缺失 PubChem CID,仅依据提供的 CSV 说明。
官方来源

预期结果

解释与实际 CSV 一致,不删除或改造结构。

9. 可选执行 PubChem 补全

全部平台

使用不同输出文件名,记录检索时间并查看 lookup_status/lookup_error;保留多个 CID,不对机密数据调用外部服务。

.venv/bin/python clean_chemical_data.py input.csv enriched.csv --pubchem
官方来源

预期结果

原行数不变,合法行得到实际 CID 列表或明确查询错误。

故障排除

  • CSV 表头错误:使用唯一 smiles 列,避免与新增字段重名。
  • 非法 SMILES:保留原始行,从原来源修正。
  • 输出已存在:选择新文件名,不覆盖输入。
  • PubChem 不可用或限流:保留本地结果与 lookup_error,之后对小批次重试。
  • 多个匹配:保留全部 CID,核对结构后选择。
  • CSV 行格式错误留下部分输出:先检查修正输入,再用新输出名执行。
仍无法运行

替代方案

可不使用 PubChem,仅用 RDKit 本地校验。去盐或互变异构标准化应单独制定科学规则并写入独立输出,不在此脚本中静默改变。