實例需求:產品清單如A列所示,現在如下統計詞組詞頻。想必各位小伙伴都指定如何使用字典對象實現去重,進而實現單個單詞的詞頻統計。
但是統計詞組詞頻就沒有那么簡單了,為了便于演示,此處的詞組只限于兩個單詞的組合。提到詞組,很多時候大家先想到的是如何將獲取全部的組合,例如n個無重復單詞,可以產生的無重復詞組個數為C(n,2) ,但是在本示例中并不需要獲取這些全部組合,實現思路自然也就不同了。
示例代碼如下。
Sub CountWorPair()Dim oDic1 As Object, oDic2 As Object, oDic3 As ObjectDim aProd, vProd, aWord, vWord, vKey, arrDataDim sKey1 As String, sKey2 As StringDim i As Long, j As Long, k As LongSet oDic1 = CreateObject("scripting.dictionary")Set oDic2 = CreateObject("scripting.dictionary")Set oDic3 = CreateObject("scripting.dictionary")arrData = Range("A1").CurrentRegion.ValueFor i = LBound(arrData) + 1 To UBound(arrData)aWord = Split(arrData(i, 1))For Each vWord In aWordIf oDic1.exists(vWord) ThenoDic1(vWord) = oDic1(vWord) & "," & arrData(i, 1)ElseoDic1(vWord) = arrData(i, 1)End IfNextNext iFor Each vKey In oDic1.keysaProd = Split(oDic1(vKey), ",")oDic2.RemoveAllFor Each vProd In aProdaWord = Split(vProd)For Each vWord In aWordIf oDic2.exists(vWord) ThenoDic2(vWord) = oDic2(vWord) + 1ElseoDic2(vWord) = 1End IfNextNextFor Each vWord In oDic2.keysIf vWord <> vKey ThensKey1 = vKey & " " & vWordsKey2 = vWord & " " & vKeyIf oDic3.exists(sKey1) ThenIf oDic2(vWord) > oDic3(sKey1) Then oDic3(sKey1) = oDic2(vWord)ElseIf oDic3.exists(sKey2) ThenIf oDic2(vWord) > oDic3(sKey2) Then oDic3(sKey2) = oDic2(vWord)ElseoDic3(sKey1) = oDic2(vWord)End IfEnd IfNextNextRange("D:E").ClearRange("D1:E1").Value = Array("Word Pair", "Times")Range("D2").Resize(oDic3.Count, 1) = Application.Transpose(oDic3.keys)Range("E2").Resize(oDic3.Count, 1) = Application.Transpose(oDic3.items)
End Sub
【代碼解析】
第6~7行代碼創建字典對象。
- oDic1用于按照單詞合并產品名稱,即字典鍵為單詞,字典值為逗號連接的產品名稱。
- oDic2用于統計每個單詞的出現次數,注意并非全部產品的詞頻。
- oDic3用于統計詞組(兩個單詞組合)的詞頻。
第9行代碼將數據表加載到數組中。
第10~19行代碼循環處理每行數據,按照單詞合并產品名稱,oDic1("Red")
的值為所有包含Red的產品名稱。
第14行代碼合并產品名稱。
第16行代碼為字典對象添加鍵值。
第20~42行代碼循環遍歷oDic1中的鍵,最終實現統計詞組詞頻。
第21行代碼讀取oDic1的值(逗號連接的產品名稱),并按照逗號拆分為產品列表(數組)。
第22行代碼清空oDic2對象。
第23~32行代碼循環變量產品列表aProd。
第24行代碼將產品列表拆分為單詞列表aWord。
第25~31行代碼統計單詞詞頻。例如處理oDic1("Red")
時,將統計包含Red的產品名稱中,每個單詞出現的次數。
第33~41行代碼循環遍歷oDic2中的鍵,統計詞組詞頻。
第34行代碼判斷oDic1鍵是否與oDic2鍵相同,由于產品名稱中不會出現重復的單詞,因此Red Red
屬于無效的詞組。
第35~36行代碼將兩個鍵值按照不同的次序進行組合。
這里是本示例中的小技巧,由于Red Car
和Car Red
實際上屬于同一個詞組,二者的詞頻也移動相同,因此在輸出結果中只需要保留一個即可,所以此處需要將創建兩個變量sKey1和sKey2。
第37行代碼判斷oDic3中是否已經存在sKey1和sKey2,如果不存在,那么第38行代碼在oDic3中添加鍵值。
這個邏輯看起來有些復雜,下面舉例說明。
以詞組Red Car
為例,oDic1("Red")
的值為Red Car,Red Kia Car
,經過拆分統計oDic2("Car")
的值為2
,即詞頻為2,最終oDic3("Red Car")
的值2
,當然結果字典中也可能是oDic3("Car Red")
。
第43行代碼清空目標單元格區域。
第44行代碼設置表格標題。
第45行代碼將詞組(oDic3的鍵)寫入D列。
第45行代碼將詞頻(oDic3的值)寫入E列。
微軟文檔:
Dictionary object
Range.Resize property (Excel)