信息抽取Python算法总结:词库匹配,词向量,TFIDF,机器学习,深度学习(持续更)

信息提取(Information Extraction)
把文本里包含的信息进行结构化处理,变成表格一样的组织形式。
本文的信息抽取主要是【关键词、主题、词组】抽取。

1、纯规则

1.1、词典匹配

from jieba import cut
lexicon = {
    
    '剑圣', '大法师', '守望者', '山丘之王'}
def extract(text): return [w for w in cut(text)if w in lexicon]
print(extract('剑圣斩杀大法师'))

1.2、正则表达式+预设权重

import re
from collections import Counter

# 否定正则表达式
RE_NEGATION = re.compile(r'(?<![无没])不[^a-z\W\d_限无]|除[\u4e00-\u9fa5、a-z\d]*?外|?', re.I)
RE_EXCLUSION = re.compile('([^)]*(不含|不包含|不包括|不列入|除[^)。;!?]*外|以外|禁止|限制)[^)]*)')

def clean_exclusion(x):
    """括号里排除"""
    return RE_EXCLUSION.sub(' ', x)

RE = (
    (re.compile('中小企业(?!数量)'), {
    
    '中型企业': 20, '小型企业': 20, '个人': -1}),
    (re.compile('大中企业(?!数量)'), {
    
    '大型企业': 10, '中型企业': 20, '个人': -1}),
    (re.compile('小微企业(?!数量)'), {
    
    '小型企业': 10, '微型企业': 5, '个人': -1}),
    (re.compile('(个人|人才)[\u4e00-\u9fa5、()]*补贴'), {
    
    '个人': 5}),
)

def text2sentence(text):
    text = clean_exclusion(text)  # 清除否定短句
    for sentence in re.split('[\n。…;;!!??]+', text):
        if not RE_NEGATION.search(sentence):  # 过滤否定句
            yield sentence

def ner_theme(text, weight=1):
    c = Counter()
    for sentence in text2sentence(text):
        for rec, themes in RE:
            if rec.search(sentence):
                for theme, score in themes.items():
                    c[theme] += score * weight
    return c.most_common()

if __name__ == '__main__':
    for _text in '''
    江门市人才举荐类补贴
    小微企业吸纳高校毕业生社保补贴(不含大中企业)
    大中企业奖励。不包括小微企业
    '''.strip().split():
        print(_text, ner_theme(_text))

1.3、预设多层权重(有向无环图)

0.5
0.5
0.5
0.5
0.5
0.5
0.3
句子
匹配出关键词
关键词映射到实体
实体间相互作用
过滤
例如
AI之NLP的LDA
AI
NLP
LDA
图像识别
自然语言处理
神经语言程序学
主题模型
线性判别式分析
自然语言处理
主题模型
线性判别式分析
1.0
0.8
from jieba import cut  # 带词性分词
from collections import Counter

THRESHOLD = .7
NAME2THEME = {
    
    
    '图像识别': {
    
    '图像识别': 1, '自然语言处理': -1},
    '自然语言处理': {
    
    '自然语言处理': 1, '图像识别': -1},
    'AI': {
    
    '图像识别': .5, '自然语言处理': .5},
    'NLP': {
    
    '自然语言处理': .5, '神经语言程序学': .5},
    'LDA': {
    
    '主题模型': .5, '线性判别式分析': .5},
}
RELATION = {
    
    
    '自然语言处理': {
    
    '主题模型': 1.6, '词向量': 1.6},
    '图像识别': {
    
    '卷积神经网络': 2, '长短期记忆网络': .5},
}

def relation(c):
    print(c)
    for theme, themes2weight in RELATION.items():
        if theme in c:
            for theme2, weight in themes2weight.items():
                if theme2 in c:
                    c[theme2] *= weight
    print(c)
    return c

def extract(text):
    # 词库匹配,统计
    c0 = Counter(w for w in cut(text) if w in NAME2THEME)
    # 关键词转目标
    c1 = Counter()
    for name, freq in c0.items():
        for theme, weight in NAME2THEME[name].items():
            c1[theme] += freq * weight
    # 内联修改得分
    c1 = relation(c1)
    # 设定阈值
    return [i for i in c1.most_common() if i[1] > THRESHOLD]

text1 = 'AI之NLP的LDA'
print(text1, extract(text1))

2、词典匹配+词向量

2.1、匹配范围扩大

生成
聚合
1
0.8
0.7
1
1
0.64
0.49
1
词库
词库+词向量相近词
词库
例如
图像识别
图像识别
人工智能
自然语言处理
自然语言处理
图像识别
自然语言处理
from re import split
import jieba
from gensim.models import Word2Vec
from collections import Counter

THRESHOLD = 0.6
STOP_WORDS = set('了是在和有他我的也为就这都等着来与要又而一个之以她去那但把我们可他们并或由其给使却它及此们即因呢该每应吧')


def texts2sentences(texts):
    return [jieba.lcut(s) for t in texts for s in split('[\n。…;;!!??]+', t)]


def word2vector(texts):
    return Word2Vec(texts2sentences(texts), window=11, sg=1).wv  # skip-gram


class Model:
    def __init__(self, texts, keywords):
        # 加入词库
        for word in keywords:
            jieba.add_word(word)
        # 训练词向量
        self.wv = word2vector(texts)
        # 词库扩展
        self.dt = {
    
    w: {
    
    w: 1} for w in keywords}
        for word in keywords:
            for w, s in self.wv.similar_by_word(word, 99):
                if s < THRESHOLD:
                    break
                self.dt[w] = dict({
    
    word: s**2}, **self.dt.get(w, dict()))
        print(self.dt)

    def ner(self, text):
        # 抽取扩展后的关键词
        c1 = Counter(w for w in jieba.cut(text) if w in self.dt)
        # 扩展后的关键词映射到原关键词
        c2 = Counter()
        for k1, v1 in c1.items():
            for k2, v2 in self.dt[k1].items():
                c2[k2] += v1 * v2
        return c2.most_common()


from data9 import X  # 新闻9分类,不导入标签
_words = {
    
    '汽车', '教育', '娱乐', '时尚', '经济', '军事', '政治', '科学', '体育'}
model = Model(X, _words)
while True:
    try:
        x = X[int(input('输入数字').strip())]
        c = model.ner(x)
        print('\033[033m{}\033[0m'.format(c), x, sep='\n')
    except:
        pass

2.2、实体消歧

实体抽取后,根据上下文词向量来消除歧义,示例如下

from jieba import lcut
from gensim.models import Word2Vec
from numpy import argmax

"""待识别的实体及其分类"""
labels = {
    
    
    0: ['小米', '苹果', '小米粥', '鸡蛋', '粥', '焖饭'],
    1: ['小米', '华为', '魅族', '一加', '苹果', '三星'],
}
entities = {
    
    w: [] for v in labels.values() for w in v}
for label in labels.keys():
    for entity in labels[label]:
        entities[entity].append(label)
labels = ['食品', '手机']

"""语料"""
texts_train = """
小米粥是以小米作为主要食材熬制而成的粥,口味清淡,清香味,具有简单易制,健胃消食的特点。
煮粥时一定要先烧开水然后放入洗净后的小米,先煮沸,然后用文火熬,汤粘稠后即可关火。
小米是传统健康食品,可单独焖饭和熬粥。在北方小米是主要食物之一,很多地区有晚餐吃小米粥的习俗。
苹果,是水果中的一种,是富含维生素的健康新鲜一袋食品。
粥的营养价值很高,富含矿物质和维生素,含钙量丰富,有助于代谢掉体内多余盐分。
鸡蛋有很高的营养价值,是优质蛋白质、B族维生素的良好来源,还能提供一定的脂肪、维生素A和矿物质。
这家超市的食品都非常新鲜,我的一袋鸡蛋在这里买的。
小米营养价值高,营养全面均衡,含有碳水化合物、蛋白质及氨基酸、脂肪及脂肪酸、维生素、矿物质。
小米、三星、华为,作为安卓三大手机旗舰,它们各有什么特色?
别再管小米华为了!魅族手机再曝光:这次真的完美了!
苹果手机或将重陷2016年困境,但这次它无法再大幅提价了。
三星想要继续压制华为,仅凭GalaxyNote10还远远不够!
三星手机屏占比将再创新高,超华为及苹果旗舰。
华为P30、三星A70爆卖,斩获苏宁最佳手机营销奖。
雷军使用一张图告诉你:小米和三星的差距在哪里。
小米米聊APP官方Linux版上线,完美适配Deepin深度系统.
三星刚刚更新了自家的可穿戴设备APP,这次又不小心泄露了可穿戴设备新品的阵容。
""".strip().split()
texts_test = """
小米营养丰富,但是和其它谷物一样蛋白质中赖氨酸过低。
刚才煮粥的时候,我的小米手机突然响了,是楼下卖鸡蛋的阿姨打来的。
广州街坊邱先生报料称,自己前几天在工厂上班时,好端端放在裤袋里的苹果手机,突然冒烟。
苹果APP可以买水果,价格超实惠,买了一箱苹果,非常新鲜,还送了一袋小米。
华为小米跨界并不可怕,可怕的打不破内心的“天花板”。
""".strip().split()

"""词向量"""
sentences = [lcut(i) for i in texts_train]
model = Word2Vec(sentences, size=25, window=10, min_count=1, sg=1, hs=1)
wv = model.wv
for label in labels:
    print(label, wv.similar_by_word(label, 5))

"""计算标签与周边词的相似度,返回最大相似度的标签(索引)"""
def similarity(words):
    vocabulary = set(wv.index2word)
    return argmax([sum(wv.similarity(l, w) if w in vocabulary else 0 for w in words) for l in labels])

"""实体识别"""
replace_color = lambda word: '\033[033m%s\033[0m' % word
for tid, text in enumerate(texts_test):
    words = lcut(text)
    for i, word in enumerate(words):
        if word not in entities:
            continue
        if entities[word].__len__() == 1:
            label_id = entities[word][0]
        else:
            # 实体消歧
            indexes = [j for j in [i - 1, i, i + 1] if len(words) > j >= 0]  # 周边词位置索引
            # weights = [.9, 1.1, .8, 1.1, .9]  # 添加索引权重
            words_around = [words[j] for j in indexes]
            label_id = similarity(words_around)
        word = replace_color(word)
        label = replace_color(labels[label_id])
        duplicate = words[:i] + [word] + words[i + 1:]
        print(word, label, '\033[035m句子%02d\033[0m' % tid,
              ''.join(duplicate), sep=' | ')

3、词典匹配+监督学习

词典匹配后使用分类模型消除歧义(或情感分析),示例如下:

import jieba  # https://yellow520.blog.csdn.net/article/details/97821734
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB

STOP_WORDS = set('了是在和有他我的也为就这都等着来与要又而一个之以她去那但把我们可他们并或由其给使却它及此们即因呢该每应吧')
replace_color = lambda word: '\033[033m%s\033[0m' % word
replace_word = lambda sentence, word, head, tail: sentence[:head] + word + sentence[tail:]

def ner(texts_train, Y_train, labels, texts_test):
    # 待识别的实体及其分类
    entities = {
    
    w: [] for v in labels.values() for w in v}
    for label in labels.keys():
        for entity in labels[label]:
            entities[entity].append(label)
    # TF-IDF向量训练
    vectorizer = TfidfVectorizer(tokenizer=jieba.cut, stop_words=STOP_WORDS)
    X_train = vectorizer.fit_transform(texts_train)
    # 分类模型
    clf = MultinomialNB()
    clf.fit(X_train, Y_train)
    # 实体识别
    for tid, text in enumerate(texts_test):
        for word, start, end in jieba.tokenize(text, HMM=False):
            if word not in entities:
                continue
            if entities[word].__len__() == 1:
                label = entities[word][0]
            else:
                # 实体消歧
                vector = vectorizer.transform([text])
                label = clf.predict(vector)[0]
            label = replace_color(label)
            word = replace_color(word)
            print(word, label, '\033[035m句子%02d\033[0m' % tid,
                  replace_word(text, word, start, end), sep=' | ')

if __name__ == '__main__':
    # 语料
    texts_train = """
    小米粥是以小米作为主要食材熬制而成的粥,口味清淡,清香味,具有简单易制,健胃消食的特点。
    煮粥时一定要先烧开水然后放入洗净后的小米,先煮沸,然后用文火熬,汤粘稠后即可关火。
    小米是传统健康食品,可单独焖饭和熬粥。在北方小米是主要食物之一,很多地区有晚餐吃小米粥的习俗。
    苹果,是水果中的一种,是蔷薇科苹果亚科苹果属植物,其树为落叶乔木。
    粥的营养价值很高,富含矿物质和维生素,含钙量丰富,有助于代谢掉体内多余盐分。
    鸡蛋有很高的营养价值,是优质蛋白质、B族维生素的良好来源,还能提供一定的脂肪、维生素A和矿物质。
    这家超市的水果都非常新鲜,我的鸡蛋都在这里买的。
    小米营养价值高,营养全面均衡,主要含有碳水化合物、蛋白质及氨基酸、脂肪及脂肪酸、维生素、矿物质。
    小米、三星、华为,作为安卓三大手机旗舰,它们各有什么特色?
    别再管小米华为了!魅族手机再曝光:这次真的完美了!
    苹果手机或将重陷2016年困境,但这次它无法再大幅提价了。
    三星想要继续压制华为,仅凭GalaxyNote10还远远不够!
    三星手机屏占比将再创新高,超华为及苹果旗舰。
    华为P30、三星A70爆卖,斩获苏宁最佳手机营销奖。
    雷军使用一张图告诉你:小米和三星的差距在哪里。
    小米米聊APP官方Linux版上线,完美适配Deepin深度系统.
    三星刚刚更新了自家的可穿戴设备APP,这次又不小心泄露了可穿戴设备新品的阵容。
    """.strip().split()
    texts_test = """
    小米营养丰富,但是和其它谷物一样蛋白质中赖氨酸过低。
    刚才煮粥的时候,我的小米手机突然响了,是楼下卖鸡蛋的阿姨打来的。
    某街坊继续报料,自己前几天在工厂上班时,好端端放在裤袋里的苹果手机突然冒烟。
    苹果易购APP可以买水果,价格超实惠,买了一箱苹果,非常新鲜,还送了一袋小米。
    华为、小米跨界并不可怕,可怕的打不破内心的“天花板”。
    """.strip().split()
    Y_train = ['饮食'] * 8 + ['手机'] * 9  # 训练集标签
    # 实体识别和消除歧义
    ner(
        texts_train,
        Y_train,
        {
    
    
            '饮食': ['小米', '苹果', '小米粥', '鸡蛋', '粥', '焖饭'],
            '手机': ['小米', '华为', '魅族', '一加', '苹果', '三星'],
        },
        texts_test
    )

4、监督学习多标签抽取

from jieba import cut
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.preprocessing import MultiLabelBinarizer
from sklearn.multiclass import OneVsRestClassifier
from sklearn.linear_model import LogisticRegression

class MultiLabelClassifier:
    def __init__(self, x, y):
        # 文本向量化
        self.vec = TfidfVectorizer(tokenizer=cut)
        x = self.vec.fit_transform(x)
        # 多标签二值化
        self.bin = MultiLabelBinarizer()
        y = self.bin.fit_transform(y)
        # 机器学习分类模型
        self.clf = OneVsRestClassifier(LogisticRegression())
        self.clf.fit(x, y)

    def predict(self, text):
        x = self.vec.transform([text])
        prob = self.clf.predict_proba(x)[0]
        return {
    
    l: prob[i] for i, l in enumerate(self.bin.classes_)}


X = ['某女星代言小米手机', '小米手机预售价2000元', '某女星潜规则月入2000万', '月入2000元']
Y = [['娱乐', '手机'], ['手机'], ['娱乐'], []]
model = MultiLabelClassifier(X, Y)
print(model.predict('某女星买2000元的小米手机'))
print(model.predict('2000元'))

5、句法分析

待开发

6、词组合抽取

待开发

猜你喜欢

转载自blog.csdn.net/Yellow_python/article/details/108155378