From f9d523904bb5d71ced0ab054f99be0ef9b48d32d Mon Sep 17 00:00:00 2001 From: luozhouyang Date: Fri, 21 May 2021 00:22:33 +0800 Subject: [PATCH] Update README --- README.md | 219 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 202 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index eb0e3eb..7f9b7b5 100644 --- a/README.md +++ b/README.md @@ -16,32 +16,25 @@ Automated Phrase Mining from Massive Text Corpora in Python. pip install -U autophrasex ``` -## 使用 +## 基本使用 ```python from autophrasex import * - -# 构造需要抽取的特征 -N = 4 -ngrams_extractor = NgramsExtractor(N=N) -idf_extractor = IDFExtractor() -entropy_extractor = EntropyExtractor() - -# 读取语料,处理语料&统计信息 -reader = DefaultCorpusReader( - tokenizer=BaiduLacTokenizer(), - extractors=[ngrams_extractor, idf_extractor, entropy_extractor]) -reader.read(corpus_files=['data/DBLP.5K.txt'], N=N, verbose=True, logsteps=500) - -# 构造AutoPhrase,短语选择&特征构造 +# 构造autophrase autophrase = AutoPhrase( - selector=DefaultPhraseSelector(ngrams_extractor=ngrams_extractor), - composer=DefaultFeatureComposer(idf_extractor, ngrams_extractor, entropy_extractor), + reader=DefaultCorpusReader(tokenizer=JiebaTokenizer()), + selector=DefaultPhraseSelector(), + extractors=[ + NgramsExtractor(N=N), + IDFExtractor(), + EntropyExtractor() + ] ) # 开始挖掘 predictions = autophrase.mine( + corpus_files=['data/answers.10000.txt'], quality_phrase_files='data/wiki_quality.txt', callbacks=[ LoggingCallback(), @@ -55,10 +48,202 @@ for pred in predictions: ``` + +## 高级用法 + 本项目的各个关键步骤都是可以扩展的,所以大家可以自由实现自己的逻辑。 +本项目大体上可以氛围以下几个主要模块: + +* `tokenizer`分词器模块 +* `reader`语料读取模块 +* `selector`高频短语的选择模块 +* `extractors`特征抽取器,用于抽取分类器所需要的特征 +* `callbacks`挖掘周期的回调模块 + +以下是每个模块的高级使用方法。 + +### tokenizer + +`tokenizer`用于文本分词,用户可以继承`AbstractTokenizer`实现自己的分词器。本库自带`JiebaTokenizer`。 + +例如,你可以使用`baidu/LAC`来进行中文分词。你可以这样实现分词器: + +```bash +# pip install lac + +class BaiduLacTokenizer(AbstractTokenizer): + + def __init__(self, custom_vocab_path=None, model_path=None, mode='seg', use_cuda=False, **kwargs): + self.lac = LAC(model_path=model_path, mode=mode, use_cuda=use_cuda) + logging.info('LAC initialized successfully.') + if custom_vocab_path: + self.lac.load_customization(custom_vocab_path) + logging.info('LAC load custom vocab successfully.') + + def tokenize(self, text, **kwargs): + text = self._uniform_text(text, **kwargs) + results = self.lac.run(text) + results = [x.strip() for x in results if x.strip()] + return results +``` + +然后在构建`reader`的使用使用`BaiduLacTokenizer`: +```python +reader = DefaultCorpusReader(tokenizer=BaiduLacTokenizer()) +``` + +### reader + +`reader`用于读取语料,用户可以继承`AbstractCorpusReader`实现自己的Reader。本库自带`DefaultCorpusReader`。 + +因为目前的`extractor`其实是依赖`reader`的(具体来说是`extractor`实现了`reader`的生命周期回调接口),因此想要重写`reader`,在有些情况下需要同时更改`extractor`的实现,此时自定义成本比较大,暂时不推荐重写`reader`。 + +### selector + +`selector`用于选择高频Phrase,用户可以继承`AbstractPhraseSelector`实现自己的Phrase选择器。本库自带`DefaultPhraseSelector`。 + +`selector`可以拥有多个`phrase_filter`,用于实现Phrase的过滤。关于`phrase_filter`本库提供了开放的接口,用户可以继承`AbstractPhraseFilter`实现自己的过滤器。本库自带了默认的过滤器`DefaultPhraseFilter`,并且在默认情况下使用。 + +如果你想要禁用默认的过滤器,转而使用自己实现的过滤器,可以在构造`selector`的时候设置: + +```python +# 自定义过滤器 +class MyPhraseFilter(AbstractPhraseFilter): + + def apply(self, pair, **kwargs): + phrase, freq = pair + # return True to filter this phrase + if is_verb(phrase): + return True + return False + +selector = DefaultPhraseSelector( + phrase_filters=[MyPhraseFilter()], + use_default_phrase_filters=False +) +``` + +考虑到有些过滤过程,使用按批处理可以显著提升速度(例如使用深度学习模型计算词性),`phrase_filter`提供了一个`batch_apply`方法。 + +举个例子,使用`baidu/LAC`来计算词性,从而实现Phrase的过滤: + +```python + +class VerbPhraseFilter(AbstractPhraseFilter): + + def __init__(self, batch_size=100): + super().__init__() + self.lac = LAC() + self.batch_size = batch_size + + def batch_apply(self, batch_pairs, **kwargs): + predictions = [] + for i in range(0, len(batch_pairs), self.batch_size): + batch_texts = [x[0] for x in batch_pairs[i: i + self.batch_size]] + batch_preds = self.lac.run(batch_texts) + predictions.extend(batch_preds) + candidates = [] + for i in range(len(predictions)): + _, pos_tags = predictions[i] + if any(pos in ['v', 'vn', 'vd'] for pos in pos_tags): + continue + candidates.append(batch_pairs[i]) + return candidates + +selector = DefaultPhraseSelector( + phrase_filters=[VerbPhraseFilter()], + use_default_phrase_filters=False +) +``` + +### extractor + +`extractor`用于抽取分类器的特征。特征抽取器会在`reader`读取语料的时候进行必要信息的统计。因此`extractor`实现了`reader`的回调接口,所以在自定义特征抽取器的时候,需要同时继承`AbstractCorpusReadCallback`和`AbstractFeatureExtractor`。 + +本库自带了以下几个特征抽取器: + +* `NgramExtractor`,`n-gram`特征抽取器,可以计算phrase的`pmi`特征 +* `IDFExtractor`,`idf`特征抽取器,可以计算phrase的`doc_freq`、`idf`特征 +* `EntropyExtractor`,`熵`特征抽取器,可以计算phrase的`左右熵`特征 + +上述自带的特征抽取器,都是基于`n-gram`统计的,因此都支持`ngram`的选择,也就是都可以自定义`ngram_filter`来过滤不需要统计的`ngram`。本库自带了`DefaultNgramFilter`,并且默认启用。用户可以实现自己的`ngram_filter`来灵活选取合适的`ngram`。 + +举个例子,我需要过滤掉`包含标点符号`的`ngram`: + +```python +CHARACTERS = set('!"#$%&\'()*+,-./:;?@[\\]^_`{|}~ \t\n\r\x0b\x0c,。?:“”【】「」') + +class MyNgramFilter(AbstractNgramFiter): + + def apply(self, ngram, **kwargs): + if any(x in CHARACTERS for x in ngram): + return True + return False + +autophrase = AutoPhrase( + reader=DefaultCorpusReader(tokenizer=JiebaTokenizer()), + selector=DefaultPhraseSelector(), + extractors=[ + NgramsExtractor(N=N, ngram_filters=[MyNgramFilter()]), + IDFExtractor(ngram_filters=[MyNgramFilter()]), + EntropyExtractor(ngram_filters=[MyNgramFilter()]), + ] +) +# 开始挖掘 +... +``` + +用户可以继承`AbstractFeatureExtractor`实现自己的特征计算。只需要在构建autophrase实例的时候,把这些特征计算器传入即可,不需要做其他任何额外操作。 + +举个例子,我增加一个`phrase是否是unigram`的特征: + +```python +class UnigramFeatureExtractor(AbstractFeatureExtractor,AbstractCorpusReadCallback): + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + def extract(self, phrase, **kwargs): + parts = phrase.split(' ') + features = { + 'is_unigram': 1 if len(parts) == 1 else 0 + } + return features + + +autophrase = AutoPhrase( + reader=DefaultCorpusReader(tokenizer=JiebaTokenizer()), + selector=DefaultPhraseSelector(), + extractors=[ + NgramsExtractor(N=N), + IDFExtractor(), + EntropyExtractor(), + UnigramFeatureExtractor(), + ] +) + +# 可以开始挖掘了 +... +``` + +### callback + +`callback`回调接口,可以提供phrase挖掘过程中的生命周期监听,并且实现一些稍微复杂的功能,例如`EarlyStopping`、`判断阈值Schedule`等。 + +本库自带以下回调: + +* `LoggingCallback`提供挖掘过程的日志信息打印 +* `ConstantThresholdScheduler`在训练过程中调整阈值的回调 +* `EarlyStopping`早停,在指标没有改善的情况下停止训练 + +用户可以自己继承`Callback`实现自己的逻辑。 + + ## 结果示例 +> 以下结果属于本库比较早期的测试效果,目前本库的代码更新比较大,返回结果和下述内容不太一致。仅供参考。 + 新闻语料上的抽取结果示例: ```bash