簡介
幾乎所有人都會購物。從基本的必需品(比如食品)到娛樂產品(比如音樂專輯),我們會購買各種各樣的物品。當購物時,我們不僅會尋找在生活中用到的東西,也會在表達我們對某些社會群體的興趣。我們的線上行為和決策塑造了我們自己的行為特徵。
當購買產品時,該產品具有多個屬性,這使得它類似或不同於其他產品。例如,一個產品的價格、大小或型別都是它的不同特徵。除了這些數值或列舉類的結構化屬性之外,還有非結構化的文字屬性。例如,產品描述或客戶評論的文字也構成了其明顯的特徵。
對於從這些非結構化文字屬性中提取有意義的東西而言,文字分析和其他自然語言處理(NLP)技術非常有幫助,而這對行為分析等任務又很有價值。
本文將介紹如何使用文字分類來構建行為描述模型。文中將展示如何使用 SciKit 這個強大的基於 Python 的機器學習包來實現模型構造和評估,還會對模擬的客戶及其產品購買歷史記錄應用該模型。在這種特定的場景中,將會構造一個模型,向客戶分配一些音樂聽眾感興趣的特色內容,比如狂歡、哥特或金屬音樂。該分配是以每個客戶的購買的具體產品和相應的文字產品說明為基礎的。
音樂行為描述場景
請看下面的場景。您有一個包含許多客戶個人資料的資料集。每個客戶個人資料都包括客戶已經購買的所有產品的一個簡潔的、基於自然語言的描述列表。下面是一款靴子的示例產品描述。
描述:這一款男裝搭扣靴子是一雙哥特式靴子,具有暗波紋亞文化氣息,靴子的鉚釘頭帶來了業內的最新時尚。這款靴子採用了合成的人造皮革鞋面,鞋帶正面使用的是交叉扣,這種交叉一直延續到了鞋統,鞋底是橡膠大底,底部採用了花紋底,而前幫則採用了戰鬥風格,內側配有拉鍊,方便穿鞋和脫鞋。鞋統 13.5 英寸,腿部開口周長約 16 英寸。(鞋碼為 9.5。)風格:男裝搭扣靴子。
我們的目標是根據這些產品描述,將每位當前使用者和未來使用者分類到某個行為配置檔案中。
如下所示,負責人使用產品示例來建立行為特徵、行為模型、客戶特徵,以及最終的客戶行為特徵。
圖 1. 構建客戶行為特徵的高層次方法
第一步是假設負責人的作用,並向系統提供對每個行為特徵的理解。實現此操作的一種方法是手動將每個產品的示例放入系統。示例有助於定義行為特徵。本次討論將使用者劃分到以下音樂行為描述之一:
- 朋克
- 哥特
- 嘻哈
- 金屬
- 狂歡
向定義為朋克的產品提供示例,比如朋克專輯和樂隊的描述,例如,Sex Pistols 的 “Never Mind the Bollocks”。其他專案可能包括與髮型或鞋類相關的產品,比如雞冠頭和 Doc Marten 皮靴。
庫、軟體和資料的建立
這篇文章中所使用的全部資料和原始碼都可以從 bpro project on JazzHub 下載。在下載並解壓 tar 檔案後,需要確保您擁有 Python,SciKit Learn(機器學習和文字分析包),以及所有的依賴關係(比如 numpy、scipy,等等)。如果使用的是 Mac,那麼 SciPy Superpack 可能是您最好的選擇。
在解壓 tar 檔案後,您會注意到兩個包含簡介資料的 YAML 檔案。產品描述是通過讀取種子語料(或文件的正文)來人工生成的。在生成產品描述的過程中,會考慮到詞語在產品描述中出現的頻率。清單 1 是一個人工的產品描述。
備註:下面的描述並不是一個真正的自然語言描述,但在實際情況中可能會出現這種描述。
清單 1. 人工的產品描述
1 2 3 4 5 |
customer single clothes for his size them 1978 course group rhymes have master record-breaking group few starts heard blue ending company that the band the music packaged master kilmister not trousers got cult albums heart commentary cut 20.85 tour... |
這個分析包括兩個資料檔案:
- customers.yaml:包括一個客戶列表。對於每個客戶,包括一個產品描述列表,以及目標標籤,或正確的 行為描述。正確的行為描述是指您知道的那個行為描述是正確的。例如,在實際的場景中,將會檢查哥特使用者的特徵資料,以便驗證這些購買行為表明該使用者是一個哥特使用者。
- behavioral_profiles.yaml:包含描述檔案(朋克、哥特等)的列表,以及定義該描述檔案的產品描述的樣本集。
您可以通過執行命令 python bpro.py -g
生成自己的模擬檔案。
備註:必須先在種子目錄中填充一些內容,定義感興趣的流派。進入種子目錄,開啟任何檔案,並瞭解相關說明。您可以操縱 bpro.py 檔案中的引數,以改變產品描述長度、噪聲量、訓練示例的數量或其他引數。
構建行為描述模型
首先,使用 SciKit 的 CountVectorizer
構建一個基於術語計數的簡單語料庫描述。語料庫物件是包含產品描述的一個簡單字串列表。
清單 2. 構建一個簡單的術語計數
1 2 3 4 5 |
vectorizer = CountVectorizer(gmin_df=1) corpus=[] for bp in behavioral_profiles: for pd in bp.product_descriptions: corpus.append(pd.description) |
SciKit 還有其他更先進的向量器(vectorizers),比如 TFIDFVectorizer
,它使用術語頻率/逆文件頻率 (TF/IDF) 加權來儲存文件術語。TF/IDF 表示有助於讓獨特的術語(比如 Ozzy、 raver和 Bauhaus)的權重比反覆出現的術語(比如 and、 the 和 for)的權重還要高。
接下來,將產品描述劃分為單個單詞,並建立一個術語字典。分析器在匹配過程中找到的每個術語被賦予一個與在結果矩陣中的列相對應的惟一整數索引:
fit_corpus = vectorizer.fit_transform(corpus)
備註:這個分詞器配置(tokenizer configuration)也丟棄了單字元單詞。
您可以使用 print vectorizer.get_feature_names()[200:210]
列印出一些特性,看看哪些單詞被分詞。此命令的輸出如下所示。
清單 3. print 命令的輸出
1 2 |
[u'better', u'between', u'beyond', u'biafra', u'big', u'bigger', u'bill', u'billboard', u'bites', u'biting'] |
請注意,當前向量器沒有詞幹化的單詞。詞幹化 是為詞尾變化或派生的單詞得到一個共同的基礎或詞根形式的過程。例如,big 是在前面列表中的 bigger 的一個常見詞幹。SciKit 不處理更復雜的分詞(比如詞幹化、詞簇化和複合斷詞),但您可以使用自定義分詞器,比如那些來自 Natural Language Toolkit (NLTK) 庫的那些分詞器。關於自定義分詞器的示例,請參見 scikit-learn.org。
分詞過程(比如,詞幹化)有助於減少所需的訓練例項的數量,因為如果某個單詞有多種形式,而且不要求對每種形式都提供統計表示。您可以使用其他技巧來減少培訓需求,比如使用型別字典。例如,如果您有所有哥特樂隊的樂隊名稱列表,那麼可以建立一個共同的文字標記,比如 goth_band
,並在生成特性之前將它新增到您的描述中。通過使用這種方法,如果在描述中第一次遇到某個樂隊,該模型處理此樂隊的方式會與處理模型可以理解其模式的其他樂隊的方式相同。對於本文中的模擬資料,我們要關心的不是減少培訓需求,所以我們應該繼續執行下一個步驟。
在機器學習中,出現這樣的監督分類問題是因為首先要為一組觀察定義一組特性和相應的目標,或者正確的標籤。然後,所選擇的演算法會嘗試相應的模型,該模型會找到最適合的資料,並且參照已知的資料集來最大限度地減少錯誤。因此,我們的下一步操作是構建特性和目標標籤向量(參見清單 4)。隨機化觀察總是一個好辦法,因為它可以防止驗證技術沒有這樣做。
清單 4. 構建特性和目標標籤向量
1 2 3 4 5 6 |
data_target_tuples=[ ] for bp in behavioral_profiles: for pd in bp.product_descriptions: data_target_tuples.append((bp.type, pd.description)) shuffle(data_target_tuples) |
接下來,組裝向量,如清單 5 所示。
清單 5. 組裝向量
1 2 3 4 5 6 7 8 9 |
X_data=[ ] y_target=[ ] for t in data_target_tuples: v = vectorizer.transform([t[1]]).toarray()[0] X_data.append(v) y_target.append(t[0]) X_data=np.asarray(X_data) y_target=np.asarray(y_target) |
現在,您可以選擇一個分類器並修整您的行為描述模型。在此之前,最好先評估模型,這樣做只是為了確保該模型可用,然後再讓客戶試用。
評估行為描述模型
首先使用 Linear Support Vector Machine (SVM),對於此類稀疏向量問題,這是一個匹配度很高的不錯的模型。使用程式碼 linear_svm_classifier = SVC(kernel="linear", C=0.025)
。
備註:您可以通過修改這個模式初始化程式碼來切換到其他模型型別。如果需要試用不同的模型型別,那麼可以使用這個分類器對映,它為一些常見的選項設定了初始化。
清單 6. 使用分類器的對映
1 2 3 4 5 6 7 8 9 10 11 12 |
classifier_map = dict() classifier_map["Nearest Neighbors"]=KNeighborsClassifier(3) classifier_map["Linear SVM"]=SVC(kernel="linear", C=0.025) classifier_map["RBF SVM"]= SVC(gamma=2, C=1) classifier_map["Decision Tree"]=DecisionTreeClassifier(max _depth=5) classifier_map["Random Forest"]=RandomForestClassifier (max_depth=5, n_estimators=10, max_features=1) classifier_map["AdaBoost"]=AdaBoostClassifier() classifier_map["Naive Bayes"]=GaussianNB() classifier_map["LDA"]=LDA() classifier_map["QDA"]=QDA() |
因為這是一個多級分類問題(也就是說,在該問題中,您需要選擇的可能類別多於兩個),您還需要指定相應的策略。一種常見的方法是執行一對全的分類。例如,來自 goth 類的產品描述被用於定義一個類,而另一個類包括來自其他所有類( metal
、rave
,等等)的示例描述。最後,作為驗證的一部分,您需要確保修整該模型的資料不是測試資料。一個常見的技術是使用交叉摺疊驗證法。您可以使用此技術五次,這意味著穿過資料的五個部分的分割槽五次。在每次穿過時,五分之四的資料被用於修整,其餘五分之一用於測試。
清單 7. 交叉摺疊驗證
1 2 3 4 |
scores = cross_validation.cross_val_score(OneVsRestClassifier (linear_svm_classifier), X_data, y_target, cv=2) print("Accuracy using %s:%0.2f (+/- %0.2f) and %d folds" % ("Linear SVM", scores.mean(), scores.std() * 2, 5)) |
儘管如此,您仍會得到完全精確的結果,這標誌著模擬資料有點過於完美。當然,在現實生活中,始終會有干擾因素,因為群體之間的完美界限並不總是存在。例如,有 goth punk 的問題流派,所以像 Crimson Scarlet 這樣的樂隊可能會同時進入 goth
和 punk
的訓練示例。您可以試一下 bpro 下載軟體包 中的種子資料,以便更好地瞭解這種型別的干擾因素。
在瞭解一個行為描述模型之後,您可以再繞回來,用您的所有資料修整它。
清單 8. 修整行為描述模型
1 2 |
behavioral_profiler = SVC(kernel="linear", C=0.025) behavioral_profiler.fit(X_data, y_target) |
試用行為模型
現在,您可以玩一下模型,鍵入一些虛構的產品描述,看看模型如何工作。
清單 9. 試用模型
1 2 |
print behavioral_profiler.predict(vectorizer.transform(['Some black Bauhaus shoes to go with your Joy Division hand bag']).toarray()[0]) |
請注意,它的確會返回 ['goth']
。如果刪除單詞 Bauhaus 並重新執行,您可能會注意到,它現在會返回 ['punk']
。
對您的客戶應用行為模型
繼續將修整過的模型應用於客戶及其購買的產品描述。
清單 10. 將修整過的模型應用於我們的客戶及其產品描述
1 2 3 4 5 6 7 8 9 10 11 |
predicted_profiles=[ ] ground_truth=[ ] for c in customers: customer_prod_descs = ' '.join(p.description for p in c.product_descriptions) predicted = behavioral_profiler.predict(vectorizer .transform([customer_product_descriptions]).toarray()[0]) predicted_profiles.append(predicted[0]) ground_truth.append(c.type) print "Customer %d, known to be %s, was predicted to be %s" % (c.id,c.type,predicted[0]) |
最後,計算準確性,看看您可以多頻繁地分析購物者。
清單 11. 計算準確性
1 2 3 |
a=[x1==y1 for x1, y1 in zip(predicted_profiles,ground_truth)] accuracy=float(sum(a))/len(a) print "Percent Profiled Correctly %.2f" % accuracy |
如果使用所提供的預設描述資料,結果應該是 95%。如果這是真實的資料,那麼這是一個相當不錯的準確率。
擴充套件模型
現在,我們已經構建和測試了模型,可以把它應用於數以百萬計的客戶個人資料。您可以使用 MapReduce 框架,並將修整後的行為分析器傳送到工作節點。然後,每個工作節點都會得到一批客戶個人資料及其購買歷史,並應用模型。儲存結果。此時,模型已被應用,您的客戶被分配為一個行為描述。您可以在很多方面使用該行為描述分配任務。例如,您可能決定用定製的促銷活動來定位目標客戶,或者使用行為描述作為產品推薦系統的輸入。