python-机器学习程序员

自然语言处理-文本特征值抽取(一)

2018-07-01  本文已影响132人  董小贱

这是我有关机器学习的第一篇文章。机器学习看了有一段时间了,感觉其知识体系甚是繁杂, 各种原理也是互相交错。故先选择一个方向进行专门的学习。最近在看一些自然语言处理的一些东西,看了不少东西, 感觉还甚是迷茫,难以形成一个完整的体系, 故从易到难整理了一些东西, 也算是对近期学习的一个梳理。因为是对自然语言处理进行系统的初探,有些原理的也是不甚了解, 如果错误还望不吝指教,在此多谢。

1:字典特征抽取: 对字典数据进行特征值化

类:sklearn.feature_extraction.DictVectorizer

dict_to_vec = DictVectorizer()
看一下它的实例方法(源码中常用的一部分):
dict_to_vec.fit_transform(X)
   X:字典或者包含字典的迭代器
    返回值:返回sparse矩阵
dict_to_vec.get_feature_names()
   不接收参数
   返回按索引排序的特性名称列表。
dict_to_vec.inverse_transform(X)
   X:转换之后的array数组或者sparse矩阵
   返回转换之前的数据
dict_to_vec.transform(x)
  按照之前的标准转换

实例代码:

# coding:utf-8
__author__ = "dongxiaojian"

from sklearn.feature_extraction import DictVectorizer
def dict_vec(params):
    """
    字典特征值抽取
    :param params: 字典或者包含字典的迭代器
    :return: 
    """

    dic = DictVectorizer(sparse=False) # sparse默认为True, 返回值将会是sparse矩阵。这里将其置为False, 返回值为one-hot编码的矩阵
    data = dic.fit_transform(params)
    print(dic.get_feature_names())
    print(data)
    print(dic.inverse_transform(data)) # 这里需要注意的是, 转回去的编码其实跟之前的有区别

if __name__ == "__main__":
    params = [{'subjects': '语文', 'score': 100}, {'subjects': '数学', 'score': 90}, {'subjects': '英语', 'score': 10}]
    dict_vec(params)

打印结果为:

 ['score', 'subjects=数学', 'subjects=英语', 'subjects=语文']
 [[100.   0.   0.   1.]
 [ 90.   1.   0.   0.]
 [ 10.   0.   1.   0.]]
 [{'score': 100.0, 'subjects=语文': 1.0}, {'score': 90.0, 'subjects=数学': 1.0}, {'score': 10.0, 'subjects=英语': 1.0}]

2:文本特征抽取: 对文本数据进行特征值化

类: sklearn.feature_extraction.DictVectorizer.text.CountVectorizer

count_to_vec = CountVectorizer()
count_to_vec.fit_transform(X)
  X: 包含文本的迭代器
count_to_vec.get_feature_names()
 返回值: 对应的单词列表
count_to_vec.inverse_transform(X)
X: 转换之后的array数组或者sqarse矩阵

示例代码:

# coding:utf-8
__author__ = "dongxiaojian"

import jieba
from sklearn.feature_extraction.text import CountVectorizer

def count_vec(count):
    """
    :param count:包含文本的迭代器
    :return:
    """
    count_to_vec = CountVectorizer()
    data = count_to_vec.fit_transform(count)

    print(count_to_vec.get_feature_names())
    print(data.toarray())
    print(count_to_vec.inverse_transform(data))


if __name__ == "__main__":
    str_con1 = '越过山丘 虽然已白了头 喋喋不休 时不我予的哀愁 还未如愿见着不朽 就把自己先搞丢 越过山丘 才发现无人等候 喋喋不休 再也唤不回温柔 为何记不得上一次是谁给的拥抱 在什么时候'
    str_con2 = """ 想说却还没说的 还很多 攒着是因为想写成歌 让人轻轻地唱着 淡淡地记着 就算终于忘了 也值了 说不定我一生涓滴意念 侥幸汇成河 然后我俩各自一端 望着大河弯弯 终于敢放胆 嘻皮笑脸 面对 人生的难"""
    # 加载自定义词典
    jieba.load_userdict('user_dict.txt') # 这一步其实没什么用, 只是把分词结果更能体现语义
    count1 = jieba.lcut(str_con1)
    count2 = jieba.lcut(str_con2)
    # 构建迭代器
    count = [' '.join(count1), ' '.join(count2)]
    # 中文特征值化
    count_vec(count)

3.TF-IDF:体现词语在文本中的重要程度

基本的解释:

 TF: Term Frequency  衡量一个term在文档中的出现的有多频繁。
    TF =  某个词出现在文档中的次数/文档中的总词数
IDF: Inverse Document Frequency 衡量一个term的重要程度。
    有的在不同的文档出现的次数都很多,很显然, 这些词的重要程度就应该很低。例 如:is 、the、and、的、了、么、 呢。我们要做就是将在某篇文档中出现的次数高, 在其他的文章中出现的次数低的挑选出来。
    IDF = log(文档总数/含有t的文档数)
TF-IDF: TF*IDF 

实现TF-IDF在sklearn中有两种方式:

3.1先进行CountVectorizer然后进行TfidfTransformer
# coding:utf-8
 __author__ = "dongxiaojian"


import jieba
from sklearn.feature_extraction.text import CountVectorizer, TfidfTransformer


def count_vec_tfidf(count):
    """
    :param count:
    :return:
    """
    count_to_vec = CountVectorizer()
    data = count_to_vec.fit_transform(count)
    tfidf = TfidfTransformer()
    tfidf_response = tfidf.fit_transform(data)
    feature_names = count_to_vec.get_feature_names()
    tf_idf_value = tfidf_response.toarray()
    for i in range(len(tf_idf_value)):
        print('-------------------第{}个句子----------------'.format(int(i) + 1))
        for j in range(len(feature_names)):
            print(feature_names[j], tf_idf_value[i][j])


if __name__ == "__main__":
    str_con1 = '越过山丘 虽然已白了头 喋喋不休 时不我予的哀愁 还未如愿见着不朽 就把自己先搞丢 越过山丘 才发现无人等候 喋喋不休 再也唤不回温柔 为何记不得上一次是谁给的拥抱 在什么时候'
    str_con2 = """ 想说却还没说的 还很多 攒着是因为想写成歌 让人轻轻地唱着 淡淡地记着 就算终于忘了 也值了 说不定我一生涓滴意念 侥幸汇成河 然后我俩各自一端 望着大河弯弯 终于敢放胆 嘻皮笑脸 面对 人生的难"""
    # 加载自定义词典
    jieba.load_userdict('user_dict.txt')
    count1 = jieba.lcut(str_con1)
    count2 = jieba.lcut(str_con2)
    # 构建迭代器
    count = [' '.join(count1), ' '.join(count2)]
    # 中文特征值化, 并进行tf-idf处理
    count_vec_tfidf(count)
3.2 使用TfidfVectorizer直接一步到位
# coding:utf-8
__author__ = "dongxiaojian"

import jieba
from sklearn.feature_extraction.text import TfidfVectorizer

def words_tfidf(count):
    """

    :param count:
    :return:
    """

    tfidf_vec = TfidfVectorizer()

    tfidf_response = tfidf_vec.fit_transform(count)
    print(tfidf_response.toarray())


if __name__ == "__main__":
    str_con1 = '越过山丘 虽然已白了头 喋喋不休 时不我予的哀愁 还未如愿见着不朽 就把自己先搞丢 越过山丘 才发现无人等候 喋喋不休 再也唤不回温柔 为何记不得上一次是谁给的拥抱 在什么时候'
    str_con2 = """ 想说却还没说的 还很多 攒着是因为想写成歌 让人轻轻地唱着 淡淡地记着 就算终于忘了 也值了 说不定我一生涓滴意念 侥幸汇成河 然后我俩各自一端 望着大河弯弯 终于敢放胆 嘻皮笑脸 面对 人生的难"""
    # 加载自定义词典
    jieba.load_userdict('user_dict.txt')
    count1 = jieba.lcut(str_con1)
    count2 = jieba.lcut(str_con2)
    # 构建迭代器
    count = [' '.join(count1), ' '.join(count2)]
    # 进行tf-idf特征值化
    words_tfidf(count)

注:以上的方法知识其中一部分简单sklearn中的文本特征值化的一部分方法。其他类似的方法还有NLTK(自带语料库、词类分类库、分类、分词等功能)等。 但是观察其结果, 这些方法都是建立在词频的基础上实现的,其结果表达的含义早已失去了文本原有的意思,所以这几种方法处理起情感分析、问答系统类的问题还是能明显看出其弊端的。接下来的文章将介绍词语向量化的word2vec的方法。

本人水平有限, 如有错误欢迎提出指正!如有参考, 请注明出处!!禁止原文抄袭,遇抄必肛!!!

上一篇下一篇

猜你喜欢

热点阅读