词袋模型与TF-IDF

词集与词袋模型

这个算法的主要作用也就是对文本做单词切分,有点从一篇文章里提取关键词这种意思,旨在用向量来描述文本的主要内容,其中包含了词集与词袋两种。

词集模型 DictVectorizer:单词构成的集合,集合中每个元素只有一个,即词集中的每个单词都只有一个。

词袋模型 CountVectorizer:在词集的基础上加入了频率这个维度,即统计单词在文档中出现的次数(令牌化和出现频数统计),通常我们在应用中都选用词袋模型。

以词袋模型为例1

from sklearn.feature_extraction.text import CountVectorizer
#使用默认参数实例化分词对象
vec=CountVectorizer()
#查看词袋模型的参数
vec.get_params()
输出:
{'analyzer': 'word',
 'binary': False,
 'decode_error': 'strict',
 'dtype': numpy.int64,
 'encoding': 'utf-8',
 'input': 'content',
 'lowercase': True,
 'max_df': 1.0,
 'max_features': None,
 'min_df': 1,
 'ngram_range': (1, 1),
 'preprocessor': None,
 'stop_words': None,
 'strip_accents': None,
 'token_pattern': '(?u)\\b\\w\\w+\\b',
 'tokenizer': None,
 'vocabulary': None}
##让我们使用它对文本corpus进行简单文本全集令牌化,并统计词频:
corpus = [
...     'This is the first document.',
...     'This is the second second document.',
...     'And the third one.',
...     'Is this the first document?',
... ]

X = vec.fit_transform(corpus)
#在拟合期间发现的每个项都被分配一个与所得矩阵中的列对应的唯一整数索引
X
输出:
<4x9 sparse matrix of type '<class 'numpy.int64'>'
    with 19 stored elements in Compressed Sparse Row format>

#获取特征名称(列名)
vec.get_feature_names()
输出:
['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']

X.toarray()   
输出:
array([[0, 1, 1, 1, 0, 0, 1, 0, 1],
       [0, 1, 0, 1, 0, 2, 1, 0, 1],
       [1, 0, 0, 0, 1, 0, 1, 1, 0],
       [0, 1, 1, 1, 0, 0, 1, 0, 1]], dtype=int64)
#获取词汇表(训练语料库),词汇表由特征名和出现频次构成
vec.vocabulary_
输出:
{'and': 0,
 'document': 1,
 'first': 2,
 'is': 3,
 'one': 4,
 'second': 5,
 'the': 6,
 'third': 7,
 'this': 8}

针对其他文本进行词袋处理时, 可以直接使用现有的词汇表

voc=vec.vocabulary_
new_vec=CountVectorizer(vocabulary=voc)

在将来的调用转换方法中,在训练语料库vocabulary_中未出现的词将被完全忽略:

vec.transform(['Something third new.']).toarray()
输出:
array([[0, 0, 0, 0, 0, 0, 0, 1, 0]])

以词袋模型为例2

from sklearn.feature_extraction.text import CountVectorizer
#词袋模型,这里的min_df取值为3,即该向量在整个payload中至少出现了三次
vec=CountVectorizer(min_df=3,ngram_range=(1,1))
content=[
    '<s[NULL]cript>alert(1)</s[NULL]cript>X</a>',
    '\'><video><source o?UTF-8?Q?n?error="alert(1)">',
    '\'><FRAMESET><FRAME RC=""+"javascript:alert(\'X\');"></FRAMESET>',
    '"></script>\'//<svg "%0Aonload=alert(1) //>',
    '"></script><img \'//"%0Aonerror=alert(1)// src>',
    'id%3Den%22%3E%3Cscript%3Ealert%28%22AKINCILAR%22%29%3C/script%3E',
    '?a%5B%5D%3D%22%3E%3Cscript%3Ealert%28document.cookie%29%3C/script%3E',
    '><iframe src="data:data:javascript:,% 3 c script % 3 e confirm(1) % 3 c/script %3 e">',
    '?mess%3D%3Cscript%3Ealert%28document.cookie%29%3C/script%3E%26back%3Dsettings1',
    'title%3D%3Cscript%3Ealert%28%22The%20Best%20XSSer%22%29%3C/script%3E',
    '<script charset>alert(1);</script charset>',
    '"><meta charset="x-mac-farsi">??script ??alert(1)//??/script ??',
    '</script><script>/*"/*\'/**/;alert(1)//</script>#',
]

X=vec2.fit_transform(content)
vec2.get_feature_names()
输出:
['22', '29', '3c', '3cscript', '3d', '3e', '3ealert', 'alert', 'script']
In [124]:
vec2.vocabulary_
输出:
{'22': 0,
 '29': 1,
 '3c': 2,
 '3cscript': 3,
 '3d': 4,
 '3e': 5,
 '3ealert': 6,
 'alert': 7,
 'script': 8}

TF-IDF算法

TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术。TF意思是词频(Term Frequency),IDF意思是逆向文件频率(Inverse Document Frequency),因此TF-IDF其实就是TF*IDF。

举个例子,下面有这么几句话:

1.“我今天跑你家去偷吃了你家的大米,但是被你家狗咬了,你要赔我钱”

2.“我想下午找你玩,但是天气预报说下午要下雨,所以你还是自己玩泥巴去吧”

3.“从见到你老婆的第一天起,你这个兄弟我就交定了”

假设以上三句话我们分别写在三张纸上,那么这个词频,也就是TF,代表的就是某个词在它所处的那张纸上的出现频率,比如“你”这个词,在第一张纸上出现的频率。

而IDF则代表这个词和所有文档整体的相关性,如果某个词在某一类别出现的多,在其他类别出现的少,那IDF的值就会比较大。如果这个词在所有类别中都出现的多,那么IDF值则会随着类别的增加而下降,比如例中的“你”,它的TF值可能很高,但由于其在三个文本中均有出现,所以IDF值就会比较低。IDF反映的是一个词能将当前文本与其它文本区分开的能力。

TF-IDF的缺陷
由于IDF值的公式,使其存在一些天然的缺陷:

  • 没有考虑特征词的位置因素对文本的区分度,词条出现在文档的不同位置时,对区分度的贡献大小是不一样的。
  • 按照传统TF-IDF函数标准,往往一些生僻词的IDF(反文档频率)会比较高、因此这些生僻词常会被误认为是文档关键词。(换句话说,如果一个特征项只在某一个类别中的个别文本中大量出现,在类内的其他大部分文本中出现的很少,那么不排除这些个别文本是这个类中的特例情况,因此这样的特征项不具有代表性。)
  • TF-IDF没有考虑到特征项在类间和类内的分布情况,比如某个特征项在某类文档中大量分布,而在其它文档中少量分布,那么该特征项其实能很好的作为区分特征,但根据TF-IDF的公式,该特征就会受到抑制。

联合使用

tf-idf的主要作用就是找出某个词或某些词用以区别于其它文本,而词袋模型恰好又是找出文本中出现频率高的词语,那我们可以试想:

如果我先用词袋模型筛选出一些高热度词汇,再用tf-idf计算其权值,我们将得到词袋模型中词汇的tf-idf值,值越高说明该词区分每条语句的效果越好。

import numpy as np
from sklearn import preprocessing
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer

vec=CountVectorizer(min_df=3,ngram_range=(1,1))
content=[
    '<s[NULL]cript>alert(1)</s[NULL]cript>X</a>',
    '\'><video><source o?UTF-8?Q?n?error="alert(1)">',
    '\'><FRAMESET><FRAME RC=""+"javascript:alert(\'X\');"></FRAMESET>',
    '"></script>\'//<svg "%0Aonload=alert(1) //>',
    '"></script><img \'//"%0Aonerror=alert(1)// src>',
    'id%3Den%22%3E%3Cscript%3Ealert%28%22AKINCILAR%22%29%3C/script%3E',
    '?a%5B%5D%3D%22%3E%3Cscript%3Ealert%28document.cookie%29%3C/script%3E',
    '><iframe src="data:data:javascript:,% 3 c script % 3 e confirm(1) % 3 c/script %3 e">',
    '?mess%3D%3Cscript%3Ealert%28document.cookie%29%3C/script%3E%26back%3Dsettings1',
    'title%3D%3Cscript%3Ealert%28%22The%20Best%20XSSer%22%29%3C/script%3E',
    '<script charset>alert(1);</script charset>',
    '"><meta charset="x-mac-farsi">??script ??alert(1)//??/script ??',
    '</script><script>/*"/*\'/**/;alert(1)//</script>#',
]
X=vec.fit_transform(content)
trans=TfidfTransformer()
tfidf=trans.fit_transform(X)
print (vec.get_feature_names())
print (tfidf.toarray())

输出结果:
['22', '29', '3c', '3cscript', '3d', '3e', '3ealert', 'alert', 'script']
[[ 0.          0.          0.          0.          0.          0.          0.
   1.          0.        ]
 [ 0.          0.          0.          0.          0.          0.          0.
   1.          0.        ]
 [ 0.          0.          0.          0.          0.          0.          0.
   1.          0.        ]
 [ 0.          0.          0.          0.          0.          0.          0.
   0.75787695  0.65239752]
 [ 0.          0.          0.          0.          0.          0.          0.
   0.75787695  0.65239752]
 [ 0.60865989  0.27418507  0.27418507  0.27418507  0.          0.54837013
   0.27418507  0.          0.16767089]
 [ 0.33715382  0.30375763  0.30375763  0.30375763  0.33715382  0.60751526
   0.30375763  0.          0.18575524]
 [ 0.          0.          0.          0.          0.          0.          0.
   0.          1.        ]
 [ 0.          0.38907452  0.38907452  0.38907452  0.43185075  0.38907452
   0.38907452  0.          0.23792861]
 [ 0.39646122  0.35719043  0.35719043  0.35719043  0.39646122  0.35719043
   0.35719043  0.          0.21843071]
 [ 0.          0.          0.          0.          0.          0.          0.
   0.50226141  0.86471583]
 [ 0.          0.          0.          0.          0.          0.          0.
   0.50226141  0.86471583]
 [ 0.          0.          0.          0.          0.          0.          0.
   0.36109936  0.93252735]]

由此得到词袋模型中词汇的tf-idf值,值越高说明该词区分每条语句的效果越好。
但我们做特征工程追求的是泛化能力,即寻找能更好的概括整体文本的特征的词汇,与tf-idf追求的结果恰恰相反,所以我们可以看到像alert、script这种在安全从业者看来明显的攻击特征在上面结果中的权值反而很低。

我们再回过头来看看tf-idf的缺陷,其中的第二点和第三点以相反角度来看都有助于我们对词袋模型中特征向量的优化(这个需要各位好好理解一下)。

那么我们正好可以利用这个特征来判断词袋模型中向量的泛化效果
即:tf-idf值越高其泛化能力越低,也就越不适合作为我们的特征向量。

从上面的结果中我们可以看出来,script、alert这两个向量相比于其它能更好的反映出我们整体攻击语句的特征,符合我们人工判断的结果。而在script和alert两者中alert显然泛化效果又更加的优秀。

两者结合使用,我们就可以自动化的从大文本中提取优质的特征向量,以减少人工干预,大大降低特征工程中的成本。

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

推荐阅读更多精彩内容