news 2026/10/15 18:05:50

RDKit 信息熵模块深度解析:从 InfoEntropy 到分子指纹位点排序实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RDKit 信息熵模块深度解析:从 InfoEntropy 到分子指纹位点排序实战
  • 科学计算
  • 科研
  • 机器学习

【免费下载链接】rdkit

The official sources for the RDKit library

项目地址:https://gitcode.com/gh_mirrors/rd/rdkit
点击查看免费下载

导读

rdkit.ML.InfoTheory.entropy是 RDKit 机器学习工具集中用于信息论度量的核心模块,它提供了计算信息熵(informational entropy)、信息增益(information gain)与卡方统计量(chi-squared)的完整实现,并在此基础上支撑起分子指纹位点(bit)的活性排序、特征筛选等典型应用。读完本文,你将掌握该模块的纯 Python 实现与 C 加速实现的双层结构、底层数学定义与输入数据约定,并能直接调用InfoBitRanker对带活性标签的指纹集合进行位点排名。

该模块的官方文档入口位于 Docs/Book/source/rdkit.ML.InfoTheory.entropy.rst,实际源码位于 rdkit/ML/InfoTheory/entropy.py。由于该文档采用 Sphinx 的automodule指令动态提取源码 docstring,因此"文档"的实质内容完全等价于源码模块本身,本文以源码为准展开。

模块定位:一套面向化学信息学的信息论度量

entropy.py的开头明确说明:本模块所采用的定义与 Tom Mitchell 的经典著作《Machine Learning》一致,这意味着模块中的熵与信息增益公式遵循标准的香农信息论框架,而不是某种自定义变体。从源码结构看,模块本身是"薄封装"设计:

  1. 纯 Python 参考实现PyInfoEntropy、PyInfoGain;
  2. 尝试导入 C 扩展rdkit.ML.InfoTheory.rdInfoTheory(即编译产物rdInfoTheory);
  3. 若 C 扩展可用,则将InfoEntropy/InfoGain指向 C 版本(hascEntropy = 1),否则回退到纯 Python 版本。
# 摘自 rdkit/ML/InfoTheory/entropy.py try: import rdkit.ML.InfoTheory.rdInfoTheory as cEntropy except ImportError: hascEntropy = 0 else: hascEntropy = 1 if hascEntropy: InfoEntropy = cEntropy.InfoEntropy InfoGain = cEntropy.InfoGain else: InfoEntropy = PyInfoEntropy InfoGain = PyInfoGain

这一"优先 C、回退 Python"的模式保证了功能可用性与运行性能的平衡:C 扩展缺失时(例如仅安装纯 Python 环境)模块依然可以正常工作,只是计算速度较慢。

核心 API:InfoEntropy 与 InfoGain

InfoEntropy:一维计数数组的熵

InfoEntropy(results)接收一个一维计数数组,数组中每个元素表示"某一结果出现的次数"。例如某个函数有 3 种可能结果,命中次数分别为 5、6、1,则传入[5, 6, 1]。

纯 Python 实现的核心逻辑(entropy.py):

def PyInfoEntropy(results): nInstances = float(sum(results)) if nInstances == 0: return 0 # 空输入返回 0 熵 probs = results / nInstances t = numpy.choose(numpy.greater(probs, 0.0), (1, probs)) return sum(-probs * numpy.log(t) / _log2)

其中_log2 = math.log(2),最终结果以bit(以 2 为底)为单位输出。代码中有一段值得注意的细节处理:由于log(0.0)会引发错误,而0 * log(0)在数学约定上应视为 0,模块通过numpy.choose(numpy.greater(probs, 0.0), (1, probs))将概率为 0 的位置替换为 1,从而安全地跳过对数运算。源码注释还保留了一个"更快的风险方案"(给概率加1e-10微小量)作为历史对照,但当前实现选择了数值上完全安全的方案。

InfoGain:二维列联矩阵的增益

PyInfoGain(varMat)接收一个Numeric 二维数组,行对应变量的各个取值,列对应各个可能结果。例如某变量可取 4 个值、结果有 3 种,则varMat为 4×3。内部先按行求和得到variableRes(即 Mitchell 记法中的 $S_v$),按列求和得到overallRes(即 $S$),再计算:

def PyInfoGain(varMat): variableRes = numpy.sum(varMat, 1) # 每行之和 Sv overallRes = numpy.sum(varMat, 0) # 每列之和 S term2 = 0 for i in range(len(variableRes)): term2 = term2 + variableRes[i] * InfoEntropy(varMat[i]) tSum = sum(overallRes) if tSum != 0.0: term2 = 1. / tSum * term2 gain = InfoEntropy(overallRes) - term2 else: gain = 0 return gain

即 $Gain(S, A) = Entropy(S) - \sum_{v \in Values(A)} \frac{|S_v|}{|S|} Entropy(S_v)$。当总样本数为 0 时返回 0,避免除零。

底层原理:C++ 模板实现的同一套公式

当 RDKit 以完整方式编译时,InfoEntropy与InfoGain实际调用的是 C++ 模板函数,定义于 Code/ML/InfoTheory/InfoGainFuncs.h。该头文件位于RDInfoTheory命名空间内,提供三个模板函数:

  • InfoEntropy(T *tPtr, long int dim):先累加nInstances求总样本数,再逐项计算-d * log(d),最后除以log(2.0)换算成以 2 为底的结果;对d == 0的项直接跳过,与 Python 版处理思路一致;
  • InfoEntropyGain(T *dMat, long int dim1, long int dim2):先求行和(variableRes)与列和(overallRes),再按term2 += variableRes[i] * InfoEntropy(该行)累加加权熵,最终gain = InfoEntropy(overallRes) - term2 / tSum,与PyInfoGain数学等价;
  • ChiSquare(T *dMat, long int dim1, long int dim2):按列联表公式 $\chi^2 = \sum_i \frac{N}{R_i}\sum_j \frac{N_{ij}^2}{C_j} - N$ 计算卡方统计量(头文件注释中给出了 3×3 列联表的Nij / Ri / Cj / N符号说明)。

Python 绑定位于 Code/ML/InfoTheory/Wrap/rdInfoTheory.cpp(传统 boost.python 版)与 Code/ML/InfoTheory/nbWrap/rdInfoTheory.cpp(nanobind 版),通过BOOST_PYTHON_MODULE(rdInfoTheory)/NB_MODULE(rdInfoTheory)导出InfoEntropy、InfoGain、ChiSquare三个函数以及InfoBitRanker、BitCorrMatGenerator两个类。模块级 docstring 为:"Module containing bunch of functions for information metrics and a ranker to rank bits"(一组信息度量函数与一个位点排序器)。

输入类型与 dtype 处理

绑定层对输入数组做了严格约束:

  • InfoEntropy要求一维数组(minDim = maxDim = 1),且维度必须大于 0;
  • InfoGain与ChiSquare要求二维数组(minDim = maxDim = 2);
  • 非数组对象会抛出ValueError("Expecting a Numeric array object")。

在 boost.python 版本中,nativeOrDoubleType对NPY_DOUBLE / NPY_FLOAT / NPY_INT / NPY_LONG / NPY_LONGLONG使用原生指针直读,其他类型统一转换为 double;nanobind 版本则显式支持int8/16/32/64、uint8/16/32/64、float、double共 10 种 dtype。这一设计的背景可在 Code/ML/InfoTheory/Wrap/rdInfoTheory.cpp 的注释中看到:NPY_LONG在 Windows 上只有 32 位,而 numpy 默认整数类型是NPY_LONGLONG,历史上曾因类型未被识别而静默返回 0.0(GitHub issue #8421),因此现在对常见 dtype 全覆盖。

实战检验:用测试用例校准你的计算结果

Code/ML/InfoTheory/Wrap/testRanker.py 提供了完整的数值基准,可作为自测标准:

rdit.InfoEntropy(numpy.array([9, 5], float)) # == 0.9403 rdit.InfoEntropy(numpy.array([9, 9], float)) # == 1.0000 rdit.InfoEntropy(numpy.array([5, 0], float)) # == 0.0000(单类别无信息量) rdit.InfoEntropy(numpy.array([5, 5, 5], float)) # == 1.5850(三类别均匀分布) rdit.InfoEntropy(numpy.array([2, 5, 5], float)) # == 1.4834 rdit.InfoGain(numpy.array([[6, 2], [3, 3]], float)) # == 0.0481 rdit.ChiSquare(numpy.array([[6, 2], [3, 3]], float)) # == 0.9333

测试还覆盖了边界情况:全零矩阵[[0,0],[0,0]]的InfoGain为 0,两列完全一致时增益为 0;同时验证了从int8到float64的多种 dtype 下结果一致(testGainFunDtypes)。

实战进阶:InfoBitRanker 指纹位点排序

entropy模块最典型的应用场景是对分子指纹的位点(bit)做活性相关度排序。核心类InfoBitRanker定义于 Code/ML/InfoTheory/InfoBitRanker.h,其用法为"三部曲":

  1. 构造:InfoBitRanker(nBits, nClasses, infoType),其中nBits为指纹长度,nClasses为类别数(类编号约定为 0 到 nClasses-1);
  2. 累加投票:对每个带标签的指纹调用AccumulateVotes(bv, label),统计每个位点在各类别中的命中次数;
  3. 取排名:调用GetTopN(num)返回得分最高的num个位点及其统计量。

四种度量类型

构造器的第三个参数infoType通过枚举InfoType选择度量(InfoBitRanker.h):

枚举值含义底层函数
ENTROPY默认,信息熵增益InfoEntropyGain
BIASENTROPY偏向指定类别的熵增益BiasInfoEntropyGain
CHISQUARE卡方统计量ChiSquare
BIASCHISQUARE偏向指定类别的卡方BiasChiSquareGain

四种模式的分发逻辑位于 InfoBitRanker.cpp 的switch (d_type)语句中。每次计算时,代码将每个位点组织成一个 2×nClasses 的列联表:第一行为"该类命中该位点的样本数",第二行为"该类未命中该位点的样本数"(即d_clsCount[j] - d_counts[j][i]),再交给对应的度量函数。

官方示例:4 个 4 位指纹的排序演示

InfoBitRanker.h 的类注释给出了可直接复现的完整示例。设数据为:

指纹位串 活性标签 0001 0 0101 0 0010 1 1110 1

默认熵增益排序(InfoBitRanker(4, 2)):

>>> ranker = InfoBitRanker(4, 2) >>> for i, bv in enumerate(bvs): ranker.AccumulateVotes(bv, acts[i]) >>> for bit, gain, n0, n1 in ranker.GetTopN(3): ... print(int(bit), '%.3f' % gain, int(n0), int(n1)) 3 1.000 2 0 2 1.000 0 2 0 0.311 0 1

偏向类别 1 的熵增益(InfoBitRanker(4, 2, InfoType.BIASENTROPY)+SetBiasList((1,))):

2 1.000 0 2 0 0.311 0 1 1 0.000 1 1

卡方排序(InfoType.CHISQUARE):

3 4.000 2 0 2 4.000 0 2 0 1.333 0 1

偏向类别 1 的卡方(InfoType.BIASCHISQUARE+SetBiasList((1,))):

2 4.000 0 2 0 1.333 0 1 1 0.000 1 1

GetTopN的返回是一个形状为num × (2 + nClasses)的二维数组,每行依次为:位点 ID、度量得分、各类别命中数。注意num不能超过指纹位数,否则抛出ValueError("attempt to rank more bits than present in the bit vectors")(InfoBitRanker.cpp);若设置了掩码位,num还不能超过掩码位总数。

偏置机制与掩码

SetBiasList(classList)用于 BIASENTROPY / BIASCHISQUARE 模式:只有当偏置类别中至少一个类别的位点命中率不低于所有非偏置类别时,该位点才参与评分。其判定逻辑BiasCheckBit(InfoBitRanker.cpp)先计算各类别命中率fracs[i] = resMat[i] / d_clsCount[i],取非偏置类别的最大命中率maxCor,再检查偏置类别中是否有命中率>= maxCor。这在"活性优先"场景中非常有用——例如你只关心富集活性分子的位点,而不是均衡区分两类。

SetMaskBits(maskBits)则限定只对指定位点集合进行评估,accumulateVotes在计数时会同时检查dp_maskBits掩码(InfoBitRanker.cpp)。此外还提供WriteTopBitsToFile(fileName)将排名结果以表格形式(Bit / InfoContent / class0 / class1 ...)输出到文件。

测试 testRanker.py 中的test1ranker/test2ranker展示了随机指纹上的典型用法:构造 100 个 100 位稀疏指纹,10% 标记为活性(label=1),AccumulateVotes后GetTopN(50);test2ranker验证了SetMaskBits([63, 70, 15, 25, 10])后排名结果恰好是这 5 个位点,且请求GetTopN(10)会抛出异常;test3Issue140/test4Issue237则是针对历史缺陷(如 Linux 上偏置排序导致 core dump)的回归测试。

纯 Python 配套工具:BitRank 模块

如果你的环境没有编译 C 扩展,rdkit/ML/InfoTheory/BitRank.py 提供了纯 Python 的位点分析工具链,它们直接复用entropy.InfoGain:

  • FormCounts(bitVects, actVals, whichBit, nPossibleActs, nPossibleBitVals=2):为单个位点生成 nPossibleBitVals × nPossibleActs 的计数矩阵(内部使用,默认按二值位处理);
  • CalcInfoGains(bitVects, actVals, nPossibleActs, nPossibleBitVals=2):逐个位点调用FormCounts与entropy.InfoGain,返回每个位点的增益数组;
  • RankBits(bitVects, actVals, nPossibleBitVals=2, metricFunc=CalcInfoGains):按增益降序返回位点排序与度量值;
  • AnalyzeSparseVects(bitVects, actVals)/SparseRankBits(...):面向SparseBitVect的稀疏优化版本,只遍历开位(on bits),返回(bit, gain, nAct, nInact)列表。

这些函数要求bitVects与actVals长度一致,否则抛出ValueError('var and activity lists should be the same length')。

延伸组件:BitCorrMatGenerator 与 BitClusterer

排序出"高价值位点"之后,常需要分析位点之间的相关性。BitCorrMatGenerator(Code/ML/InfoTheory/CorrMatGenerator.h)统计指定位点集合中两两同时出现的次数:

cmg = BitCorrMatGenerator() cmg.SetBitList(blist) # 例如:上一轮 GetTopN 选出的位点 for fp in fpList: cmg.CollectVotes(fp) # 支持 ExplicitBitVect / SparseBitVect corrMat = cmg.GetCorrMatrix() # 一维数组,仅含对称矩阵的下三角元素

其 Python 绑定与文档字符串见 Code/ML/InfoTheory/Wrap/BitCorrMatGenerator.cpp。

在此基础上,rdkit/ML/InfoTheory/BitClusterer.py 的BitClusterer类将相关位点聚成簇:ClusterBits(corrMat)先把相关矩阵取倒数转为距离矩阵(distMat = 1 / corrMat),再交给rdSimDivPickers的HierarchicalClusterPicker做层次聚类(默认ClusterMethod.WARD);随后可用MapToClusterScores(fp)把指纹映射为"每个簇命中位数"的实值向量,或用MapToClusterFP(fp)压缩成更小尺寸的簇级指纹——这一步可以把数百个原始位点浓缩成少量去相关特征,供下游建模使用。

小结与使用建议

rdkit.ML.InfoTheory.entropy及其配套的InfoBitRanker、BitCorrMatGenerator构成了 RDKit 中一套完整的信息论特征筛选流水线:

  1. 用InfoEntropy/InfoGain/ChiSquare快速评估任意变量与结果的相关强度;
  2. 用InfoBitRanker对带活性标签的指纹集合做位点排序,通过BIASENTROPY/BIASCHISQUARE实现活性偏向,通过SetMaskBits限定候选集;
  3. 用BitCorrMatGenerator+BitClusterer消除位点冗余,压缩特征空间。

实际使用时注意三点:输入数组必须为 numpy 数组且维度正确(一维给InfoEntropy,二维给InfoGain/ChiSquare);GetTopN的请求数量不能超过指纹位数或掩码位总数;偏置模式下类 ID 必须在[0, nClasses)范围内且不能重复。如需验证实现正确性,可对照 testRanker.py 中给出的数值基准(如InfoEntropy([9,5]) = 0.9403、InfoGain([[6,2],[3,3]]) = 0.0481)逐项核对。

  • 科学计算
  • 科研
  • 机器学习

【免费下载链接】rdkit

The official sources for the RDKit library

项目地址:https://gitcode.com/gh_mirrors/rd/rdkit
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 18:04:53

DLMS协议C#实现:HDLC帧、COSEM协变量与AA-1认证全解析

简介:本资源是一套基于C#实现的DLMS协议电能表数据采集源代码,面向具备.NET开发基础、需对接智能电表的嵌入式或能源管理系统开发者。代码严格遵循IEC 62056标准,完整覆盖DLMS客户端构建、APDU编解码、LN/SN双模式对象寻址、HDLC/LLC链路层封…

作者头像 李华
网站建设 2026/10/15 18:04:04

FANUC机器人伺服焊枪配网配置详解:从通信架构到实操避坑

简介:面向工业机器人集成与自动化工程师的FANUC伺服焊枪配置及配网技术文档,围绕点焊机器人伺服焊枪的添加、运动方向设置、零点标定、自动调整、厚度检查与压力标定等全流程展开,同时涵盖PROFINET网络下的配网组态、DO/DI信号与DCS配置&…

作者头像 李华
网站建设 2026/10/15 18:02:24

基于D3D的YV12视频渲染:GPU纹理与Shader实现高性能上屏

简介:在视频播放与监控上屏开发中,YUV色彩空间转换是决定性能的关键环节。以YV12为代表的4:2:0平面格式,若在CPU中逐像素转换为RGB,会导致高占用与帧率下降。基于D3D纹理上传与像素着色器(Shader)的GPU渲染…

作者头像 李华
网站建设 2026/10/15 18:02:16

把 GoAnime 当库用:pkg/goanime 客户端二次开发完全指南

【免费下载链接】GoAnime Search, stream and download anime, movies and TV shows from the terminal, in English and Brazilian Portuguese. 项目地址: https://gitcode.com/gh_mirrors/go/GoAnime 点击查看 免费下载 GoAnime 是一款在终端搜索、流媒体播放和下…

作者头像 李华