假期過後,你的元氣值恢復了嗎?

清明三天假期眨眼就劃過了,你的元氣值恢復了嗎,還是依然感覺疲憊?

(關注公衆號:livandata,回覆:元氣值,即可獲取本文案例的代碼)

隨着工作年限的增長,這一感覺似乎越來越明顯,似乎一週七天裏面最累的是週一——黑眼圈、惺忪眼、哈氣連天,不自覺會想起曾經那個三天網吧,三天課堂的少年。

那麼,如何才能預測出一個人的工作恢復能力呢?筆者藉着小夥伴的調研,做了簡單的探索。有興趣的小夥伴可以簡單試一下,剛好也借這個機會梳理一下常用的機器學習的常用算法,畢竟這個研究的過程,幾乎嘗試了常見的機器學習算法。

文章的緣起是一個心理學問題,希望能從微博近幾個禮拜的數據中找尋到人類的情感波動,並輔以問卷調研的方法探索當下發微博的人的復工程度,由於數據的權限問題,這裏只做技術性探討,後文也會附上代碼,如果有興趣,歡迎大家嘗試。

之前在《增長的旋律——AARRR模式思考(三)》文章中曾仔細分析過微博和微信的差異,作爲一個線上的公共場所,微博無時無刻不承載着各種網絡言論,其中不乏對工作的安排、對生活的情緒,微博也便成爲了線上反應各自情緒的數據來源。那麼,通過對微博數據的挖掘,能否預測出真實生活中人的行爲和狀態呢?作爲一個數據人,總是希望能夠有機會一探究竟,下面我們一起走一遍研究的過程:

P1 數據收集

研究隨機圈定了一羣經常使用微博的人,收集他們在微博上發表的博文,記錄他們的發表時間,發表地點,點贊和評論次數等相關信息,每週爲一個單位,持續關注三到四個月的時間,以此來探索被試者的情緒波動,確定被試者在何種情緒下會發出什麼樣的文字。

爲了更全面的探索,研究增加了線下調研的部分,對這些經常使用微博的人進行有償問卷作答,從工作狀況、家庭狀況、收入以及睡眠等幾個方面設計問卷,並通過心理學的方法探索被試者在心理剝離、放鬆經驗、控制經驗等方面的得分,探索用分數的形式表現緊張、憤怒、精力、抑鬱等多種情緒。

數據的收集結構如下圖:

通過上面的兩種思路,我們收集到了一整套完整的數據,涵蓋了文本、字符串和數字,經過彙總整理後,我們得到如下表格:

(1)線下調研部分數據樣式爲:

(2)微博部分數據樣式爲:

P2  數據處理

 

觀察上面的數據,我們會發現,數據的樣式比較多樣,有文本形式,有時間值,有數值得分也有字符串等,需要進行較爲詳細的特徵工程,在建模的時候花費大量時間的往往就在這裏了:離散值怎麼向量化?文本怎麼提取語義?怎麼做降維處理?怎麼歸一化?基本步驟都會圍繞這些問題進行,對於離散化、歸一化和降維處理都是一些常規的做法,在sklearn中會有一些完整的函數:

 

1)離散化等one-hot處理:

 

這一處理方法主要應用在特徵獨立性要求不強的模型中,因爲one-hot是將一個特徵以向量的方式呈現成多列,這些擴展開的列存在一定的相關性,如果對於特徵獨立性要求高的模型可以嘗試使用WOE計算方法,將各個無法計算的特徵(【山東、上海、……】)轉化成可以計算的數字。

另外爲了便於分類,也會存在將連續的數字拆分成幾個離散的值,比如將【1,2,3,4,5,6,7,8,9】等連續值拆分成兩類【0,1】,這樣的方法往往會用統計學中的一些分箱方法,進行等頻分箱或者等額分箱等。

 

2)降維處理:

 

降維處理在建模過程中算是必備的一個步驟,經過離散化處理之後,數據特徵有可能已經達到1000甚至10000維度,這一數據量直接投放到模型中往往會引發維度爆炸、維度災難,那如何降維呢?最常用的方法主要有兩個:一般機器學習的模型會比較常用主成分分析,神經網絡深度學習部分主要是embedding方法,這些方法在降維的效果上不僅能夠有效減少維度,更重要的他們能夠減少各個特徵中大量爲零的狀態,使模型的訓練能更加高效精準。

這兩種方法分別在兩個包裏:

主成分分析在sklearn中的函數爲:

estimator = PCA(n_components=num)pca_X_train = estimator.fit_transform(X_train4)pca_X_test = estimator.fit_transform(X_test4)pre_test_Y = y_test[['y_mean']]pca_train_Y = y_train['y_mean'].tolist()

embedding在keras中的函數爲:

model = Sequential()model.add(Embedding(5000, 512,input_length=100))

講到embedding不妨多說一句,在深度學習中,embedding、word2vec、dropout、attention被稱作是必備組件,可見embedding的地位。

 

3)特徵歸一化:

 

經歷過離散化、降維處理之後,有沒有發現我們的特徵有大有小,來自於各個方向的數據往往存在不同的量綱,直接投放到模型中會存在量級上的差異,千萬級別的數據會輕而易舉的抹殺掉個位數的特徵,導致量級小的特徵特性不明顯,因此需要進行歸一化處理。歸一化主要是爲了取消掉各個特徵之間的量綱,使各個特徵統一在一個維度使用。

歸一化在sklearn中的函數爲:​​​​​​​

from sklearn import preprocessingimport numpy as npX = np.array([[ 1., -1.,  2.],              [ 2.,  0.,  0.],              [ 0.,  1., -1.]])X_scaled = preprocessing.scale(X)

歸一化的方法除了我們常用的z-score標準化之外,還有min-max標準化,改進的z-score標準化等方法,使用過程中可以根據需要選擇相應的方法。

 

上面的三個處理方法往往是我們建模過程中的標準套路,幾乎可以不假思索的應用於所有的特徵工程,看到這裏的你有沒有不解渴的感覺,費這麼大功夫寫一篇文章,難道連一點特產也沒有嗎?當然不是,這個模型構建的特色在於對文本的處理,也就是下面我們重點講的東西:

文本的處理往往是獨立於數據挖掘的另外一個領域——NLP,這一領域相對獨立但又與模型有千絲萬縷的聯繫,我們來看一下本文中的案例使用了什麼獨特的方法:

本文采用的方法主要是採用關鍵詞處理的方法,根據博文進行詞性分析,根據詞性計算各個詞片段的得分,進而得出各個關鍵詞的權重分。個人以爲,這也是這個研究中比較有特色的一個文本處理方法,不同於我們經常使用的TF-IDF、LDA、HMM隱馬、CRF條件隨機場等NLP模型。我們來仔細瞭解一下這一方法:

1)梳理關鍵詞:整理出我們比較關注的關鍵詞,添加到特徵工程中,作爲特徵值,並同時篩選程度詞和否定詞,作爲計算權重的依據;

2)切分詞短句:按照微博號彙總每個被試者發表的博文,並將博文按照“,”,“。”等標點符號拆分成一個個的短句,此時每個被試者的博文就會成爲一個個帶有一定語義的詞短句,我們接下來就是要通過對這些短句進行處理,來判斷第一步中各個關鍵詞的權重,並作爲特徵值將其融入到特徵工程中。

3)統計關鍵詞詞頻:遍歷每一個詞短句,統計其中關鍵詞的頻數,如果當下詞短句有對應的關鍵詞則記錄詞頻數l1,如果沒有對應的關鍵詞,則記爲0。

4)計算程度詞權重:不同的程度詞權重係數不同,比如:“百分之百”、“倍加”等記爲2,“多麼”、“格外”等記爲1.75,“大不了”、“更加”等記爲1.5,“多多少少”、“還”等記爲0.5,如果沒有程度詞,則記爲1,這樣的詞彙可以區分出每個被試者在博文中的情緒強弱,並以數字的形式表現出來。

5)計算否定詞權重:如果詞短句中出現“沒有”、“未必”等詞語時可以根據需要標記成-1或者-0.5,沒有否定詞則記爲1,通過這個方法來減少詞短句的權重。

6)計算關鍵詞權重:基於上面的計算我們將關鍵詞、程度詞和否定詞彙總在一起,形成我們對應關鍵詞的權重值:

 

關鍵詞權重=關鍵詞詞頻+程度詞權重*否定詞權重

 

上文中各個詞性的詞語可以按照項目的需要進行相應的調整,沒有統一的規則說是哪些詞一定在哪個項下,也沒有統一的規則確定每個詞性的權重值,具體的數值還是需要在應用的場景中仔細琢磨。

 

案例如下:

 

被試者在微博中發表了一個博文:“不過今天工作累死了,下班好好休息一下,真不想起牀呀,但願明天工作不這麼累”。

我們的分析步驟可以按照下面的流程一步步實現:

1)詞短句切分:

首先我們把上面這個博文按照“,”、“。”切分成四個詞短句,分別爲:[S1:“不過今天工作累死了”,S2:“下班好好休息一下”,S3:“真不想起牀呀”,S4:“但願明天工作不這麼累”]

2) 關鍵詞計算:

遍歷我們關注的關鍵詞,統計這個被試者對關鍵詞的使用頻次:

下表中關鍵詞記爲被選爲特徵值的關鍵詞,詞短句記爲含有該關鍵詞的詞短句,權重即爲詞短句出現的次數。

3) 程度詞計算:

微博片段出現程度詞“太”和“不過”,對應查詢程度詞表發現“太”的權重是2,“不過”的權重是1.75,所以,S1的程度詞權重爲:2+1.75=3.75;同理,S2的程度詞權重爲1,S3爲1,S4爲1。

 

4) 否定詞計算:

詞短句S1、S2中沒有否定詞,則否定詞權重記爲0,詞短句S3有否定詞“不”,則權重記爲-1,S4中有否定詞“不”,則權重記爲-1

 

5) 彙總出關鍵詞權重:

以此爲例,同理可以計算出“下班”、“休息”、“起牀”等關鍵詞的權重值。

對應計算公式如下:

 

梳理出上面的代碼,我們可以看到,越是在這種複雜的邏輯面前越體現python的簡潔:​​​​​​​

splitchar = [',', '.', '?', '!', ';', ',', '。', ';', '?', '!']# 每個微博號一個t:for r in range(0, len(data_com['com_contents'])):    t = data_com.loc[r, 'com_contents']    t_l = []    for j in splitchar:        t = t.replace(j, '=')    S = t.split('=')    # 對於每一個自變量關鍵詞:    for i in data_col:        # 計算i中對應的片段有多少:        S1 = [x for x in S if(len(x.split(i)) > 1)]        print(i)        # 遍歷各個S片段中哪些片段有i,權重記爲1:        t_q_z = 0        for s in S1:            # 計算每個片段中的目標詞,有次關鍵詞的記爲1            # len(s.split(i)) > 1:說明s片段中有關鍵詞            # 1、計算目標值頻次:            pic = len(s.split(i)) - 1 if(len(s.split(i)) > 1) else 0            # 2、計算程度詞和否定詞權重:            # 2.1)f1表示程度詞權重爲2:            q_f1 = sum([len(s.split(a)) - 1 for a in f1])            q_f11 = 1 if(q_f1 == 0) else q_f1 + 2            # 2.2)f2表示程度詞權重爲0.5:            q_f2 = sum([len(s.split(a)) - 1 for a in f2])            q_f21 = 1 if (q_f2 == 0) else q_f2 + 0.5            # 2.3)f3表示程度詞權重爲1.5:            q_f3 = sum([len(s.split(a)) - 1 for a in f3])            q_f31 = 1 if (q_f3 == 0) else q_f3 + 1.5            # 2.4)f4表示程度詞權重爲1.75:            q_f4 = sum([len(s.split(a)) - 1 for a in f4])            q_f41 = 1 if (q_f4 == 0) else q_f4 + 1.75            q_f = q_f11 + q_f21 + q_f31 + q_f41            # # 2.5)否定詞計算:            fd_f = sum([len(s.split(b)) - 1 for b in f5]) * (-1)            # 3)s的權重詞:            qz = pic +(q_f * fd_f)            t_q_z = t_q_z + qz        data_c.loc[r, i] = t_q_z

介紹到這裏,大家有沒有一些想法:所謂NLP,簡單講即爲區分各個詞語詞性的情況下,深度計算各個詞語之間的組合概率,尋找最大組合概率的詞語序列,並解讀其中的含義。案例中的這個方法有沒有這一思路的影子呢?筆者認爲是有的,所以,筆者在與小夥伴聊天的時候曾戲虐的說是初探NLP,也不算是一句妄言了。

關鍵詞的處理,除了上面直觀計算外還有一些比較簡單的分詞工具,可以讓大家既快捷又準確的切分各個關鍵詞,並計算對應的詞頻、詞性等,筆者瞭解的一個工具爲——文心繫統。是一個心理學領域的文本分析軟件,可以有效的切分各個關鍵詞並進行詞性計算。

如下即爲文心繫統的界面,操作較爲簡單,效果也非常明顯,不過問題在於只有win版的,蘋果系統無法使用這個軟件,略感可惜。

經過上面特徵工程的部分,我們的特徵處理可以說基本上處理完成了,接下來的部分,我們介紹一下在這個案例中使用的一些常用算法。由於前期對數據特徵的精細化處理,研究中並沒有選用一些較爲高深的算法模型,筆者相信:數據決定了結果的上限,而算法只是讓我們的結果無限逼近這個上限而已。

 

P3  模型構建

 

這次的研究我們儘可能的遍歷了常用的幾個算法,以求找到最佳的效果,確定最優的模型,結果表明:天下沒有免費的午餐,沒有哪個算法是有天然的優勢的,具體算法的好壞,還是需要根據項目中的特徵進行篩選比較的,或許讓你的模型更上一層樓的是一個你一直看不上的簡單算法,本案例就給筆者好好的上了一課。

本案例中,筆者使用了SVM、嶺迴歸、彈性網、CART、LR、GBDT、LASSO甚至使用GBDT+Ridge等融合模型,效果最好的不是這些貌似高大上的GBDT等算法,也不是理論基礎紮實的GBDT+Ridge等融合模型,而是一個不起眼的嶺迴歸模型Ridge。

接下來我們詳細描述一下研究的過程。

 

1)彙總特徵工程:

 

經過上面的特徵處理,我們得到了一個比較完成的特徵工程集合,其中不僅涵蓋了關鍵詞部分,也涵蓋了數值部分,並在此基礎上實現了降維處理,得到的特徵工程如下:

 

……

如上只展示數據的樣式,研究數據保密的原因無法全部呈現,請諒解~

 

2)進行連續值預測:

 

主要是將復工能力看做1-100的連續值,用連續值預測的模型訓練相應的結果,研究選用的連續性模型主要有嶺迴歸、線性迴歸、彈性網、CART樹等常用模型,由於sklearn良好的封裝效果,我們在使用這些模型的時候只需要進行函數調用即可。

連續型模型構建的效果檢驗我們使用的是修正的R方檢驗,越靠近1的效果越好,另外,在效果評估過程中,筆者曾用最簡單的相關係數進行效果檢驗,可以初步判斷效果,但最終還是要落地到R方的評估方法上來。

 

3)進行離散值預測:

 

連續型預測之後我們又嘗試用離散的形式進行模型構建,將y值進行二分處理,分別表示復工能力較高和復工能力較低兩類,訓練使用的模型爲:SVM、LR迴歸、GBDT等分類模型,訓練效果方面我們嘗試用最常見的幾種:精準率、召回率和F1-score檢驗三個方法,f1值效果較爲明顯,究其原因,f1檢驗是綜合了精準率和召回率的模型,能夠很好的進行效果評估。

如下爲代碼部分:

經過這一系列的訓練,我們會得出對當下被試人羣的預測值,用修正的R2進行檢驗發現:R2在0.4~0.5之間,證明這一方法在復工能力預測方面有一定的價值,也驗證了通過微博的情感分析來判斷人在實際生活中的行爲有一定的效果,爲行爲分析提供了可能性。

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