分别使用sklearn和gensim提取文本的tfidf特征

语料

text_list= [
    '我喜欢吃苹果和桃子尤其是桃子',
    '小甲喜欢吃苹果', 
    '小乙喜爱吃西瓜', 
    '小丁喜欢吃苹果西瓜'
]

sklearn会对语料自动进行分词,默认以空格拆分,并且默认过滤掉长度为1的token和标点符号;而gensim需要先对语料分词后才能处理。为了保证两者的输入语料相同,因此处理如下

In [101]: ws = [jieba.lcut(s) for s in text_list]  # gensim的输入
In [102]: ws
Out[102]:
[['我', '喜欢', '吃', '苹果', '和', '桃子', '尤其', '是', '桃子'],
 ['小甲', '喜欢', '吃', '苹果'],
 ['小乙', '喜爱', '吃', '西瓜'],
 ['小丁', '喜欢', '吃', '苹果', '西瓜']]

In [119]: ws_sk = [' '.join(s) for s in ws]  # sklearn的输入
In [120]: ws_sk
Out[120]: ['我 喜欢 吃 苹果 和 桃子 尤其 是 桃子', '小甲 喜欢 吃 苹果', '小乙 喜爱 吃 西瓜', '小丁 喜 欢 吃 苹果 西瓜']

1. 使用sklearn提取计算tfidf

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

方法一:使用CountVectorizer和TfidfTransformer

1. CountVectorizer是通过fit_transform函数将文本中的词语转换为词频矩阵

  • get_feature_names()可看到所有文本的关键字
  • vocabulary_可看到所有文本的关键字和其位置
  • toarray()可看到词频矩阵的结果
# token_pattern为分词方式,默认默认过滤掉长度为1的token和标点符号,即`r"(?u)\b\w\w+\b"`,为了保证分词结果和我们使用jieba的分词结果一致,这里对分词方式做修改
In [135]: vectorizer = CountVectorizer(token_pattern=r"(?u)\b\w+\b")
In [136]: count = vectorizer.fit_transform(ws_sk)

In [137]: vectorizer.get_feature_names()
Out[137]: ['吃', '和', '喜欢', '喜爱', '小丁', '小乙', '小甲', '尤其', '我', '是', '桃子', '苹果', '西瓜']

In [138]: vectorizer.vocabulary_
Out[138]:
{'我': 8,
 '喜欢': 2,
 '吃': 0,
 '苹果': 11,
 '和': 1,
 '桃子': 10,
 '尤其': 7,
 '是': 9,
 '小甲': 6,
 '小乙': 5,
 '喜爱': 3,
 '西瓜': 12,
 '小丁': 4}

In [139]: count.toarray()
Out[139]:
array([[1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 2, 1, 0],
       [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
       [1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1],
       [1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1]])

2. TfidfTransformer是统计CountVectorizer中每个词语的tf-idf权值

In [142]: transformer = TfidfTransformer()

In [143]: tfidf_matrix = transformer.fit_transform(count)

In [144]: tfidf_matrix.toarray()
Out[144]:
array([[0.17311114, 0.33173127, 0.21173977, 0.        , 0.        ,
        0.        , 0.        , 0.33173127, 0.33173127, 0.33173127,
        0.66346254, 0.21173977, 0.        ],
       [0.3612126 , 0.        , 0.44181486, 0.        , 0.        ,
        0.        , 0.69218835, 0.        , 0.        , 0.        ,
        0.        , 0.44181486, 0.        ],
       [0.30675807, 0.        , 0.        , 0.58783765, 0.        ,
        0.58783765, 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.46345796],
       [0.31707032, 0.        , 0.38782252, 0.        , 0.60759891,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.38782252, 0.47903796]])

方法二:使用TfidfVectorizer

TfidfVectorizer可以把CountVectorizer, TfidfTransformer合并起来,直接生成tfidf值
TfidfVectorizer的关键参数:

  • max_df:这个给定特征可以应用在 tf-idf 矩阵中,用以描述单词在文档中的最高出现率。假设一个词(term)在 80% 的文档中都出现过了,那它也许(在剧情简介的语境里)只携带非常少信息。
  • min_df:可以是一个整数(例如5)。意味着单词必须在 5 个以上的文档中出现才会被纳入考虑。设置为 0.2;即单词至少在 20% 的文档中出现 。
  • ngram_range:这个参数将用来观察一元模型(unigrams),二元模型( bigrams) 和三元模型(trigrams)。参考n元模型(n-grams)。
In [146]: tfidf_vec = TfidfVectorizer(token_pattern=r"(?u)\b\w+\b")
In [147]: tfidf_matrix = tfidf_vec.fit_transform(ws_sk)

In [148]: tfidf_vec.get_feature_names()
Out[148]: ['吃', '和', '喜欢', '喜爱', '小丁', '小乙', '小甲', '尤其', '我', '是', '桃子', '苹果', '西瓜']

In [149]: tfidf_vec.vocabulary_
Out[149]:
{'我': 8,
 '喜欢': 2,
 '吃': 0,
 '苹果': 11,
 '和': 1,
 '桃子': 10,
 '尤其': 7,
 '是': 9,
 '小甲': 6,
 '小乙': 5,
 '喜爱': 3,
 '西瓜': 12,
 '小丁': 4}

In [150]: tfidf_matrix.toarray()
Out[150]:
array([[0.17311114, 0.33173127, 0.21173977, 0.        , 0.        ,
        0.        , 0.        , 0.33173127, 0.33173127, 0.33173127,
        0.66346254, 0.21173977, 0.        ],
       [0.3612126 , 0.        , 0.44181486, 0.        , 0.        ,
        0.        , 0.69218835, 0.        , 0.        , 0.        ,
        0.        , 0.44181486, 0.        ],
       [0.30675807, 0.        , 0.        , 0.58783765, 0.        ,
        0.58783765, 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.        , 0.46345796],
       [0.31707032, 0.        , 0.38782252, 0.        , 0.60759891,
        0.        , 0.        , 0.        , 0.        , 0.        ,
        0.        , 0.38782252, 0.47903796]])


2. 使用gensim计算tfidf

from gensim import corpora, models, similarities
In [151]: dictionary = corpora.Dictionary(ws)  # 建立词典

In [152]: dictionary.token2id
Out[152]:
{'吃': 0,
 '和': 1,
 '喜欢': 2,
 '尤其': 3,
 '我': 4,
 '是': 5,
 '桃子': 6,
 '苹果': 7,
 '小甲': 8,
 '喜爱': 9,
 '小乙': 10,
 '西瓜': 11,
 '小丁': 12}

In [153]: corpus = [dictionary.doc2bow(doc) for doc in ws]

In [154]: corpus
Out[154]:
[[(0, 1), (1, 1), (2, 1), (3, 1), (4, 1), (5, 1), (6, 2), (7, 1)],
 [(0, 1), (2, 1), (7, 1), (8, 1)],
 [(0, 1), (9, 1), (10, 1), (11, 1)],
 [(0, 1), (2, 1), (7, 1), (11, 1), (12, 1)]]

In [155]: tfidf_model = models.TfidfModel(corpus)
In [156]: tfidf_matrix_gensim = tfidf_model[corpus]  # 得到语料的tfidf值
In [157]: tfidf_matrix_gensim[0]  # 第一条语料的tfidf值
Out[157]:
[(1, 0.35166544195065214),
 (2, 0.07297717280499402),
 (3, 0.35166544195065214),
 (4, 0.35166544195065214),
 (5, 0.35166544195065214),
 (6, 0.7033308839013043),
 (7, 0.07297717280499402)]

# 计算与新数据的相似度
In [158]: index = similarities.SparseMatrixSimilarity(tfidf_model [corpus], num_features=len(dictionary.keys()))

In [159]: text_new = '小明喜欢吃苹果'  # 一条新数据
In [160]: ws_new = jieba.lcut(text_new)
In [161]: ws_new
Out[161]: ['小明', '喜欢', '吃', '苹果']
In [162]: ws
Out[162]:
[['我', '喜欢', '吃', '苹果', '和', '桃子', '尤其', '是', '桃子'],
 ['小甲', '喜欢', '吃', '苹果'],
 ['小乙', '喜爱', '吃', '西瓜'],
 ['小丁', '喜欢', '吃', '苹果', '西瓜']]

In [163]: vec_new = dictionary.doc2bow(ws_new)
In [164]: vec_new
Out[164]: [(0, 1), (2, 1), (7, 1)]
In [165]: index[tfidf_model[vec_new]]
Out[166]: array([0.1032053 , 0.28159946, 0.        , 0.2538916 ], dtype=float32)  # 与第二条相似度最高,最后一条次高,结果还是比较合理的


3. 对比sklearn和gensim的计算结果

回顾下sklean和gensim各自生成的词表

In [163]: tfidf_vec.vocabulary_  # sklean
Out[163]:
{'我': 8,
 '喜欢': 2,
 '吃': 0,
 '苹果': 11,
 '和': 1,
 '桃子': 10,
 '尤其': 7,
 '是': 9,
 '小甲': 6,
 '小乙': 5,
 '喜爱': 3,
 '西瓜': 12,
 '小丁': 4}

In [164]: dictionary.token2id  # gensim
Out[164]:
{'吃': 0,
 '和': 1,
 '喜欢': 2,
 '尤其': 3,
 '我': 4,
 '是': 5,
 '桃子': 6,
 '苹果': 7,
 '小甲': 8,
 '喜爱': 9,
 '小乙': 10,
 '西瓜': 11,
 '小丁': 12}

第一条数据我 喜欢 吃 苹果 和 桃子 尤其 是 桃子

In [158]: list(tfidf_matrix.toarray()[0])  # sklearn的结果
Out[158]:
[
0.1731111372459707,  # 吃
 0.3317312678886485,  # 和
 0.21173977118307816,  # 喜欢
 0.0,  # 喜爱
 0.0,  # 小丁
 0.0,  # 小乙
 0.0,  # 小甲
 0.3317312678886485,  # 尤其
 0.3317312678886485,  # 我
 0.3317312678886485,  # 是
 0.663462535777297,  # 桃子
 0.21173977118307816,  # 苹果
 0.0  # 西瓜
]

In [159]: tfidf_matrix_gensim[0]  # gensim的结果
Out[159]:
[
(1, 0.35166544195065214),  # 和
 (2, 0.07297717280499402),  # 喜欢
 (3, 0.35166544195065214),  # 尤其
 (4, 0.35166544195065214),  # 我
 (5, 0.35166544195065214),  # 是
 (6, 0.7033308839013043),  # 桃子
 (7, 0.07297717280499402)  # 苹果
]

简单观察,发现gensim对重要token计算出的tfidf值偏大,对次要token计算出的tfidf偏小,区分度更大

参考:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,133评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,682评论 3 390
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,784评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,508评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,603评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,607评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,604评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,359评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,805评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,121评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,280评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,959评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,588评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,206评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,193评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,144评论 2 352

推荐阅读更多精彩内容