特徵工程系列:空間特徵構造以及文本特徵構造

原創: JunLiang 木東居士  

特徵工程系列:空間特徵構造以及文本特徵構造

本文爲數據茶水間羣友原創,經授權在本公衆號發表。

關於作者:JunLiang,一個熱愛挖掘的數據從業者,勤學好問、動手達人,期待與大家一起交流探討機器學習相關內容~

0x00 前言

數據和特徵決定了機器學習的上限,而模型和算法只是逼近這個上限而已。由此可見,特徵工程在機器學習中佔有相當重要的地位。在實際應用當中,可以說特徵工程是機器學習成功的關鍵。

那特徵工程是什麼?

特徵工程是利用數據領域的相關知識來創建能夠使機器學習算法達到最佳性能的特徵的過程。

特徵工程又包含了 Data PreProcessing(數據預處理)、Feature Extraction(特徵提取)、Feature Selection(特徵選擇)和 Feature construction(特徵構造)等子問題,本章內容主要討論特徵構造的方法。

創造新的特徵是一件十分困難的事情,需要豐富的專業知識和大量的時間。機器學習應用的本質基本上就是特徵工程。
——Andrew Ng

0x01 特徵構造介紹

空間特徵構造以及文本特徵構造具體方法:

0x02 空間特徵構造

1.按經緯度對空間進行劃分

劃分流程:

1)對經緯度進行特徵分桶,得到類別特徵

binned_latitude(lat) = [
  0  < lat <= 10
  10 < lat <= 20
]
binned_longitude(lon) = [
  0  < lon <= 15
  15 < lon <= 30
]

2)使用笛卡爾乘積生成空間劃分後的特徵

樣本 0<lat<=10& 0<lon<=15 0<lat<=10& 15<lon<=30 10<lat<=20& 0<lon<=15 10<lat<=20& 15<lon<=30
1 1 0 0 0
2 ... ... ... ...

3)對每塊子空間進行編碼,得到類別特徵

效果類似下圖,把空間劃分爲多塊子空間。

2.使用座標拾取系統獲取行政區域信息(類別特徵)

  • 省份ID/名字

  • 城市ID/名字

  • 市轄區ID/名字

  • 街道ID/名字

3.結合其他地址計算距離

例如:計算每個地點至某商業中心的距離。

距離類型:

  • 歐式距離

  • 球面距離

  • 曼哈頓距離

  • 真實距離

0x03 文本特徵構造

1.文本統計特徵

  • 文本長度;

  • 單詞個數;

  • 數字個數;

  • 字母個數;

  • 大小寫單詞個數;

  • 大小寫字母個數;

  • 標點符號個數;

  • 特殊字符個數;

  • 數字佔比;

  • 字母佔比;

  • 特殊字符佔比;

  • 名詞個數;

  • 動詞個數;

適用範圍:所有文本特徵。

統計單詞的個數作爲特徵的程序實現

import pandas as pd

# 構造數據集
df = pd.DataFrame({'興趣': ['健身 電影 音樂', '電影 音樂', '電影 籃球', '籃球 羽毛球', ]})
# 統計興趣愛好的數量
df['興趣數量'] = df['興趣'].apply(lambda x: len(x.split()))
display(df.head())
# 輸出:
     興趣           興趣數量
0    健身 電影 音樂  3
1    電影 音樂      2
2    電影 籃球      2
3    籃球 羽毛球    2

2.字典映射

有序特徵的映射,使用的方法是先構建一個映射字典 mapping,再用 pandas 的 map() 或者 replace() 函數進行映射轉換。

適用範圍:只有一個詞語的有序特徵。

程序實現:

import pandas as pd
df = pd.DataFrame({'edu_level': ['博士', '碩士', '大學', '大專及以下']})
#構建學歷字典
mapping_dict={'博士':4,'碩士':3,'大學':2,'大專及以下':1}
#調用map方法進行轉換
df['edu_level_map']=df['edu_level'].map(mapping_dict)
display(df.head())
# 輸出
	edu_level	edu_level_map
0	博士        4
1	碩士        3
2	大學        2
3	大專及以下   1

3.標籤二值化(LabelBinarizer)

功能與 OneHotEncoder 一樣,但是 OneHotEncode 只能對數值型變量二值化,無法直接對字符串型的類別變量編碼,而 LabelBinarizer 可以直接對字符型變量二值化。

適用範圍:只有一個詞語或者包含多個詞語的特徵。例子:
只有一個詞語的特徵:職業。
有多個詞語的特徵:用戶興趣特徵爲“健身 電影 音樂”。

程序實現:

import pandas as pd
from sklearn.preprocessing import LabelBinarizer
df = pd.DataFrame({'職業': ['老師', '程序員', '警察', '銷售', '銷售', ]})

lb = LabelBinarizer()
lb.fit(df['職業'])
print('類別:{}'.format(lb.classes_))
# 輸出:類別:['程序員' '老師' '警察' '銷售']

display(lb.fit_transform(df['職業']))
# 輸出:
array([[0, 1, 0, 0],
       [1, 0, 0, 0],
       [0, 0, 1, 0],
       [0, 0, 0, 1],
       [0, 0, 0, 1]])

4.多標籤二值化(MultiLabelBinarizer)

把有多個單詞的文本轉換01特徵向量,轉換後的結果可能會有多個爲1的值。

適用範圍:包含多個詞語的特徵。

程序實現:

import pandas as pd
from sklearn.preprocessing import MultiLabelBinarizer
# 構造數據集
df = pd.DataFrame({'興趣': ['健身 電影 音樂', '電影 音樂', '電影 籃球', '籃球 羽毛球', ]})
df['興趣列表'] = df['興趣'].apply(lambda x: x.split())
display(df.head())
# 輸出:
     興趣            興趣列表
0    健身 電影 音樂   [健身, 電影, 音樂]
1    電影 音樂        [電影, 音樂]
2    電影 籃球        [電影, 籃球]
3    籃球 羽毛球      [籃球, 羽毛球]

# 構造特徵
mlb = MultiLabelBinarizer()
feature_array = mlb.fit_transform(df['興趣列表'])
print('類別順序:{}'.format(mlb.classes_))
# 輸出:類別順序:['健身' '電影' '籃球' '羽毛球' '音樂']

print(feature_array)
# 輸出:
[[1 1 0 0 1]
 [0 1 0 0 1]
 [0 1 1 0 0]
 [0 0 1 1 0]]

5.特徵哈希(Feature Hashing)

1)原理

特徵哈希(Feature Hashing),特徵散列化技術,或可稱爲 “散列法” (hashing trick) 的技術,使用哈希函數計算與名稱對應的矩陣列。

當特徵取值列表很大,且有多個需 onehot 編碼時,會導致特徵矩陣很大,且有很多 0,這時可用哈希函數將特徵根據特徵名和值映射到指定維數的矩陣。

2)適用範圍:大數據集文本。

3)程序實現

from sklearn.feature_extraction.text import HashingVectorizer

corpus = [
    'This is the first document.',
    'This is the second second document.',
    'And the third one.',
    'Is this the first document?',
]
hv = HashingVectorizer(n_features=10)
X = hv.fit_transform(corpus)

print('shape={}'.format(X.shape))
# 輸出:shape=(4, 10)
print(X.toarray())
# 輸出:
[[ 0.  0.   0.  0.  0.    0.         -0.57735027  0.57735027  -0.57735027 0.]
 [ 0.  0.   0.  0.  0.    0.81649658 0.           0.40824829  -0.40824829 0.]
 [ 0.  0.5  0.  0.  -0.5  -0.5       0.           0.          -0.5        0.]
 [ 0.  0.   0.  0.  0.    0.         -0.57735027  0.57735027  -0.57735027 0.]]

6.詞袋模型(BOW)

1)原理

詞袋模型假設我們不考慮文本中詞與詞之間的上下文關係,僅僅只考慮所有詞的權重。而權重與詞在文本中出現的頻率有關。
詞袋模型首先會進行分詞,在分詞之後,通過統計每個詞在文本中出現的次數,我們就可以得到該文本基於詞的特徵,如果將各個文本樣本的這些詞與對應的詞頻放在一起,就是我們常說的向量化。

2)適用範圍:長文本特徵。

3)程序實現

from sklearn.feature_extraction.text import CountVectorizer

corpus = [
    'This is the first document.',
    'This is the second second document.',
    'And the third one.',
    'Is this the first document?',
]
vectorizer = CountVectorizer(min_df=1)
X = vectorizer.fit_transform(corpus)
print(X.toarray())
# 輸出:
[[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]]

feature_name = vectorizer.get_feature_names()
print(feature_name)
# 輸出:['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']

由於大部分文本都只會用詞彙表中很少一部分的詞,因此詞向量中有大量的0,也就是說詞向量是稀疏的。因此在實際應用中一般使用稀疏矩陣來存儲。

7.TF-IDF

在大文本語料中,一些詞語出現非常多(比如:英語中的“the”, “a”, “is” ),它們攜帶着很少量的信息量。我們不能在分類器中直接使用這些詞的頻數,這會降低那些我們感興趣但是頻數很小的term。

我們需要對 feature 的 count 頻數做進一步 re-weight 成浮點數,以方便分類器的使用,這一步通過 tf-idf 轉換來完成。

1)主要思想

如果某個詞或短語在一篇文章中出現的頻率 TF 高,並且在其他文章中很少出現,則認爲此詞或者短語具有很好的類別區分能力,適合用來分類。TF-IDF 實際上是:TF * IDF,TF 表示詞頻(term-frequency),IDF 表示 inverse document-frequency。它原先適用於信息檢索(搜索引擎的ranking),同時也發現在文檔分類和聚類上也很好用。

2)實現原理

詞頻(Term Frequency,TF)

詞頻 (term frequency, TF) 指的是某一個給定的詞語在該文件中出現的次數。這個數字通常會被歸一化(一般是詞頻除以文章總詞數),以防止它偏向長的文件。(同一個詞語在長文件裏可能會比短文件有更高的詞頻,而不管該詞語重要與否。)

逆向文件頻率(Inverse Document Frequency,IDF)

逆向文件頻率 (inverse document frequency, IDF) IDF的主要思想是:如果包含詞條t的文檔越少, IDF越大,則說明詞條具有很好的類別區分能力。某一特定詞語的IDF,可以由總文件數目除以包含該詞語之文件的數目,再將得到的商取對數得到。

某一特定文件內的高詞語頻率,以及該詞語在整個文件集合中的低文件頻率,可以產生出高權重的 TF-IDF。因此,TF-IDF傾向於過濾掉常見的詞語,保留重要的詞語。

3)適用範圍:長文本特徵。

4)程序實現

from sklearn.feature_extraction.text import TfidfVectorizer
# 構造數據集
corpus = [
    'This is the first document.',
    'This is the second second document.',
    'And the third one.',
    'Is this the first document?',
]
tfidf = TfidfVectorizer()
X = tfidf.fit_transform(corpus)
print(X.toarray())
# 輸出:
[[0.         0.43877674 0.54197657 0.43877674 0.         0.         0.35872874 0.         0.43877674]
 [0.         0.27230147 0.         0.27230147 0.         0.85322574 0.22262429 0.         0.27230147]
 [0.55280532 0.         0.         0.         0.55280532 0.         0.28847675 0.55280532 0.        ]
 [0.         0.43877674 0.54197657 0.43877674 0.         0.         0.35872874 0.         0.43877674]]
 
# feature_name = tfidf.get_feature_names()
print(feature_name)
# 輸出:['and', 'document', 'first', 'is', 'one', 'second', 'the', 'third', 'this']

5)其它使用方法

實際使用時,特別是當文本內容比較長時,可以只保留權重值 top n 的向量:

  • 使用 Top n 個單詞的 TF-IDF 權重值作爲特徵值;

  • 提取 Top n 個單詞,然後使用多標籤二值化、詞袋模型和詞嵌入向量等相關方法來構造特徵;

8.LDA主題模型

1)原理

LDA(Latent Dirichlet Allocation,隱含狄利克雷分佈)是一種主題模型,它可以將文檔集中每篇文檔的主題以概率分佈的形式給出,從而通過分析一些文檔抽取出它們的主題(分佈)出來後,便可以根據主題(分佈)進行主題聚類或文本分類。同時,它是一種典型的詞袋模型,即一篇文檔是由一組詞構成,詞與詞之間沒有先後順序的關係。

此外,一篇文檔可以包含多個主題,文檔中每一個詞都由其中的一個主題生成。

2)適用範圍:長文本特徵。

3)程序實現

import pandas as pd
import jieba
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation

article_list = [
    '沙瑞金讚歎易學習的胸懷,是金山的百姓有福,可是這件事對李達康的觸動很大。易學習又回憶起他們三人分開的前一晚,大家一起喝酒話別,易學習被降職到道口縣當縣長,王大路下海經商,李達康連連賠禮道歉,覺得對不起大家,他最對不起的是王大路,就和易學習一起給王大路湊了5萬塊錢,王大路自己東挪西撮了5萬塊,開始下海經商。沒想到後來王大路竟然做得風生水起。沙瑞金覺得他們三人,在困難時期還能以沫相助,很不容易。',
    '沙瑞金向毛婭打聽他們家在京州的別墅,毛婭笑着說,王大路事業有成之後,要給歐陽菁和她公司的股權,她們沒有要,王大路就在京州帝豪園買了三套別墅,可是李達康和易學習都不要,這些房子都在王大路的名下,歐陽菁好像去住過,毛婭不想去,她覺得房子太大很浪費,自己家住得就很踏實。',
    '347年(永和三年)三月,桓溫兵至彭模(今四川彭山東南),留下參軍周楚、孫盛看守輜重,自己親率步兵直攻成都。同月,成漢將領李福襲擊彭模,結果被孫盛等人擊退;而桓溫三戰三勝,一直逼近成都。',
]
df = pd.DataFrame({'文章': article_list})
df['文章分詞'] = df['文章'].apply(lambda x: ' '.join(jieba.cut(x)))

# 去停用詞
stopwords_filename = 'data/HIT_stopwords.txt'
def get_stopwords_list(filepath):
    stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()]
    return stopwords

stopwords_list = get_stopwords_list(stopwords_filename)

# 把詞轉化爲詞頻向量,注意由於LDA是基於詞頻統計的,因此一般不用TF-IDF來做文檔特徵
cnt_vector = CountVectorizer(stop_words=stopwords_list)
cnt_tf = cnt_vector.fit_transform(df['文章分詞'])
print(cnt_tf)

# LDA建模
lda = LatentDirichletAllocation(n_topics=2,
                                learning_offset=50.,
                                random_state=0)
docres = lda.fit_transform(cnt_tf)
# 文檔主題的分佈
print(docres)

# 詞列表
print(cnt_vector.get_feature_names())
# 主題和詞的分佈
print(lda.components_)

文檔主題的分佈

[[0.011413   0.988587  ]
 [0.01987086 0.98012914]
 [0.02454516 0.97545484]]

可見第一個和第二個文檔較大概率屬於主題2,則第三個文檔屬於主題1。

主題和詞的分佈

# 詞列表
['347', '一起', '萬塊', '三人', '三套', '三年', '三月', '下海經商', '不想', '不要', '東南', '東挪西撮', '之後', '事業有成', '事對', '京州', '京州帝', '親率', '以沫', '公司', '擊退', '分開', '別墅', '前一晚', '縣當', '縣長', '參軍', '同月', '名下', '後來', '周楚', '喝酒', '四川', '回憶起', '困難', '大家', '大路', '太大', '好像', '孫盛', '學習', '家住', '容易', '對不起', '將領', '康和易', '彭山', '彭模', '很大', '成漢', '成都', '戰三勝', '房子', '打聽', '時期', '有福', '李福', '李達', '李達康', '歐陽', '步兵', '毛婭', '永和', '沒想到', '沒有', '浪費', '溫兵', '瑞金', '留下', '百姓', '直攻', '相助', '看守', '竟然', '而桓溫', '股權', '胸懷', '襲擊', '覺得', '觸動', '話別', '豪園', '賠禮道歉', '讚歎', '踏實', '輜重', '這件', '連連', '逼近', '道口', '金山', '降職', '風生水']
# 每篇文章中每個詞的權重
[[0.8881504  0.79494616 0.88179783 0.72261358 0.7825649  0.80513119
  0.82520957 0.78049205 0.81985708 0.8075189  0.87151537 0.76026665
  0.65725012 0.83192188 0.90323191 0.71051575 0.88162668 0.86249018
  0.72348522 0.6859634  0.85216699 0.83801094 0.74827181 0.69732318
  0.74391631 0.74718763 0.69555681 0.76728713 0.74016533 0.79252597
  0.77958582 0.79331665 0.74595963 0.75151718 0.727614   0.68439365
  0.7365373  0.82113611 0.83377043 0.80014547 0.81893092 0.7554505
  0.75366236 0.77624709 0.71719464 0.84291399 0.80728078 0.70518523
  0.83663851 0.76965302 0.76998538 0.84991333 0.82899283 0.83610283
  0.77734802 0.79315431 0.71280155 0.85322984 0.75106508 0.76941605
  0.89065397 0.87517217 0.76503638 0.81516416 0.82584699 0.85074834
  0.79851313 0.73489237 0.79478729 0.84659611 0.75482478 0.87778172
  0.73947408 0.79949669 0.74764634 0.82890922 0.79219997 0.7224377
  0.80204307 0.8059688  0.72302738 0.85992729 0.76778892 0.86866686
  0.7849911  0.74455222 0.71045084 0.74751146 0.75303978 0.88231417
  0.70699699 0.81767636 0.7186858 ]
 [1.1299159  1.73678241 1.70108861 1.63209268 1.24573913 1.17166174
  1.17693454 1.6663298  1.13029804 1.24124777 1.12768978 1.16812888
  1.21634987 1.13392317 1.23887105 1.24017098 1.19215182 1.34132569
  1.30165184 1.19149742 1.20026225 1.28672459 1.69238527 1.22516326
  1.18699503 1.2412282  1.21361079 1.26812676 1.22683284 1.17583033
  1.19362235 1.35699255 1.21487917 1.2011862  1.25260128 1.69570488
  4.42797426 1.12767075 1.17668924 1.63724037 3.07246623 1.14539765
  1.26922685 1.70900224 1.25625654 1.19620242 1.1986915  1.73981801
  1.28557341 1.24561315 1.63740977 1.2527631  1.687533   1.1186095
  1.25932486 1.19376139 1.21549145 1.09958827 1.69627686 1.63400573
  1.21757517 2.20850807 1.23833306 1.25239533 1.19799035 1.0949596
  1.33692107 2.09364188 1.30451503 1.17003591 1.28622407 1.19110364
  1.19129703 1.35972852 1.16049861 1.20988364 1.25763215 1.19630738
  2.14870101 1.21893029 1.19022771 1.13023978 1.15592638 1.2631164
  1.19764651 1.20991235 1.28665997 1.20537521 1.22217857 1.22113286
  1.22059467 1.24019187 1.17945498]]

上面輸出的“文檔主題分佈權重”和“主題和詞分佈權重”都可以作爲特徵來訓練模型。

9.詞嵌入向量(Word Embedding)

詞嵌入(Word embeddings)是一種單詞的表示形式,它允許意義相似的單詞具有類似的表示形式。我們可以利用 Word Embedding 將一個單詞轉換成固定長度的向量表示,從而便於進行數學處理。

適用範圍:所有文本特徵。

1)只有一個詞語的特徵

例子:'職業': ['老師', '程序員', '警察', '銷售', '銷售', ]

程序實現:

from mitie import total_word_feature_extractor
import pandas as pd
import numpy as np
# 構造數據集
df = pd.DataFrame({'職業': ['老師', '程序員', '警察', '銷售', '銷售', ]})

# 加載語言模型,此處使用mitie的中文語言模型,也可以使用其他語言模型
twfe = total_word_feature_extractor('./total_word_feature_extractor_zh.dat')
# 把詞語轉換成embedding向量
embedding_array = np.array(list(df['職業'].apply(lambda x :twfe.get_feature_vector(x))))
print('shape={}'.format(embedding_array.shape))
# 輸出:shape=(5, 271)
print(embedding_array)
# 輸出:
[[ 0.          5.94052029 -0.55087203 ...  0.98895782 -0.45328307 -2.60366035]
 [ 0.          5.73116112 -0.10071201 ...  0.08086307 -2.83375955 -1.30700874]
 [ 0.          5.46504879  0.31765267 ... -0.67403883 -0.32645369 -0.19468342]
 [ 0.          5.64302588 -0.60524434 ... -1.24884379 -1.201828 0.77896601]
 [ 0.          5.64302588 -0.60524434 ... -1.24884379 -1.201828 0.77896601]]

2)包含多個單詞的特徵或者長文本

由於一個特徵有多個單詞,並且每個樣本的單詞數量不一樣,而每個單詞都有一個對應的 embedding 向量,把每個單詞轉換成特徵向量後依然向量維數不一樣,所以不能直接使用。

一般情況下,我們可以把每個多個單詞對應的 embedding 向量求和/求平均值作爲最終的特徵向量。用求和/求平均運算單元的算法適用於任何單詞數量的特徵,這個求和/求平均值運算效果不錯,實際上它會把所有單詞的意思加起來,或者把所有單詞的意思給平均起來。

包含多個單詞的特徵程序實現:

import pandas as pd
import numpy as np
from mitie import total_word_feature_extractor

# 構造數據集
df = pd.DataFrame({'興趣': ['健身 電影 音樂', '電影 音樂', '電影 籃球', '籃球 羽毛球', ]})
df['興趣列表'] = df['興趣'].apply(lambda x: x.split())
display(df.head())
# 輸出:
     興趣            興趣列表
0    健身 電影 音樂    [健身, 電影, 音樂]
1    電影 音樂        [電影, 音樂]
2    電影 籃球        [電影, 籃球]
3    籃球 羽毛球      [籃球, 羽毛球]

# 加載Embedding模型
mitie_model_filename = 'data/total_word_feature_extractor_zh.dat'
twfe = total_word_feature_extractor(mitie_model_filename)

# 使用加法模型獲取特徵向量
add_embeding_array = np.array(list(df['興趣列表'].apply(
    lambda x : np.sum([twfe.get_feature_vector(w) for w in x], axis=0))))
print(add_embeding_array)
# 輸出:
[[ 0.         17.69472837  0.99066588 ...  1.80016923 -3.46660849 1.61377704]
 [ 0.         11.59600973  1.27471587 ...  1.51293385 -0.89438912 2.50961554]
 [ 0.         11.41014719  0.71066754 ...  1.70346397  2.00526482 1.10128853]
 [ 0.         10.79806709 -0.79963933 ...  1.38594878  3.12447354 0.0570921 ]]
   
# 使用平均值模型獲取特徵向量
mean_embeding_array = np.array(list(df['興趣列表'].apply(
    lambda x : np.mean([twfe.get_feature_vector(w) for w in x], axis=0))))
print(mean_embeding_array)
# 輸出:
[[ 0.          5.89824279  0.33022196 ...  0.60005641 -1.15553616 0.53792568]
 [ 0.          5.79800487  0.63735794 ...  0.75646693 -0.44719456 1.25480777]
 [ 0.          5.7050736   0.35533377 ...  0.85173199  1.00263241 0.55064426]
 [ 0.          5.39903355 -0.39981966 ...  0.69297439  1.56223677 0.02854605]]
 

長文本特徵程序實現:

import pandas as pd
import jieba
import numpy as np
from mitie import total_word_feature_extractor

article_list = [
    '沙瑞金讚歎易學習的胸懷,是金山的百姓有福,可是這件事對李達康的觸動很大。易學習又回憶起他們三人分開的前一晚,大家一起喝酒話別,易學習被降職到道口縣當縣長,王大路下海經商,李達康連連賠禮道歉,覺得對不起大家,他最對不起的是王大路,就和易學習一起給王大路湊了5萬塊錢,王大路自己東挪西撮了5萬塊,開始下海經商。沒想到後來王大路竟然做得風生水起。沙瑞金覺得他們三人,在困難時期還能以沫相助,很不容易。',
    '沙瑞金向毛婭打聽他們家在京州的別墅,毛婭笑着說,王大路事業有成之後,要給歐陽菁和她公司的股權,她們沒有要,王大路就在京州帝豪園買了三套別墅,可是李達康和易學習都不要,這些房子都在王大路的名下,歐陽菁好像去住過,毛婭不想去,她覺得房子太大很浪費,自己家住得就很踏實。',
    '347年(永和三年)三月,桓溫兵至彭模(今四川彭山東南),留下參軍周楚、孫盛看守輜重,自己親率步兵直攻成都。同月,成漢將領李福襲擊彭模,結果被孫盛等人擊退;而桓溫三戰三勝,一直逼近成都。',
]
df = pd.DataFrame({'文章': article_list})
df['文章分詞'] = df['文章'].apply(lambda x: ' '.join(jieba.cut(x)))

# 去停用詞
stopwords_filename = 'data/HIT_stopwords.txt'
def get_stopwords_list(filepath):
    stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()]
    return stopwords

stopwords_list = get_stopwords_list(stopwords_filename)
def remove_stopwords_apply(article):
    article_list = article.split(' ')
    w_list = []
    for w in article_list:
        if w not in stopwords_list and len(w) > 0:
            w_list.append(w)
            
    return ' '.join(w for w in w_list)

df['文章分詞去停用詞'] = df['文章分詞'].apply(remove_stopwords_apply)
display(df.head())


# 加載Embedding模型
mitie_model_filename = 'data/total_word_feature_extractor_zh.dat'
twfe = total_word_feature_extractor(mitie_model_filename)

# 使用加法模型獲取特徵向量
add_embeding_array = np.array(list(df['文章分詞去停用詞'].apply(
    lambda x : np.sum([twfe.get_feature_vector(w) for w in x], axis=0))))
print('加法模型結果:\n{}'.format(add_embeding_array))

# 使用平均值模型獲取特徵向量
mean_embeding_array = np.array(list(df['文章分詞去停用詞'].apply(
    lambda x : np.mean([twfe.get_feature_vector(w) for w in x], axis=0))))
print('平均模型結果:\n{}'.format(mean_embeding_array))

輸出結果:

# 加法模型結果:
[[ 7.60000000e+01  8.59864759e+02 -2.00617124e+01 ... 2.81215128e+01]
 [ 5.10000000e+01  5.03333374e+02 -4.37566057e+01 ... 1.04791496e+01]
 [ 3.60000000e+01  4.14553602e+02 -6.15878703e+01 ... 1.78334359e+01]]
# 平均模型結果:
[[ 3.36283186e-01  3.80471132e+00 -8.87686389e-02 ... 1.24431472e-01]
 [ 3.59154930e-01  3.54460123e+00 -3.08145110e-01 ... 7.37968283e-02]
 [ 3.42857143e-01  3.94812954e+00 -5.86551145e-01 ... 1.69842246e-01]]

0x0FF 總結

  1. 空間特徵(如GPS座標)一般不能直接使用,需要先進行編碼才能作爲特徵訓練模型。可以直接把某塊區域按一定的比例劃分爲多個子區域,也可以按行政區域劃分爲多個子區域,然後再對子區域進行標籤二值化。

  2. 長文本特徵的特徵提取流程

    • Step 1:文本清洗,去除HTML標記、去停用詞、轉小寫、去除噪聲、統一編碼等。

    • Step 2:分詞。

    • Step 3:提取特徵。

預告:下一篇文章將介紹自動化特徵構造。

參考文獻

[1] https://machinelearning-notes.readthedocs.io/zh_CN/latest/feature/%E7%89%B9%E5%BE%81%E5%B7%A5%E7%A8%8B%E2%80%94%E2%80%94%E6%97%B6%E9%97%B4.html
[2] https://www.cnblogs.com/nxf-rabbit75/p/11141944.html#_nav_12
[3] https://gplearn.readthedocs.io/en/stable/examples.html#symbolic-classifier
[4] 利用 gplearn 進行特徵工程. https://bigquant.com/community/t/topic/120709
[5] Practical Lessons from Predicting Clicks on Ads at Facebook. https://pdfs.semanticscholar.org/daf9/ed5dc6c6bad5367d7fd8561527da30e9b8dd.pdf
[6] Feature Tools:可自動構造機器學習特徵的Python庫. https://www.jiqizhixin.com/articles/2018-06-21-2
[7] 各種聚類算法的系統介紹和比較. https://blog.csdn.net/abc200941410128/article/details/78541273

特徵工程系列文章

特徵工程系列:數據清洗

特徵工程系列:特徵篩選的原理與實現(上)

特徵工程系列:特徵篩選的原理與實現(下)

特徵工程系列:特徵預處理(上)

特徵工程系列:特徵預處理(下)

特徵工程系列:特徵構造之概覽篇

特徵工程系列:聚合特徵構造以及轉換特徵構造

特徵工程系列:笛卡爾乘積特徵構造以及遺傳編程特徵構造

特徵工程系列:GBDT特徵構造以及聚類特徵構造

特徵工程系列:時間特徵構造以及時間序列特徵構造

 

 

熱門文章

直戳淚點!數據從業者權威嘲諷指南!

AI研發工程師成長指南

數據分析師做成了提數工程師,該如何破局?

算法工程師應該具備哪些工程能力

數據團隊思考:如何優雅地啓動一個數據項目!

數據團隊思考:數據驅動業務,比技術更重要的是思維的轉變

 

 


 

 

 

閱讀 896

 在看9

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章