查看訓(xùn)練好的模型的各個(gè)特征的系數(shù)

查看訓(xùn)練好的模型的各個(gè)特征的系數(shù)有助于做特征篩選滔驾,下面針對(duì)不同特征類(lèi)型使用了不同方法來(lái)得到不同特征的系數(shù)削锰。

# 使用http://www.reibang.com/p/20456b512fa7中的模型數(shù)據(jù)
# 假設(shè)數(shù)據(jù)已經(jīng)處理好括袒,因此直接訓(xùn)練模型以及預(yù)測(cè)

from itertools import chain

#原始數(shù)據(jù)如下
births.show(3)
+----------------------+-----------+----------------+------------------+----------+---------+---------+---------+----------------+-----------------+----------------------+------------------+------------+-------------+------------+-------------+------------------+
|INFANT_ALIVE_AT_REPORT|BIRTH_PLACE|MOTHER_AGE_YEARS|FATHER_COMBINE_AGE|CIG_BEFORE|CIG_1_TRI|CIG_2_TRI|CIG_3_TRI|MOTHER_HEIGHT_IN|MOTHER_PRE_WEIGHT|MOTHER_DELIVERY_WEIGHT|MOTHER_WEIGHT_GAIN|DIABETES_PRE|DIABETES_GEST|HYP_TENS_PRE|HYP_TENS_GEST|PREV_BIRTH_PRETERM|
+----------------------+-----------+----------------+------------------+----------+---------+---------+---------+----------------+-----------------+----------------------+------------------+------------+-------------+------------+-------------+------------------+
|                     0|          1|              29|                99|         0|        0|        0|        0|              99|              999|                   999|                99|           0|            0|           0|            0|                 0|
|                     0|          1|              22|                29|         0|        0|        0|        0|              65|              180|                   198|                18|           0|            0|           0|            0|                 0|
|                     0|          1|              38|                40|         0|        0|        0|        0|              63|              155|                   167|                12|           0|            0|           0|            0|                 0|
+----------------------+-----------+----------------+------------------+----------+---------+---------+---------+----------------+-----------------+----------------------+------------------+------------+-------------+------------+-------------+------------------+

# 需要注意的是:在訓(xùn)練模型之前需要使用 VectorAssembler 將所有特征合并在一列
pipeline = Pipeline(stages=[encoder, featuresCreator, logistic])
model = pipeline.fit(birth_train)
test_res= model.transform(birth_test)
lrm = model.stages[-1]
# 得到各個(gè)特征
attrs = sorted(
    (attr["idx"], attr["name"]) for attr in (chain(*test_model
        .schema[lrm.summary.featuresCol]
        .metadata["ml_attr"]["attrs"].values())))
print(attrs)
# 輸出
[(0, 'BIRTH_PLACE_VEC_0'),
 (1, 'BIRTH_PLACE_VEC_1'),
 (2, 'BIRTH_PLACE_VEC_2'),
 (3, 'BIRTH_PLACE_VEC_3'),
 (4, 'BIRTH_PLACE_VEC_4'),
 (5, 'BIRTH_PLACE_VEC_5'),
 (6, 'BIRTH_PLACE_VEC_6'),
 (7, 'BIRTH_PLACE_VEC_7'),
 (8, 'BIRTH_PLACE_VEC_8'),
 (9, 'MOTHER_AGE_YEARS'),
 (10, 'FATHER_COMBINE_AGE'),
 (11, 'CIG_BEFORE'),
 (12, 'CIG_1_TRI'),
 (13, 'CIG_2_TRI'),
 (14, 'CIG_3_TRI'),
 (15, 'MOTHER_HEIGHT_IN'),
 (16, 'MOTHER_PRE_WEIGHT'),
 (17, 'MOTHER_DELIVERY_WEIGHT'),
 (18, 'MOTHER_WEIGHT_GAIN'),
 (19, 'DIABETES_PRE'),
 (20, 'DIABETES_GEST'),
 (21, 'HYP_TENS_PRE'),
 (22, 'HYP_TENS_GEST'),
 (23, 'PREV_BIRTH_PRETERM')]

# 將特征與系數(shù)對(duì)應(yīng)起來(lái)
feats_coef = [(name, lrm.coefficients[idx]) for idx, name in attrs]
print(feats_coef)
[('BIRTH_PLACE_VEC_0', 0.0),
 ('BIRTH_PLACE_VEC_1', 0.594420849821937),
 ('BIRTH_PLACE_VEC_2', 2.4075589670913335),
 ('BIRTH_PLACE_VEC_3', 1.7823125440410161),
 ('BIRTH_PLACE_VEC_4', -1.6531133349571725),
 ('BIRTH_PLACE_VEC_5', -0.5495784312261248),
 ('BIRTH_PLACE_VEC_6', -1.7332912701009395),
 ('BIRTH_PLACE_VEC_7', 0.039713396666346504),
 ('BIRTH_PLACE_VEC_8', 0.0),
 ('MOTHER_AGE_YEARS', 0.00576202997456978),
 ('FATHER_COMBINE_AGE', -0.01461223060174637),
 ('CIG_BEFORE', 0.011062646656450726),
 ('CIG_1_TRI', 0.0080557042396814),
 ('CIG_2_TRI', 0.004632194351793351),
 ('CIG_3_TRI', 0.021007970934441053),
 ('MOTHER_HEIGHT_IN', -0.0010835415347563793),
 ('MOTHER_PRE_WEIGHT', -0.002190453970910452),
 ('MOTHER_DELIVERY_WEIGHT', -0.0011442841260634116),
 ('MOTHER_WEIGHT_GAIN', 0.02308236363565165),
 ('DIABETES_PRE', -0.9841689991671982),
 ('DIABETES_GEST', 0.7913093211204729),
 ('HYP_TENS_PRE', -0.2552870610582304),
 ('HYP_TENS_GEST', 0.26936315771969194),
 ('PREV_BIRTH_PRETERM', -1.2085697819317305)]

使用上面的方法可以查看一個(gè)模型各個(gè)特征的系數(shù)從而進(jìn)行特征篩選,但是summary函數(shù)目前只適用于二分類(lèi)箱舞。此外遍坟,上面的數(shù)據(jù)的特征大部分都是數(shù)值型的,而在實(shí)際應(yīng)用中晴股,有的特征是從文本中提取的愿伴,需要使用CountVectorizer將其轉(zhuǎn)換為詞向量。這時(shí)可以使用下面的方法來(lái)得到各個(gè)詞的系數(shù):

# 數(shù)據(jù)如下电湘,其中channel為label隔节,os和name為特征
df.show(4)
+-------+-------------------------------------------------------------------------------------+-------+
|os     |name                                                                                 |channel|
+-------+-------------------------------------------------------------------------------------+-------+
|iOS    |-中國(guó)X檔案:馴火奇人.mp4-娛樂(lè)-高清正版視頻在線(xiàn)觀看–愛(ài)奇藝                            |綜藝   |
|android|0001.土豆網(wǎng)-錫劇新版全本《珍珠塔》--周東亮董云華許美-綜藝-高清正版視頻在線(xiàn)觀看–愛(ài)奇藝|綜藝   |
|iOS    |0051彝族麗江打跳 (16)_baofeng-娛樂(lè)-高清正版視頻在線(xiàn)觀看–愛(ài)奇藝                       |綜藝   |
|iOS    |10歲男孩從軍 沒(méi)想到竟是個(gè)神槍狙擊手 男子看傻了-電視劇-高清正版視頻在線(xiàn)觀看–愛(ài)奇藝    |電視劇 |
+-------+-------------------------------------------------------------------------------------+-------+

### 方式一: 先將所有的詞都放在一列,然后使用CountVectorizer詞向量化
def text2terms(sentence):
    '''使用textRank分詞
    '''
    import jieba.analyse
    terms = jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v')) 
    if not terms: # 若textrank算法的到的結(jié)果為空寂呛,則使用tf-idf算法提取關(guān)鍵詞
        terms = jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
    for t in terms:
        if t.isnumeric() or (t in ['一','二','三', '四', '五', '六', '七', '八', '九', '十', 'Ⅰ','Ⅱ','Ⅲ','Ⅳ','Ⅴ','Ⅵ','Ⅶ','Ⅷ','Ⅸ']):
            terms.remove(t)
    return terms

def get_features(row):
    features = []
    features += [row.os]
    terms = text2terms(row.name)
    features += terms
    if row.channel=='電視劇':
        label=0
    else:
        label=1
    return row.channel, label, row.name, features

df1 = df.rdd.map(lambda row: get_features(row)).toDF(['channel', 'label', 'name', 'terms'])
df1.show(2, truncate=False)    
+-------+-----+-------------------------------------------------------------------------------------+-----------------------------------------------------+
|channel|label|name                                                                                 |terms                                                |
+-------+-----+-------------------------------------------------------------------------------------+-----------------------------------------------------+
|綜藝   |1    |-中國(guó)X檔案:馴火奇人.mp4-娛樂(lè)-高清正版視頻在線(xiàn)觀看–愛(ài)奇藝                            |[iOS, 視頻, 正版, 馴火, 檔案, 娛樂(lè), 奇人, 觀看, 中國(guó)]|
|綜藝   |1    |0001.土豆網(wǎng)-錫劇新版全本《珍珠塔》--周東亮董云華許美-綜藝-高清正版視頻在線(xiàn)觀看–愛(ài)奇藝|[android, 視頻, 正版, 錫劇, 珍珠, 全本, 綜藝, 觀看]  |
+-------+-----+-------------------------------------------------------------------------------------+-----------------------------------------------------+

### 擬合模型
cv = CountVectorizer(inputCol='terms', outputCol='features')
cv_model = cv.fit(df1)
df1 = cv_model.transform(df1)
df2 = df1.select('label', 'features')
logistic = cl.LogisticRegression(maxIter=10,
                                regParam=0.01,
                                featuresCol='features',
                                labelCol='label')
lr_model = logistic.fit(df2)
res = lr_model.transform(df2)

# 查看詞向量中的所有詞怎诫,這里只查看前10個(gè)
cv_model.vocabulary[:10]
#輸出
['視頻', '觀看', '正版', 'iOS', 'wp', 'android', '娛樂(lè)', '電視劇', '片花', '綜藝']
# 查看前10個(gè)詞的系數(shù)
lr_model.coefficients[:10]
array([ 0.380,  0.357,  1.339, -0.182, -0.250, -0.587,  2.607, -2.313,
       -0.966,  3.085])
# 將他們組合在一起
for i,j in zip(cv_model.vocabulary[:10], lr_model.coefficients[:10]):
    print(i,j)
視頻 0.37996859807875527
觀看 0.3567728962448092
正版 1.3386805525611496
iOS -0.18176377875140984
wp -0.2501881651132442
android -0.5865211142654886
娛樂(lè) 2.6067191688211433
電視劇 -2.3126880551420914
片花 -0.966167767504617
綜藝 3.0854430292662474

在上面我們展示了其中如何得到詞向量中每個(gè)詞的系數(shù)大小,主要是用到了CountVectorizerModelvocabulary屬性來(lái)得到詞向量中的各個(gè)詞贷痪,從而將詞與系數(shù)對(duì)應(yīng)起來(lái)幻妓。需要注意的是,這是用使用前面的summary屬性來(lái)得到特征名稱(chēng)是不可行的劫拢,返回的特征名為空肉津,這可能是因?yàn)樵嫉乃性~匯就在一列中。

下面我們將os和name特征放在兩列中進(jìn)行詞向量化后再組合在一起進(jìn)行訓(xùn)練模型:

def get_features2(row):
    terms = text2terms(row.name)
    if row.channel=='電視劇':
        label=0
    else:
        label=1
    return row.channel, label, [row.os], terms

df4 = df.rdd.map(lambda x: get_features2(x)).toDF(['channel','label','os','terms'])
df4.show(2)
# 輸出
+-------+-----+---------+------------------------------------------------+
|channel|label|os       |terms                                           |
+-------+-----+---------+------------------------------------------------+
|綜藝   |1    |[iOS]    |[視頻, 正版, 馴火, 檔案, 娛樂(lè), 奇人, 觀看, 中國(guó)]|
|綜藝   |1    |[android]|[視頻, 正版, 錫劇, 珍珠, 全本, 綜藝, 觀看]      |
+-------+-----+---------+------------------------------------------------+

### 詞向量化然后和并舱沧,最后擬合模型
cv1 = CountVectorizer(inputCol='os',outputCol='os_vec')
cv_os = cv1.fit(df4)
df5 = cv_os.transform(df4)
cv2 = CountVectorizer(inputCol='terms', outputCol='terms_vec')
cv_term = cv2.fit(df5)
df6 = cv_term.transform(df5)

assembler = VectorAssembler(inputCols=['os_vec', 'terms_vec'], outputCol='features')
df7 = assembler.transform(df6)
df7.show()
# 輸出
+-------+-----+---------+----------------------------+-------------+--------------------+--------------------+
|channel|label|       os|                       terms|       os_vec|           terms_vec|            features|
+-------+-----+---------+----------------------------+-------------+--------------------+--------------------+
|   綜藝|    1|    [iOS]|[視頻, 正版, 馴火, 檔案, ...|(3,[0],[1.0])|(888,[0,1,2,3,9,1...|(891,[0,3,4,5,6,1...|
|   綜藝|    1|[android]|[視頻, 正版, 錫劇, 珍珠, ...|(3,[2],[1.0])|(888,[0,1,2,6,49,...|(891,[2,3,4,5,9,5...|
+-------+-----+---------+----------------------------+-------------+--------------------+--------------------+

logistic = cl.LogisticRegression(maxIter=10,
                                regParam=0.01,
                                featuresCol='features',
                                labelCol='label')
lr2 = logistic.fit(df7)
res2 = lr2.transform(df7)

attrs = sorted(
    (attr["idx"], attr["name"]) for attr in (chain(*res2
        .schema['features']
        .metadata["ml_attr"]["attrs"].values())))

for i,j in zip(attrs[:10], lr2.coefficients[:10]):
    print(i, j)
# 輸出
(0, 'os_vec_0') -0.18176377875140926
(1, 'os_vec_1') -0.25018816511324415
(2, 'os_vec_2') -0.5865211142654884
(3, 'terms_vec_0') 0.37996859807875594
(4, 'terms_vec_1') 0.35677289624480935
(5, 'terms_vec_2') 1.33868055256115
(6, 'terms_vec_3') 2.606719168821142
(7, 'terms_vec_4') -2.312688055142091
(8, 'terms_vec_5') -0.9661677675046166
(9, 'terms_vec_6') 3.0854430292662482

雖然不是很明顯妹沙,但是通過(guò)簡(jiǎn)單的推測(cè)可以知道結(jié)果與上面是相同的,但是缺點(diǎn)是這里無(wú)法得知各個(gè)特征的準(zhǔn)確名稱(chēng)熟吏。

獲取特征對(duì)應(yīng)的名稱(chēng)

在平時(shí)寫(xiě)代碼時(shí)候距糖,習(xí)慣于將各列分開(kāi)處理然后串成一個(gè)pipeline來(lái)一起fit transform,這樣的好處是代碼簡(jiǎn)單分俯,但對(duì)于我們?nèi)绾潍@取原始特征名稱(chēng)卻帶來(lái)了一些麻煩肾筐。

一個(gè)簡(jiǎn)單的示例:

pipeline = [stringIndexer1, stringIndexer2, stringIndexer3, onehotEncoder, CounterVectorizer1, CounterVectorizer2, CounterVectorizer3]

pipe_model = pipeline.fit(data)
# 將所有特征合并為一列以便輸入到模型中
assembler = VectorAssembler(inputCols=concat_cols, outputCol='features')
data_transformed = assembler.transform(data)

lr = logistic.fit(data_transformed)
train_res = lr.transform(data_transformed)

如何獲取lr中所有特征對(duì)應(yīng)原始特征名稱(chēng)呢?

attrs = sorted((attr["idx"], attr["name"]) for attr in 
                        (chain(*train_res.schema['features'].metadata["ml_attr"]["attrs"].values())))

# 先通過(guò)attrs把onehotEncoder的特征的原始名稱(chēng)提取出來(lái)缸剪,后綴其實(shí)就是原始特征名稱(chēng)
oh_features = [i for i in attrs if '_oh_' in i[1]]

# 提取CountVectorizer 特征的原始名稱(chēng)
for cv in pipe_model.stages:
    if str(cv).startswith('CountVectorizerModel'):
        start = len(oh_features)
        field_name = cv.getInputCol()
        cv_features = [(i, field_name+"-"+"_".join(w.split())) for i, w in enumerate(cv.vocabulary, start)]
        oh_features += cv_features

還有一種方法其實(shí)也可以得到StringIndexer模型的原始特征名稱(chēng)吗铐,即通過(guò)StringIndexer.label屬性來(lái)獲取。但是可能在最終的特征里面會(huì)多出一個(gè)__unknown后綴結(jié)尾的特征杏节,這個(gè)特征在.label里面是獲取不到的唬渗。但是在attrs里面其實(shí)是可以看到的,并且可以通過(guò)對(duì)比上面提取到的attrs和.label來(lái)進(jìn)行對(duì)比看是否多了個(gè)__unknown結(jié)尾的特征奋渔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末镊逝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嫉鲸,更是在濱河造成了極大的恐慌撑蒜,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異座菠,居然都是意外死亡狸眼,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)浴滴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)拓萌,“玉大人,你說(shuō)我怎么就攤上這事升略∥⑼酰” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵品嚣,是天一觀的道長(zhǎng)炕倘。 經(jīng)常有香客問(wèn)我,道長(zhǎng)腰根,這世上最難降的妖魔是什么激才? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮额嘿,結(jié)果婚禮上瘸恼,老公的妹妹穿的比我還像新娘。我一直安慰自己册养,他們只是感情好东帅,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著球拦,像睡著了一般靠闭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坎炼,一...
    開(kāi)封第一講書(shū)人閱讀 49,950評(píng)論 1 291
  • 那天愧膀,我揣著相機(jī)與錄音,去河邊找鬼谣光。 笑死檩淋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的萄金。 我是一名探鬼主播蟀悦,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼氧敢!你這毒婦竟也來(lái)了日戈?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤孙乖,失蹤者是張志新(化名)和其女友劉穎浙炼,沒(méi)想到半個(gè)月后份氧,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鼓拧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年半火,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片季俩。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖梅掠,靈堂內(nèi)的尸體忽然破棺而出酌住,到底是詐尸還是另有隱情,我是刑警寧澤阎抒,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布酪我,位于F島的核電站,受9級(jí)特大地震影響且叁,放射性物質(zhì)發(fā)生泄漏都哭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一逞带、第九天 我趴在偏房一處隱蔽的房頂上張望欺矫。 院中可真熱鬧,春花似錦展氓、人聲如沸穆趴。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)未妹。三九已至,卻和暖如春空入,著一層夾襖步出監(jiān)牢的瞬間络它,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工歪赢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留化戳,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓轨淌,卻偏偏與公主長(zhǎng)得像迂烁,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子递鹉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容