詞集與詞袋模型
這個(gè)算法的主要作用也就是對(duì)文本做單詞切分,有點(diǎn)從一篇文章里提取關(guān)鍵詞這種意思,旨在用向量來(lái)描述文本的主要內(nèi)容踢关,其中包含了詞集與詞袋兩種。
詞集模型 DictVectorizer:單詞構(gòu)成的集合谦铃,集合中每個(gè)元素只有一個(gè)耘成,即詞集中的每個(gè)單詞都只有一個(gè)。
詞袋模型 CountVectorizer:在詞集的基礎(chǔ)上加入了頻率這個(gè)維度驹闰,即統(tǒng)計(jì)單詞在文檔中出現(xiàn)的次數(shù)(令牌化和出現(xiàn)頻數(shù)統(tǒng)計(jì))瘪菌,通常我們?cè)趹?yīng)用中都選用詞袋模型。
以詞袋模型為例1
from sklearn.feature_extraction.text import CountVectorizer
#使用默認(rèn)參數(shù)實(shí)例化分詞對(duì)象
vec=CountVectorizer()
#查看詞袋模型的參數(shù)
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}
##讓我們使用它對(duì)文本corpus進(jìn)行簡(jiǎn)單文本全集令牌化嘹朗,并統(tǒng)計(jì)詞頻:
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)
#在擬合期間發(fā)現(xiàn)的每個(gè)項(xiàng)都被分配一個(gè)與所得矩陣中的列對(duì)應(yīng)的唯一整數(shù)索引
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)
#獲取詞匯表(訓(xùn)練語(yǔ)料庫(kù))师妙,詞匯表由特征名和出現(xiàn)頻次構(gòu)成
vec.vocabulary_
輸出:
{'and': 0,
'document': 1,
'first': 2,
'is': 3,
'one': 4,
'second': 5,
'the': 6,
'third': 7,
'this': 8}
針對(duì)其他文本進(jìn)行詞袋處理時(shí), 可以直接使用現(xiàn)有的詞匯表
voc=vec.vocabulary_
new_vec=CountVectorizer(vocabulary=voc)
在將來(lái)的調(diào)用轉(zhuǎn)換方法中屹培,在訓(xùn)練語(yǔ)料庫(kù)vocabulary_中未出現(xiàn)的詞將被完全忽略:
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,即該向量在整個(gè)payload中至少出現(xiàn)了三次
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)是一種用于信息檢索與數(shù)據(jù)挖掘的常用加權(quán)技術(shù)褪秀。TF意思是詞頻(Term Frequency)蓄诽,IDF意思是逆向文件頻率(Inverse Document Frequency),因此TF-IDF其實(shí)就是TF*IDF媒吗。
舉個(gè)例子仑氛,下面有這么幾句話:
1.“我今天跑你家去偷吃了你家的大米,但是被你家狗咬了,你要賠我錢”
2.“我想下午找你玩锯岖,但是天氣預(yù)報(bào)說(shuō)下午要下雨介袜,所以你還是自己玩泥巴去吧”
3.“從見到你老婆的第一天起,你這個(gè)兄弟我就交定了”
假設(shè)以上三句話我們分別寫在三張紙上出吹,那么這個(gè)詞頻遇伞,也就是TF,代表的就是某個(gè)詞在它所處的那張紙上的出現(xiàn)頻率捶牢,比如“你”這個(gè)詞鸠珠,在第一張紙上出現(xiàn)的頻率。
而IDF則代表這個(gè)詞和所有文檔整體的相關(guān)性叫确,如果某個(gè)詞在某一類別出現(xiàn)的多跳芳,在其他類別出現(xiàn)的少,那IDF的值就會(huì)比較大竹勉。如果這個(gè)詞在所有類別中都出現(xiàn)的多飞盆,那么IDF值則會(huì)隨著類別的增加而下降,比如例中的“你”次乓,它的TF值可能很高吓歇,但由于其在三個(gè)文本中均有出現(xiàn),所以IDF值就會(huì)比較低票腰。IDF反映的是一個(gè)詞能將當(dāng)前文本與其它文本區(qū)分開的能力城看。
TF-IDF的缺陷
由于IDF值的公式,使其存在一些天然的缺陷:
- 沒(méi)有考慮特征詞的位置因素對(duì)文本的區(qū)分度杏慰,詞條出現(xiàn)在文檔的不同位置時(shí)测柠,對(duì)區(qū)分度的貢獻(xiàn)大小是不一樣的。
- 按照傳統(tǒng)TF-IDF函數(shù)標(biāo)準(zhǔn)缘滥,往往一些生僻詞的IDF(反文檔頻率)會(huì)比較高轰胁、因此這些生僻詞常會(huì)被誤認(rèn)為是文檔關(guān)鍵詞。(換句話說(shuō)朝扼,如果一個(gè)特征項(xiàng)只在某一個(gè)類別中的個(gè)別文本中大量出現(xiàn)赃阀,在類內(nèi)的其他大部分文本中出現(xiàn)的很少,那么不排除這些個(gè)別文本是這個(gè)類中的特例情況擎颖,因此這樣的特征項(xiàng)不具有代表性榛斯。)
- TF-IDF沒(méi)有考慮到特征項(xiàng)在類間和類內(nèi)的分布情況,比如某個(gè)特征項(xiàng)在某類文檔中大量分布搂捧,而在其它文檔中少量分布驮俗,那么該特征項(xiàng)其實(shí)能很好的作為區(qū)分特征,但根據(jù)TF-IDF的公式允跑,該特征就會(huì)受到抑制意述。
聯(lián)合使用
tf-idf的主要作用就是找出某個(gè)詞或某些詞用以區(qū)別于其它文本,而詞袋模型恰好又是找出文本中出現(xiàn)頻率高的詞語(yǔ)吮蛹,那我們可以試想:
如果我先用詞袋模型篩選出一些高熱度詞匯荤崇,再用tf-idf計(jì)算其權(quán)值,我們將得到詞袋模型中詞匯的tf-idf值潮针,值越高說(shuō)明該詞區(qū)分每條語(yǔ)句的效果越好术荤。
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())
輸出結(jié)果:
['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值,值越高說(shuō)明該詞區(qū)分每條語(yǔ)句的效果越好每篷。
但我們做特征工程追求的是泛化能力瓣戚,即尋找能更好的概括整體文本的特征的詞匯,與tf-idf追求的結(jié)果恰恰相反焦读,所以我們可以看到像alert子库、script這種在安全從業(yè)者看來(lái)明顯的攻擊特征在上面結(jié)果中的權(quán)值反而很低。
我們?cè)倩剡^(guò)頭來(lái)看看tf-idf的缺陷矗晃,其中的第二點(diǎn)和第三點(diǎn)以相反角度來(lái)看都有助于我們對(duì)詞袋模型中特征向量的優(yōu)化(這個(gè)需要各位好好理解一下)仑嗅。
那么我們正好可以利用這個(gè)特征來(lái)判斷詞袋模型中向量的泛化效果
即:tf-idf值越高其泛化能力越低,也就越不適合作為我們的特征向量张症。
從上面的結(jié)果中我們可以看出來(lái)仓技,script、alert這兩個(gè)向量相比于其它能更好的反映出我們整體攻擊語(yǔ)句的特征俗他,符合我們?nèi)斯づ袛嗟慕Y(jié)果脖捻。而在script和alert兩者中alert顯然泛化效果又更加的優(yōu)秀。
兩者結(jié)合使用兆衅,我們就可以自動(dòng)化的從大文本中提取優(yōu)質(zhì)的特征向量地沮,以減少人工干預(yù),大大降低特征工程中的成本羡亩。