在.NET中使用机器学习API(ML.NET)实现化学分子式数据格式的判定

By | 2018年9月15日

在工作中遇到一个问题,就是如何判断化学分子式的数据格式。在介绍“如何”这个问题之前,先简单介绍一下化学分子式的数据格式。通常情况下,计算机处理化学分子式,也都是将分子式序列化成一种数据模型,然后对这个数据模型进行处理。比如:水分子H2O,就由两个氢原子和一个氧原子组成,氢和氧之间有化学键相连,于是,就有了原子、键和分子的概念。只需要定义一种模型,能够表达原子、分子、键以及它们之间的关系,就可以让计算机进行处理了。

这样的模型让计算机读懂是很容易的,可是,阅读这样的数据结构,人类却并不在行。因此,国际上定义了一些标准,通过特定的规则,使得化学分子式能够以字符串的形式表达。常见的字符串格式有:

  • Simplified molecular-input line-entry system(SMILES):比如:水分子的SMILES字符串就是O,而苯环的SMILES则是C1=CC=CC=C1
  • BASE64 CDX:CDX是由PerkinElmer公司的ChemDraw软件所原生支持的数据格式,它也是国际标准。CDX本身是二进制的数据类型,但是在信息系统中,往往也会将它通过BASE64转码,然后进行存取和处理。因此,转码之后的BASE64就是一个字符串
  • CDXML:CDXML也是由PerkinElmer公司的ChemDraw软件所原生支持的数据格式,它也是国际标准,与CDX不同的是,它以XML的形式来描述化学分子式
  • CTAB:它最初是由MDL Information Systems公司创建的数据格式,目前也是业界标准,它包含V2000和V3000两个版本

事实上,能够描述化学分子式的标识字符串不止以上这些,还有比如INCHI等等,此外,还有一些标识字符串(Annotations),它们可以对大分子(比如DNA、RNA)进行描述,比如Pistoia Alliance的HELM。这里也就不多讨论了,总之,一条化学分子式的数据,可以有多种字符串表现形式。

在使用机器学习之前,判断化学分子式的数据格式基本上是对字符串的格式进行分析,根据国际标准规范来认定字符串所指代的化学分子式的数据格式。比如,通过确认某个字符串是一个合法的BASE64字符串,从而确定它就是BASE64 CDX格式。这种做法其实还是挺有效的,因为国际规范基本上不太会变化,而且各种类型的数据格式差异也还是挺大的,因此,在实际项目中,我们都是采用这种方式来确定数据格式。

接下来,让我们来看看如何使用机器学习来实现化学分子式数据格式的判定。首先,我们需要有一些样本数据,通过这些样本数据来训练设定的数据模型,然后,使用这个训练后的模型对给定的输入数据进行预测。我们可以设计如下的样本数据:

[O-]C(CCCCCCCCCCCCCCCCC)=O.[Na+]	SMILES
O=C(C1)N(C2[C@@]3(CC4)[C@](N4C5)([H])C[C@@]6([H])C5=CCOC1[C@]62[H])C7=C3C=CC=C7.O[N+]([O-])=O	SMILES
O=C(O)C1(N(CCOC)CCOC)CCC(C)CC1	SMILES
CN(C)C(C)CC(C1=CC=CC=C1)(C(CC)=O)C2=CC=CC=C2	SMILES
NCC1(CCC(CCC)CC1)N(C)CC2=COC=C2	SMILES
InChI=1S/C2H4O2.CH4O/c1-2(3)4;1-2/h1H3,(H,3,4);2H,1H3	INCHI
InChI=1S/C2H4O2.BrH/c1-2(3)4;/h1H3,(H,3,4);1H	INCHI
.......

在这个样本中,每一行包含两个列:第一个列就是分子式的数据,第二个列就是数据格式,两个列用TAB分隔,当然也可以用逗号分隔,不过在这里的INCHI的样本数据中,已经包含了逗号,所以用TAB进行分隔会更方便。这个文件的内容主要就是为了告诉机器学习算法,第一行的数据是SMILES格式,最后一行的数据是INCHI格式等等。这个文件包含的数据量越大,训练出来的模型精确度也越高,误判的可能性也就越小。在上面的例子中,并没有把所有的行都列出来,所以最后我用省略号表示后面还有很多行数据。

现在,打开Visual Studio,创建一个控制台应用程序,通过NuGet添加对Microsoft.ML程序集的引用,然后,定义两个数据模型:

public class StructureData
{
    [Column("0")]
    public string Structure;

    [Column("1")]
    [ColumnName("Label")]
    public string Label;
}

public class PredictedData
{
    [ColumnName("PredictedLabel")]
    public string PredictedLabels;
}

StructureData数据模型表示我们的样本数据,它包括两个列:Structure列对应上面样本数据中的第一列,而Label列对应上面样本中的第二列,在机器学习过程中,会读入这个样本文件,然后将对应的列映射上去。而PredictedData数据模型则保存了最终的预测结果。下面看看如何使用这两个数据模型,并结合样本数据进行预测:

static void Main(string[] args)
{
    // 创建机器学习管道对象
    var pipeline = new LearningPipeline();
    // 读入样本数据
    pipeline.Add(new TextLoader("data.txt").CreateFrom<StructureData>());
    // 设置基于Label字段进行分类
    pipeline.Add(new Dictionarizer("Label"));
    // 设置Structure字段作为建模考虑因素
    pipeline.Add(new TextFeaturizer("Features", "Structure"));
    // 选择合适的数据分类器
    pipeline.Add(new StochasticDualCoordinateAscentClassifier());
    // 指定输出
    pipeline.Add(new PredictedLabelColumnOriginalValueConverter()
    {
        PredictedLabelColumn = "PredictedLabel"
    });
    // 基于样本数据训练模型
    var model = pipeline.Train<StructureData, PredictedData>();
    // 基于训练模型进行预测
    var prediction = model.Predict(new StructureData
    {
        Structure = "C(C(=O)COP(=O)(O)O)N"
    });
    // 输出预测结果
    Console.WriteLine(prediction.PredictedLabels);
}

上面的代码中,指定数据的分类会基于StructureData的Label字段,而会把Structure列的数据作为考虑因素,也就是Structure列的数据会成为决定Label取值的一个因素。使用TextFeaturizer,使得机器学习算法会将Structure列的字符串量化成数值然后参与计算。接下来,选择合适的数据分类器,比如这里的StochasticDualCoordinateAscentClassifier,然后就是基于样本数据进行训练,最后就是使用训练好的模型,对用户的输入数据进行预测,来判定化学分子式的数据格式。

运行这个程序,可以看到,程序输出了预期的结果:

image

可以看到,使用ML.NET框架(也就是Microsoft.ML)通过机器学习来解决实际问题是多么的容易。事实上,模型的训练应该是只执行一次,并且能够将模型序列化保存下来,在实际应用程序中,只需要读入这个模型,然后直接进行预测即可,没必要每次都进行训练。今后我还会继续深入学习ML.NET,争取分享更多有趣的应用案例。

【点击此处下载本文案例代码】

(总访问量:914;当日访问量:1)

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据