当前位置: 首页 > 知识库问答 >
问题:

如何为机器学习的任意特征提取创建模块化且可扩展的代码?

衡玄裳
2023-03-14

我一直在努力创建一个Python模块,该模块执行特征提取,最终被机器学习算法使用。

我的方法是用(手工制作的)特征来增强最初的黄金标准数据集,从而创建一个新的数据集,这样训练就不涉及任何特征创建,这可能很昂贵。我相信这是大多数数据集的规范——总是包含核心特征(例如词性标签、命名实体标签、语义标签等)。

我使用的数据集只包括所有标记的句子,格式为XML标记。例如:

<s>
  <lex begin='351' end='354'>The</lex>
  <lex begin='355' end='361'>people</lex>
  <lex begin='362' end='366'>here</lex>
  <lex begin='367' end='370'>are</lex>
  <lex begin='371' end='374'>far</lex>
  <lex begin='375' end='384'>wealthier</lex>
  <lex begin='384' end='385'>.</lex>
</s>

我想为每个标记添加其他信息,例如词性、NER、语义标签等。

我一直在使用斯坦福NLP POS标记器和斯坦福NLP NER标记器。这些速度非常慢,但(希望)速度提供了更准确的POS和NER标签。我还加入了另一个解析器来获取语义标签。下面是新句子,增加了功能。

<s>
    <lex ner='O' begin='351' end='354' pos='DT' label='None'>The</lex>
    <lex CATEGORY='#ref-category PERSON' begin='355' end='361'
        FORM='#ref-category COMMON-NOUN/PLURAL' ENDS-AT='#edges ending at 3'
        CONSTITUENTS='NIL' USED-IN='NIL' Type='SPARSER::EDGE' LEFT-DAUGHTER='#word "people"'
        pos='NNS' RULE='#PSR577  person -  "people"' label='SPATIAL_ENTITY'
        REFERENT='#people 1' POSITION-IN-RESOURCE-ARRAY='1' SPANNED-WORDS='NIL'
        RIGHT-DAUGHTER=':SINGLE-TERM' ner='O' Class='#STRUCTURE-CLASS SPARSER::EDGE'
        STARTS-AT='#edges starting at 2'>people</lex>
    <lex CATEGORY='#ref-category DEICTIC-LOCATION' begin='362' end='366'
        FORM='#ref-category PROPER-NOUN' ENDS-AT='#edges ending at 4'
        CONSTITUENTS='NIL' USED-IN='NIL' Type='SPARSER::EDGE' LEFT-DAUGHTER='#word "here"'
        pos='RB' RULE='#PSR271  deictic-location -  "here"' label='PLACE'
        REFERENT='#deictic-location "here" 3' POSITION-IN-RESOURCE-ARRAY='3'
        SPANNED-WORDS='NIL' RIGHT-DAUGHTER=':SINGLE-TERM' ner='O'
        Class='#STRUCTURE-CLASS SPARSER::EDGE' STARTS-AT='#edges starting at 3'>here</lex>
    <lex CATEGORY='#ref-category BE' begin='367' end='370'
        FORM='#ref-category VERB' ENDS-AT='#edges ending at 5' CONSTITUENTS='NIL'
        USED-IN='NIL' Type='SPARSER::EDGE' LEFT-DAUGHTER='#word "are"' pos='VBP'
        RULE='#PSR145  be -  "are"' label='None' REFERENT='#be 1'
        POSITION-IN-RESOURCE-ARRAY='4' SPANNED-WORDS='NIL' RIGHT-DAUGHTER=':SINGLE-TERM'
        ner='O' Class='#STRUCTURE-CLASS SPARSER::EDGE' STARTS-AT='#edges starting at 4'>are</lex>
    <lex CATEGORY='#word "far"' begin='371' end='374'
        FORM='#ref-category SPATIAL-PREPOSITION' ENDS-AT='#edges ending at 6'
        CONSTITUENTS='NIL' USED-IN='NIL' Type='SPARSER::EDGE' LEFT-DAUGHTER='#word "far"'
        pos='RB' RULE='(5)' label='None' REFERENT='#word "far"'
        POSITION-IN-RESOURCE-ARRAY='5' SPANNED-WORDS='NIL' RIGHT-DAUGHTER=':LITERAL-IN-A-RULE'
        ner='O' Class='#STRUCTURE-CLASS SPARSER::EDGE' STARTS-AT='#edges starting at 5'>far</lex>
    <lex ner='O' begin='375' end='384' pos='JJR' label='None'>wealthier</lex>
    <lex begin='384' end='385'>.</lex>
</s>

显然,它不再是真正的人类可读的,但这并不重要,因为这些只是要传输到机器学习算法的特征。

出于我的目的,我应该只需要做一次,并且可以在培训之前添加更便宜的功能,例如单词是否大写。

然而,我目前的解决方案非常糟糕,我不确定如何重新考虑它,以便将来有人可以轻松地加入自己的钩子/函数(例如,他们希望快速添加来自其他解析器的新特性)。以下是我的工作解决方案:

xml_tokens_pattern = re.compile(r'<TOKENS>.+</TOKENS>', re.DOTALL)
sentence_pattern = re.compile(r'<s>.+?</s>', re.DOTALL)
lex_attrs_pattern = re.compile(r'(?<=<lex)[^>]+')

class Feature_Process(object):
    """Wrapper for adding features to xmls.

    """
    def __init__(self, xmls, golddir, newdir='', suffix='++',
                 feature_functions=[], renew=False, debug=False):
        self.xmls = xmls
        self.golddir = golddir
        self.newdir = newdir
        self.suffix = suffix
        self.feature_functions = feature_functions
        self.renew = renew
        self.debug = debug
        self.heavy = False

    def process(self):
        for xml in self.xmls:
            path = setup_newdir(xml, self.golddir, self.newdir,
                                self.suffix, self.renew)
            if not path:
                continue
            mkparentdirs(path)
            with open(xml, 'r') as oldfile:
                text = oldfile.read()
            doc = Space_Document(xml)
            tags = [tag for tag in doc.tags if 'start' in tag.attrib]
            new_text = text
            for (i,m) in enumerate(re.finditer(sentence_pattern, text)):
                sentence = doc.sentences[i]
                doc_lexes = sentence.getchildren()
                xml_sentence = m.group()
                tokens = [''.join([c if ord(c) < 128
                                   else u2ascii[c]
                                   for c in x.text]).encode('utf-8')
                          for x in doc_lexes]
                (pos_tags, ner_tags, edges) = ([], [], [])
                if self.heavy:
                    pos_tags = pos.tag(tokens)
                    ner_tags = ner.tag(tokens)
                    try:
                        if self.debug:
                            print ' '.join([x for x in tokens])
                        edges = p(' '.join([x for x in tokens]), split=True)
                    except:
                        'somehow got here'
                c = 0
                for (j, n) in enumerate(re.finditer(lex_attrs_pattern,
                                                    xml_sentence)):
                    doc_lex = doc_lexes[j]
                    new_lex = Lex(doc_lex.text, doc_lex.attrib)
                    attributes = n.group()
                    tag = binary_search((int(doc_lex.attrib['begin']),
                                         int(doc_lex.attrib['end']),
                                         doc_lex.text), tags)
                    label = 'None'
                    if type(tag) != type(None):
                        label = tag.tag
                    new_lex.add(('label', label))
                    new_lex.add(('word', new_lex.text.encode('utf-8')))
                    if type(tag) != type(None):
                            new_lex.addAll([(key, tag.attrib[key]) for key in tag.attrib])
                    if pos_tags:
                        if tokens[j] == pos_tags[c][0]:
                            new_lex.add(('pos', pos_tags[c][1]))
                            pos_tags.remove(pos_tags[c])
                    if ner_tags: #this error case comes up for RFC/Durango.xml
                        if tokens[j] == ner_tags[c][0]:
                            new_lex.add(('ner', ner_tags[c][1]))
                            ner_tags.remove(ner_tags[c])
                    if edges:
                        sparser_edge = ledge(edges, tokens[j])
                        if sparser_edge:
                            if sparser_edge.keyvalues:
                                keyvalues = sparser_edge.keyvalues[sparser_edge.keyvalues.keys()[0]]
                                new_lex.addAll([(key, keyvalues[key]) for key in keyvalues])
                    new_lex.addAll([function(new_lex) for function in self.feature_functions])
                    new_text = new_text.replace(attributes, str(new_lex))
            w = open(path, 'w')
            print>>w, new_text
            w.close()

共有1个答案

卫阳曜
2023-03-14

首先,如果要使用XML作为源和目标,那么手动解析XML几乎总是一个错误。使用Python XML解析库(其中有几个库)来生成可以操作的结构或流。

如果您的主要目标是提供一个API来添加可由分类器解释的词法特征,那么我唯一的建议就是将序列化/反序列化与数据结构的操作明确分开。但对于这样一个简单的案例,这并不特别困难。

 类似资料:
  • 我一直在和一个朋友争论“特征提取”。他说,ML的主要任务是提取特征。但我不同意。一般来说,特征提取不是一项ML任务。如果我们认为wx b是表示ML的最简单的方法,那么ML的任务就是找到最好的w和b。x是特征。ML试图找出给定x的最佳w和b值,它与训练数据匹配,从而学习如何找到w和b。 我的朋友说提取特征是ML的核心任务。但据我所知,特征提取主要是一项数据预处理任务。

  • 在机器学习中,灰度图像的特征提取是一个难题。 我有一个灰色的图像,是用这个从彩色图像转换而来的。 我实际上需要从这张灰色图片中提取特征,因为下一部分将训练一个具有该特征的模型,以预测图像的彩色形式。 我们不能使用任何深度学习库 有一些方法,如快速筛选球。。。但我真的不知道如何才能为我的目标提取特征。 以上代码的输出就是真的。 有什么解决方案或想法吗?我该怎么办?

  • 主成分分析是一种降维方法,通过将一个大的特征集转换成一个较小的特征集,这个特征集仍然包含了原始数据中的大部分信息,从而降低了原始数据的维数。换句话说就是减少数据集的特征数量,同时尽可能地保留信息。降维是将训练数据中的样本(实例)从高维空间转换到低维空间,该过程与信息论中有损压缩概念密切相关。同时要明白的,不存在完全无损的降维。

  • 假设我有两组不同的特性A和B。我正在尝试确定哪一组特性是最好的。由于我的数据集很小,所以我使用了漏掉一个交叉验证作为最终指标。我正试图弄清楚我的实验装置,我在以下几种方式中做出选择: 1) 将特征集A赋予我的分类器(并可选地运行特征选择),将特征集B赋予同一分类器(也可选地运行特征选择),然后比较这两个分类器之间的LOOCV错误? 2) 将特征集A和B赋予分类器,然后明确地对其进行特征选择,然后根

  • 我有一个proto,它有一条包含扩展名的消息 我有另一个proto,它有扩展(只显示下面的一个扩展) 通过protobuf代码,我能够获得MsgB的描述符和FileDescriptor,并从中检索FieldDescriptor类型的扩展名“MsgB”。我通过protobuf代码查找扩展,而不是使用MsgB协议生成的代码,因为我试图迭代所有扩展消息,而不是将每个消息硬编码为可变扩展。(我理解Muta

  • 我有一个设计问题,当使用类似的东西时: 我认为应该有一些更好的方法来实现这种参数化的特性。 我在std中没有找到好的示例(例如,在具有类似的关联类型的traits中没有实现)?