[NLP学习笔记-Task2] 文本特征提取

清洗文本

import pandas as pd
import jieba
from collections import Counter

TRAIN_PATH = '../DataSets/THUCNews/cnews.train.txt'
STOPWORDS_PATH = '../DataSets/ChineseStopWords.txt'
VOCAB_SIZE = 5000

def read_file(file_name):
    '''
        读文件
    '''
    file_path = {'train': TRAIN_PATH}
    contents = []
    labels = []
    with open(file_path[file_name], 'r', encoding='utf-8') as f:
        for line in f:
            try:
                labels.append(line.strip().split('\t')[0])
                contents.append(line.strip().split('\t')[1])
            except:
                pass
    data = pd.DataFrame()
    data['text'] = contents
    data['label'] = labels
    return data


def get_stopwordslist(path):
    stopwords = [line.strip() for line in open(path, 'r', encoding='utf-8').readlines()]  
    return stopwords          


def pre_data(data):
    content = []
    stop_words = get_stopwordslist(STOPWORDS_PATH)
    for text in data['text']:
        for uchar in text:
            # 判断是否为汉字
            if uchar >= u'\u4e00' and uchar<=u'\u9fa5':
                continue
             # 判断是否为数字
            if uchar >= u'\u0030' and uchar<=u'\u0039':    
                continue
            # 判断是否为英文字母
            if (uchar >= u'\u0041' and uchar<=u'\u005a') or (uchar >= u'\u0061' and uchar<=u'\u007a'):     
                continue
            else:
                text = text.replace(uchar, '')
        # jieba分词
        text_jieba = jieba.cut(text, cut_all=False)
        # 去停用词
        text = []
        for word in text_jieba:
            if word not in stop_words:
                text.append(word)
        content.append(text)
    
    return content

def get_wordsCounter(data):
    '''
        词,字符频率统计
    '''
    all_content = []
    # 把所有的text放到一个list中
    for content in data:
        all_content.extend(content)
    # 对字符频率统计
    counter = Counter(all_content)
    count_pairs = counter.most_common(VOCAB_SIZE - 1)
    
    words_counter = pd.DataFrame([i[0] for i in count_pairs], columns={'words'})
    words_counter['counter'] = [i[1] for i in count_pairs]
    return words_counter
        

train = read_file('train')
train = train.iloc[:100]
content = pre_data(train)
counter_words = get_wordsCounter(content)
print(counter_words)

jieba分词

  1. 分词
    cut 方法,具有3个参数:需要分词的字符串;cut_all 参数用来控制是否采用全模式;HMM 参数用来控制是否使用 HMM 模型。使用全模式会将所有字的组合都切分出来,而精确模式则试图将句子最精确地切开,适合文本分析。

    import jieba
    
    #cut_all=True,开启全模式
    sen = jieba.cut('今天二囧正在努力学习', cut_all=True)
    print('全模式分词:{}'.format('/ '.join(sen)))
    
    #cut_all=False,开启精确模式
    sen = jieba.cut('今天二囧正在努力学习', cut_all=False)
    print('精确模式分词:{}'.format('/ '.join(sen)))
    

    运行结果:
    在这里插入图片描述

  2. 添加自定义词典
    用户可以添加自定义词典,使得分词结果更好

    1.使用方法: jieba.load_userdict(file_name) 其中,file_name 为文件类对象或自定义词典的路径

    词典格式和 dict.txt 一样,一个词占一行;每一行分三部分:词语、词频(可省略)、词性(可省略),用空格隔开,顺序不可颠倒。file_name 若为路径或二进制方式打开的文件,则文件必须为 UTF-8 编码。比如 dict.txt 格式可为:

    创新办 3 i
    詹皇 2
    复联

    词频省略时使用自动计算的能保证分出该词的词频

    2.使用 add_word(word, freq=None, tag=None)del_word(word) 可在程序中动态修改词典

    3.使用 suggest_freq(segment, tune=True) 可调节单个词语的词频,使其能(或不能)被分出来

    sen = jieba.cut('今天二囧正在努力学习', cut_all=False)
    print('精确模式分词:{}'.format('/ '.join(sen3)))
    
    #提高「二囧」的词频
    jieba.suggest_freq('二囧', tune=True)
    
    sen = jieba.cut('今天二囧正在努力学习', cut_all=False)
    print('提高词频后,可以成功分出「二囧」:{}'.format('/ '.join(sen3)))
    

    运行结果:
    在这里插入图片描述

词、字符数量统计

  1. 中文文本
    词统计思路:首先使用 jieba 分词,然后使用 Python collections 模块的 Counter 类来统计词的数量

    字符统计思路:可以直接使用 Counter 类来统计字符的数量

    from collections import Counter
    
    sen = 'jieba分词和NLTK都可以用于NLP任务中的分词环节'
    
    ci = list(jieba.cut(sen, cut_all=False))
    print('词统计:{}'.format(Counter(ci)))
    
    print('=' * 100)
    
    zifu = list(sen)
    print('字符统计:{}'.format(Counter(zifu)))
    

    运行结果:
    [NLP学习笔记-Task2] 文本特征提取_第1张图片

  2. 英文文本
    可以使用 NLTK 库处理英文文本的分词,并进行统计。

语言模型

  1. 统计语言模型

    统计语言模型( Statistical Language Model),是今天所有自然语言处理的基础,并且广泛应用于机器翻译、语音识别、印刷体或手写体识别、拼写纠错、汉字输入和文献查询,而在NLP中可以用于衡量一个句子是否有实际意义,即计算一个句子的概率

    假定S表示某一个有意义的句子,由一连串特定顺序排列的词W1,W2,…,Wn组成,这里n是句子的长度(句子中词汇的个数)。于是S出现的可能性也就是数学上所说的S的概率P(S)=P(W1, W2, …, Wn),利用条件概率公式,以上算式可以展开为:

    P(W1, W2, …, Wn) = P(W1)*P(W2|W1)*P(W3|W1,W2)…P(Wn|W1,W2,…,Wn-1)

    其中P(W1)表示第一个词W1出现的概率;P(W2|W1)是在已知第一个词的前提下,第二个词出现的概率;以此类推,词Wn出现的概率取决于它前面所有的词。

    从计算上来看,第一个词的条件概率P(W1)很容易算,第二个词的条件概率P(W2|W1)也还不太麻烦,第三个词的条件概率P(W3|w1,w2)已经非常难算了,因为它涉及到三个变量W1,W2,W3,每个变量的可能性都是种语言字典的大小。到了最后一个词Wn,条件概率P(wn|w1,w2,…,Wn-1)的可能性太多,无法估算,只能采用近似计算的方法。从19世纪到20世纪初,俄国有个数学家叫马尔可夫( Andrey Markov),他提出了一种偷懒但还颇为有效的方法,也就是每当遇到这种情况时,就假设任意一个词Wi出现的概率只同它前面的词Wi-1有关,于是问题就变得很简单了。这种假设在数学上称为马尔可夫假设。

    现在,S出现的概率就变得简单了:P(S)=P(W1)*P(W2|W1)*P(W3|W2)…P(Wn|Wn-1)

    上述公式就是统计语言模型的二元模型(Bigram Model)。

    接下来的问题就是如何计算P(Wn|Wn-1),根据概率论,该公式可以变化为:P(Wn|Wn-1)=P(Wn-1,Wn)/P(Wn-1)

    因为在互联网时代有大量的语料库(Corpus)可以作为训练样本,所以只要数一数Wn-1、Wn这对词在语料库中前后相邻出现了多少次,以及Wn-1本身在相同的语料库中出现了多少次,就可得到 P(Wn|Wn-1)。

  2. n-gram 语言模型

    n-gram 模型就是统计语言模型的一种近似求解方法,它的基本思想是将文本里面的内容按照字节进行大小为N的滑动窗口操作,形成了长度是N的字节片段序列。n-gram 模型也称为n-1阶马尔科夫模型,它有一个有限历史假设:当前词的出现概率仅仅与前面n-1个词相关。因此统计语言模型中的P(S)可以近似为:
    在这里插入图片描述
    当n取1、2、3时,n-gram模型分别称为unigram、bigram和trigram语言模型。

    unigram 表示以每一个字进行划分,bigram 表示以每两个字进行划分,trigram 表示以每三个字进行划分。

    n-gram模型的参数就是条件概率P(Wi|Wi-n+1,…,Wi-1)。假设词表的大小为100,000,那么n-gram模型的参数数量为100,000n。n越大,模型越准确,也越复杂,需要的计算量越大。最常用的是bigram,其次是unigram和trigram,n取≥4的情况较少。

参考资料

n-gram语言模型

知乎:自然语言处理中N-Gram模型介绍

jieba分词

你可能感兴趣的:(NLP)