zoukankan      html  css  js  c++  java
  • 文本数据处理

    涉及:

    • 文本数据的特征提取
    • 中文文本的分词方法
    • 用n-Garm模型优化文本数据
    • 使用tf-idf模型改善特征提取
    • 删除停用词

    1.使用CountVectorizer对文本进行特征提取

    前面,用来展示的数据特征分为:

    1. 用来表示数值的连续特征
    2. 表示样本所在分类的类型特征

    第三种数据类型:文本数据

    文本数据在计算机中往往被存储为字符串类型(String)

    中文的处理相比较英文很难,因为在一个句子中,中文的词与词不像英文有空格作为分界线——处理中文时,先进行分词处理

    如句子“The quick brown fos jumps over a lazy dog”:

    #导入向量化工具CountVectorizer
    from sklearn.feature_extraction.text import CountVectorizer
    vect = CountVectorizer()
    #拟合文本数据
    en = ['The quick brown fos jumps over a lazy dog']
    vect.fit(en)
    print('单词数:',len(vect.vocabulary_))
    print('分词:',vect.vocabulary_)
    单词数: 8
    分词: {'the': 7, 'quick': 6, 'brown': 0, 'fos': 2, 'jumps': 3, 'over': 5, 'lazy': 4, 'dog': 1}

    【结果分析】

    'a' 是冠词,没被程序作为一个单词

    中文:

    #使用中文文本进行实验
    cn = ['那只敏捷的棕色狐狸跳过了一只懒惰的狗']
    #拟合中文数据
    vect.fit(cn)
    print('单词数:',len(vect.vocabulary_))
    print('分词:',vect.vocabulary_)
    单词数: 1
    分词: {'那只敏捷的棕色狐狸跳过了一只懒惰的狗': 0}

    【结果分析】

    程序无法对中文语句进行分词(没有空格)

    2.使用分词工具对中文文本进行分词

    pip install jieba 安装结巴分词

    #导入结巴分词
    import jieba
    #对中文文本分词
    cn = jieba.cut('那只敏捷的棕色狐狸跳过了一只懒惰的狗')
    #实验空格‘ ’作为词与词的分界线
    cn = [' '.join(cn)]
    print(cn)

    【结果分析】

    红底黑字是“结巴分词”导入词典和建立模型的信息

     分词完成,接着进行特征提取:

    #使用CountVectorizer对中文文本进行向量化
    vect.fit(cn)
    print('单词数:',len(vect.vocabulary_))
    print('分词:',vect.vocabulary_)
    单词数: 6
    分词: {'敏捷': 2, '棕色': 3, '狐狸': 4, '跳过': 5, '一只': 0, '懒惰': 1}

     【结果分析】

     CountVectorizer已经可以从中文文本中提取若干个整型数值,并且生成了一个字典

    接下来,使用这个字典将文本的特征表达出来,以便训练模型:

    3.使用词袋模型将文本数据转为数组

    上面的实验中,CountVectorizer给每个词编码为0-5的整型数,结果这样的处理,可以用一个稀疏矩阵对这个文本数据进行表示

    #定义词袋模型
    bag_of_words = vect.transform(cn)
    #打印词袋模型中的数据特征
    print('转化为词袋的特征:',repr(bag_of_words))
    转化为词袋的特征: <1x6 sparse matrix of type '<class 'numpy.int64'>'
    	with 6 stored elements in Compressed Sparse Row format>

    【结果分析】

    原来的语句,被转化成一个1行16列的稀疏矩阵,类型为64位整型数值,其中有6个元素

    6个元素都是什么?

    #打印词袋模型的密度表达
    print(bag_of_words.toarray())
    [[1 1 1 1 1 1]]

     

    换一句话看看结果有啥不同:

    #输入新的中文文本
    cn_1 = jieba.cut('懒惰的狐狸不如敏捷的狐狸敏捷,敏捷的狐狸不如懒惰的狐狸懒惰')
    cn2 = [' '.join(cn_1)]
    print(cn2)
    ['懒惰 的 狐狸 不如 敏捷 的 狐狸 敏捷 , 敏捷 的 狐狸 不如 懒惰 的 狐狸 懒惰']
    #建立新的词袋模型
    new_bag = vect.transform(cn2)
    #打印词袋中的数据特征
    print('转化为词袋的特征:',repr(new_bag))
    #打印词袋的密度表达
    print(new_bag.toarray())
    转化为词袋的特征: <1x6 sparse matrix of type '<class 'numpy.int64'>'
    	with 3 stored elements in Compressed Sparse Row format>
    [[0 3 3 0 4 0]]

     

    上而这种用数组表示一句话中单词出现次数的方法,被称为“词袋模型 "

    这种方法是忽略一个文本中的词序和语法,仅仅将它看作个词的集合

    这种方法对于自然语言进行了简化,以便于机器可以读取井进行模型的训练

    但模型也具有一定的局限性

     对文本类型数据的进一步优化处理

    1. 使用n_Gram算法改善词袋模型

    词袋模型劣势——把句子看作单词的简单集合,忽略单词的顺序

    比如:

    #随便写
    joke = jieba.cut('道士看见和尚吻了尼姑的嘴唇')
    joke = [' '.join(joke)]
    #转化为向量
    vect.fit(joke)
    joke_feature = vect.transform(joke)
    #打印文本数据特征
    print(joke_feature.toarray())
    [[1 1 1 1 1]]

    顺序打乱:

    #将刚才的文本打乱
    joke2 = jieba.cut('尼姑看见道士的嘴唇亲吻了和尚')
    joke2 = [' '.join(joke2)]
    #转化为向量
    vect.fit(joke2)
    joke2_feature = vect.transform(joke2)
    #打印文本数据特征
    print(joke2_feature.toarray())
    [[1 1 1 1 1 1]]

    【结果分析】

    对于机器来说,意思一模一样

    在CountVectorize 中调节n-Gram函数:

    #修改CountVectorizer的ngram参数
    vect = CountVectorizer(ngram_range=(2,2))
    #重新进行文本数据的特征提取
    cv = vect.fit(joke)
    joke_feature = cv.transform(joke)
    print('调整ngram参数后的词典:',cv.get_feature_names())
    print('新的特征表达:',joke_feature.toarray())
    调整ngram参数后的词典: ['和尚 尼姑', '尼姑 嘴唇', '看见 和尚', '道士 看见']
    新的特征表达: [[1 1 1 1]]

    【结果分析】

    将CountVectorizer的ngram_range参数调节为(2,2),意思是,进行组合的单词数量下线是2,上线也是2【即限制CountVectorizer将句子中相邻两个单词进行组合】

    试试另一句:

    #调整文本顺序
    joke2 = jieba.cut('尼姑看见道士的嘴唇亲吻了和尚')
    joke2 = [' '.join(joke2)]
    #转化为向量
    #vect.fit(joke2)   //这句书上没有,不知道是否必须
    joke2_feature = vect.transform(joke2)
    #打印文本数据特征
    print(joke2_feature.toarray())
    [[0 0 0 0]]

    2.使用tf-idf模型对文本数据进行处理

    使用tf-idf模型来进行文本特征提取的类,称为TfidfVectorizer

    tf-idf全称为 词频-逆向文件频率

    tf-idf是一种用来评估某个词对于一个语料库中某一份文件的重要程度

    如果某个词在某个文件中出现的次数非常高,但在其他文件中出现的次数非常少,那么tf-idf就会认为这个词可以很好的将文件进行区分,重要程度会较高

    【注意】tf-idf公式有很多变体

     

    介绍TfidVectorizer用法和CountVectorizer的区别:

    下载数据集  http://ai.stanford.edu/~amaas/data/sentiment  

     

     载入影评数据集:

    !tree C:UsersDELLDesktopaclImdb

    使用sklearn载入这些文本数据:

    #导入文件载入工具
    from sklearn.datasets import load_files
    #定义训练集
    train_set = load_files('C:/Users/DELL/Desktop/aclImdb/train')
    X_train,y_train = train_set.data,train_set.target
    print('训练集文件数量:',len(X_train))
    print('随机选一个',X_train[22])

    有些评论有<br />的符号,用空格替换掉,避免影响模型

    #将文本的<br />去掉
    X_train = [doc.replace(b'<br />',b' ') for doc in X_train]

    再载入数据集:

    #载入测试集
    test = load_files('C:/Users/DELL/Desktop/aclImdb/test')
    X_test,y_test = test.data,test.target
    X_test = [doc.replace(b'<br />',b' ') for doc in X_test]
    #测试集文件数量
    len(X_test)

    25000

    对文本数据进行特征提取:

    使用CountVectorizer

    #用CountVectorize拟合训练数据
    vect = CountVectorizer().fit(X_train)
    #将文本转化为向量
    X_train_vect = vect.transform(X_train)
    print('训练集样本特征数量:',len(vect.get_feature_names()))
    print('最后10个训练集样本特征:',vect.get_feature_names()[-10:])
    训练集样本特征数量: 124255
    最后10个训练集样本特征: ['üvegtigris', 'üwe', 'ÿou', 'ıslam', 'ōtomo', 'şey', 'дом', 'книги', '色戒', 'rock']

     使用有监督学习算法进行交叉验证评分:

    看看模型能否较好的拟合训练集

    #导入线性SVC分类模型
    from sklearn.svm import LinearSVC
    #导入交叉验证工具
    from sklearn.model_selection import cross_val_score
    #使用交叉验证对模型评分
    scores = cross_val_score(LinearSVC(),X_train_vect,y_train)
    print('模型平均分:',scores.mean())

    。。。。。。数据集太大,十分钟还没好。。。。。。就用书上截图了.。。。

    0.778

    泛化到测试集:

    #把测试数据集转化为向量
    X_test_vect = vect.transform(X_test)
    #使用线性SVC拟合训练集
    clf = LinearSVC().fit(X_train_vect,y_train)
    print('测试集得分:',clf.score(X_test_vect,y_test))

    0.58

    接下来用tf-idf算法处理数据:

    #导入tfidf转化工具
    from sklearn.feature_extraction.text import TfidfTransformer
    #用tfidf工具转化训练集和测试集
    tfidf = TfidfTransformer(smooth_idf = False)
    tfidf.fit(X_train_vect)
    X_train_tfidf = tfidf.transform(X_train_vect)
    X_test_tfidf = tfidf.transform(X_test_vect)
    print('未处理的特征:',X_train_vect[:5,:5].toarray())
    print('经tfidf处理的特征:',X_train_tfidf[:5,:5].toarray())

     

    结果处理后的数据集训练的模型评分:

    #重新训练线性SVC模型
    clf = LinearSVC().fit(X_train_tfidf,y_train)
    #使用新的数据进行交叉验证
    scores2 = cross_val_score(LinearSVC(),X_train_tfidf,y_train)
    print('经过tfidf处理的训练集交叉验证得分:',scores.mean())
    print('经过tfidf处理的测试集得分:',clf.score(X_test_tfidf,y_test))

    【结果分析】

     继续对模型继续改进——删除“停用词”

     

    3.删除停用词

    停用词,指在文本处理过程中被筛选出去的,出现频率高,但无意义,比如各种语气词、连词、介词

     目前没有通用的定义“停用词”的规则或工具

    常见方法:

    • 统计文本中出现频率最高的,然后把他们作为“停用词”
    •  使用现有的停用词表

     载入sklearn内置的停用词表:

    #导入内置的停用词库
    from sklearn.feature_extraction.text import ENGLISH_STOP_WORDS
    #打印停用词个数
    print(len(ENGLISH_STOP_WORDS))
    #打印前20和后20个
    print(list(ENGLISH_STOP_WORDS)[:20],list(ENGLISH_STOP_WORDS)[:-20:])

    在上方的影视评语数据集继续停用词删除:

    #导入Tfidf模型
    from sklearn.feature_extraction.text import TfidfVectorizer
    #激活英语停用词参数
    tfidf = TfidfVectorizer(smooth_idf=False,stop_words='english')
    #拟合训练集
    tfidf.fit(X_train)
    #将训练集文本转化为向量
    X_train_tfidf = tfidf.transform(X_train)
    #使用交叉验证进行评分
    scores3 = cross_val_score(LinearSVC(),X_train_tfidf,y_train)
    clf.fit(X_train_tfidf,y_train)
    #将测试集转化为向量
    X_test_tfidf = tfidf.transform(X_test)
    print('去掉停用词后训练集交叉验证平均分:',scores3.mean())
    print('去掉停用词后测试集模型得分:',clf.score(X_test_tfidf,y_test))

     

    【结果分析】

     去掉停用词,可以让机器学习模型更好的拟合文本数据,并提高模型的泛化能力

  • 相关阅读:
    poj2955(区间dp)
    poj3280(区间dp)
    poj1651(区间dp)
    hdu5001(概率dp)
    hdu4389(数位dp)
    hdu4352(数位dp)
    CF 148D(概率dp)
    zoj3329(概率dp)
    POJ1028 Web Navigation
    POJ1027 The Same Game
  • 原文地址:https://www.cnblogs.com/expedition/p/10836378.html
Copyright © 2011-2022 走看看