1. 快捷導航

            對共詞關系求協方差矩陣后再用Girvan-Newman算法做社區發現

            2022-10-21 15:56| 發布者: Fuller| 查看: 404| 評論: 0

            摘要: 本文使用中介中心度作為Girvan-Newman算法的指標,看起來先進行MST計算得到的效果更好。其實不難分析,因為MST得到的是一棵樹,只要裁掉一條邊,就變成了兩棵不連通的樹(樹也是圖)。另外,已經用MST生成了語義骨干 ...

            1  介紹

            此前我們寫了系列文章和notebook,通過分析共詞關系來分析文本的語義聚類。在《社區發現算法Girvan-Newman(GN)是否能應用于共詞矩陣?》,我們嘗試了使用Girvan-Newman算法,期望更直觀地發現語義聚集。但是,我們遇到了難題:長文本中共詞矩陣十分稠密,直接使用Girvan-Newman算法效率太低。本篇作為《對共詞關系求協方差矩陣后是否有更好的社會網絡分析結果?》的延伸,先經過社會網絡圖裁剪以后再進行社區發現,期望能提升分析效果。


            在《共詞分析中的共詞關系是怎么得到的?》一篇我們講解了共詞關系描述了什么,同時也提到,如果為了衡量詞與詞之間在文檔中的分布規律是否相似,還有其他一些度量方法。前面,通過《用networkx和python編程可視化分析共詞關系圖》這篇notebook,我們學會了怎樣用社會網絡圖分析和觀察共詞關系,通過《用MST(minimum or maximum spanning tree)算法簡化共詞關系圖》和《設置邊權重閾值裁剪共詞關系圖》學會了兩種簡化圖的方法,這兩種方法提供了兩個不同的視圖去觀察共詞關系。

            這些分析同樣的可以用在co-word之外的co-auther, co-cited, co-reference等等社會網絡分析中。用co-word進行演練有個好處:借助于GooSeeker分詞和情感分析軟件,一系列數據集唾手可得,而且可以很有意思地緊跟熱點,想研究二舅就研究二舅,想研究糖水爺爺就研究糖水爺爺。

            本notebook準備使用協方差矩陣來描述共詞關系,同共詞矩陣相比,這可以看作是更加細膩的考察,因為通過去中心化計算,詞在文檔中的分布規律不再是非負數描述的,而是有正有負,可以看作是有漲有跌,這樣,如果兩個詞有相同的漲跌,那么他們的協方差就會比較大,同時跌雖然都是負值,兩個負數相乘變成正數,為協方差的最終結果給予正向的貢獻。

            2  使用方法

            操作順序是:

            1. GooSeeker分詞和文本分析軟件上創建文本分析任務并導入包含待分析內容的excel,分析完成后導出選詞矩陣表。選詞矩陣表在NLP和機器學習領域也叫feature matrix
            2. 將導出的excel表放在本notebook的data/raw文件夾中
            3. 從頭到尾執行本notebook的單元

            注意:GooSeeker發布的每個notebook項目目錄都預先規劃好了,具體參看Jupyter Notebook項目目錄規劃參考。如果要新做一個分析項目,把整個模板目錄拷貝一份給新項目,然后編寫notebook目錄下的ipynb文件。

            3  修改歷史

            2022-10-20:第一版發布

            4  版權說明

            本notebook是GooSeeker大數據分析團隊開發的,所分析的源數據是GooSeeker分詞和文本分析軟件生成的,本notebook中的代碼可自由共享使用,包括轉發、復制、修改、用于其他項目中。

            5  準備運行環境

            5.1  引入需要用到的庫

            # -*- coding: utf-8 -*-

            ?

            import os

            import numpy as np

            import pandas as pd

            import networkx as nx

            import matplotlib.pyplot as plt

            import pylab

            ?

            from networkx.algorithms import community

            ?

            %xmode Verbose

            import warnings

            # 軟件包之間配套時可能會使用過時的接口,把這類告警忽略掉可以讓輸出信息簡練一些

            warnings.filterwarnings("ignore", category=DeprecationWarning)

            # 把RuntimeWarning忽略掉,不然畫圖的時候有太多告警了

            warnings.filterwarnings("ignore", category=RuntimeWarning)

            5.2  設置中文字體

            因為含有中文,plt畫圖會顯示下面的錯誤信息:

            C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\backends\backend_agg.py:238: RuntimeWarning: Glyph 32993 missing from current font. font.set_text(s, 0.0, flags=flags)

            為了防止plt顯示找不到字體的問題,先做如下設置。

            參看glyph-23130-missing-from-current-font

            #plt.rcParams['font.sans-serif']=['SimHei']

            # 上面一行在macOS上沒有效果,所以,使用下面的字體

            plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']

            plt.rcParams['axes.unicode_minus']=False

            5.3  常量和配置

            在我們發布的一系列Jupyter Notebook中,凡是處理GooSeeker分詞軟件導出的結果文件的,都給各種導出文件起了固定的名字。為了方便大家使用,只要把導出文件放在data/raw文件夾,notebook就會找到導出文件,賦值給對應的文件名變量。下面羅列了可能用到的文件名變量:

            file_all_word:詞頻表

            file_chosen_word: 選詞結果表

            file_seg_effect: 分詞效果表

            file_word_occurrence_matrix: 選詞矩陣表(是否出現)

            file_word_frequency_matrix: 文檔詞頻對應矩陣

            file_word_document_match: 選詞匹配表

            file_co_word_matrix: 共詞矩陣表


            pd.set_option('display.width', 1000)  # 設置字符顯示寬度

            pd.set_option('display.max_rows', None)  # 設置顯示最大

            # np.set_printoptions(threshold=np.inf) # threshold 指定超過多少使用省略號,np.inf代表無限大

            ?

            # 存原始數據的目錄

            raw_data_dir = os.path.join(os.getcwd(), '../../data/raw')

            # 存處理后的數據的目錄

            processed_data_dir = os.path.join(os.getcwd(), '../../data/processed')

            filename_temp = pd.Series(['詞頻','分詞效果','選詞矩陣','選詞匹配','選詞結果','共詞矩陣'])

            file_all_word = ''

            file_seg_effect = ''

            file_word_occurrence_matrix = ''

            file_word_frequency_matrix = ''

            file_word_document_match = ''

            file_chosen_word = ''

            file_co_word_matrix = ''

            5.4  檢測data\raw目錄下是否有GooSeeker分詞結果表

            在本notebook使用選詞矩陣表,不再是共詞矩陣表,因為選詞矩陣表含有更豐富的內容:每個詞在每篇文檔中出現的次數。下面的代碼將檢查data/raw中有沒有這個表,如果沒有會報錯,后面的程序就沒法執行了。

            # 0:'詞頻', 1:'分詞效果', 2:'選詞矩陣', 3:'選詞匹配', 4:'選詞結果', 5:'共詞矩陣'

            print(raw_data_dir + '\r\n')

            ?

            for item_filename in os.listdir(raw_data_dir):

                if filename_temp[2] in item_filename:

                    file_word_frequency_matrix = item_filename

                    continue

            ?

            if file_word_frequency_matrix:

                print("選詞矩陣表:", "data/raw/", file_word_frequency_matrix)

            else:

                print("選詞矩陣表:不存在")

            輸出結果如下:

            C:\Users\work\notebook\社區發現算法Girvan-Newman(GN)學習-對比\notebook\eda\../../data/raw

            選詞矩陣表: data/raw/ 選詞矩陣-知乎-二舅.xlsx

            6  讀取選詞矩陣表并存入矩陣

            讀入過程不展開講解,具體參看《共詞分析中的共詞關系是怎么得到的?

            6.1  用pandas dataframe讀入選詞矩陣

            df_word_frequency_matrix = pd.read_excel(os.path.join(raw_data_dir, file_word_frequency_matrix))

            df_word_frequency_matrix.head(2)

            6.2  提取字段名

            將用于給graph的node命名

            coword_names = df_word_frequency_matrix.columns.values[2:]

            print("There are ", len(coword_names), " words")

            coword_names

            輸出結果:

            There are  100  words

            array(['苦難', '精神', '內耗', '故事', '問題', '社會', '時代', '人生', '時候', '世界', '作者',

                   '殘疾', '中國', '作品', '農村', '城市', '現實', '電影', '命運', '人民', '東西', '底層',

                   '媒體', '文化', '年輕人', '人們', '事情', '感覺', '觀眾', '普通人', '孩子', '經歷', '一生',

                   '價值', '內容', '編劇', '雞湯', '能力', '年代', '時間', '原因', '能量', '意義', '老人',

                   '評論', '勵志', '文案', '村里', '資本', '醫生', '流量', '文藝創作', '國家', '藝術', '個人',

                   '情緒', '內心', '大眾', '朋友', '農民', '母親', '悲劇', '觀點', '大學', '機會', '思想',

                   '殘疾人', '文藝', '壓力', '力量', '角度', '心理', '父母', '分鐘', '方式', '人物', '老師',

                   '環境', '態度', '物質', '關系', '個體', '條件', '歷史', '情況', '群眾', '窮人', '房子',

                   '回村', '本質', '辦法', '官方', '平臺', '想法', '視角', '生命', '熱度', '地方', '醫療',

                   '身體'], dtype=object)

            6.3  生成矩陣數據結構

            # 使用astype函數對數據類型進行轉換,否則,下面畫圖的時候可能會報錯

            array_word_frequence_matrix = df_word_frequency_matrix.values[:, 2:].astype(float)

            array_word_frequence_matrix

            7  求協方差矩陣

            在《共詞分析中的共詞關系是怎么得到的?》我們說過,如果選詞矩陣稱為R,那么,RTR(R的轉置乘以R)就是共詞矩陣(這里假定R中只有0和1兩個值表示是否出現這個詞,我們下面的計算所用的不只是1,而是>=1的數值表示詞頻,原理一樣)。如果先把R去中心化得到矩陣B(轉換成mean deviation form),那么,BTB(B的轉置乘以B)就是協方差矩陣。

            covariance = np.cov(array_word_frequence_matrix, rowvar = False)

            covariance

            協方差矩陣是一個對稱矩陣,對角線上的值是每個詞的方差(variance),為了畫圖的時候不畫環回的邊,我們把對角線的所有值賦0

            np.fill_diagonal(covariance, 0)

            covariance

            8  生成圖并進行探索

            8.1  從NumPy數組生成networkx圖

            參看networkx文檔,有專門的函數從其他數據結構直接生成graph

            graph_covariance = nx.from_numpy_array(covariance)

            print(nx.info(graph_covariance))

            #graph_covariance.edges(data=True)

            輸出結果:

            Name: 

            Type: Graph

            Number of nodes: 100

            Number of edges: 4950

            Average degree:  99.0000

            8.2  給node加上label

            對程序代碼的解釋參看《用networkx和python編程可視化分析共詞關系圖》,不再贅述。

            coword_labels = {}

            for idx, node in enumerate(graph_covariance.nodes()): 

                print("idx=", idx, "; node=", node)

                coword_labels[node] = coword_names[idx]

            graph_covariance = nx.relabel_nodes(graph_covariance, coword_labels)

            sorted(graph_covariance)

            8.3  畫圖

            figure函數的使用方法參看pyplot官網 。其他參考資料:

            由于是一個全連接圖,就沒有畫的必要了,下面的代碼都注釋掉了。

            #pos = nx.spring_layout(graph_covariance)

            #plt.figure(1,figsize=(120,120)) 

            #nx.draw(graph_covariance, pos, node_size=10, with_labels=True, font_size=22, font_color="red")

            #plt.show()

            9  定義畫社區圖的函數

            # 用這個函數,可以最多畫4種顏色不同的社區

            def plot_communities(G, group_array):

                color_map = []

                for node in G:

                    found = False

                    for idx, group in enumerate(group_array):

                        if node in group:

                            found = True

                            if idx == 0:

                                color_map.append('blue')

                            elif idx == 1:

                                color_map.append('green')

                            elif idx == 2:

                                color_map.append('orange')

                            elif idx == 3:

                                color_map.append('red')

                            else:

                                color_map.append('purple')

                    if found == False:

                        color_map.append('black')

            ?

                pos = nx.spring_layout(G)

                plt.figure(1,figsize=(15,15))

                #nx.draw(G, pos, node_size=100, font_size=22, node_color=color_map, with_labels=True, font_color='white')

                nx.draw(G, pos, node_color=color_map, with_labels=True, font_color='white')

                plt.show()

            10  用MST(maximum spanning tree)刪減邊

            10.1  MST計算

            graph_covariance_mst = nx.maximum_spanning_tree(graph_covariance)

            print(nx.info(graph_covariance_mst))

            # graph_covariance_mst.edges(data=True)

            輸出結果:

            Name: 

            Type: Graph

            Number of nodes: 100

            Number of edges: 99

            Average degree:   1.9800

            10.2  畫MST后的圖

            #pos = nx.circular_layout(graph_covariance_mst)

            pos = nx.spring_layout(graph_covariance_mst)

            plt.figure(2,figsize=(15,15)) 

            nx.draw(graph_covariance_mst, pos, node_size=50, with_labels=True, font_size=15, font_color="red")

            plt.show()

            10.3  社區發現

            10.3.1  分拆社區

            comm_gen = community.girvan_newman(graph_covariance_mst)

            top_level_co_word = sorted(map(sorted, next(comm_gen)))

            top_level_co_word

            second_level_co_word = sorted(map(sorted, next(comm_gen)))

            second_level_co_word

            third_level_co_word = sorted(map(sorted, next(comm_gen)))

            third_level_co_word

            10.3.2  畫社區圖

            前面我們做了三層分解,那么就用這三層分解的結果分別畫圖,以示對比

            plot_communities(graph_covariance_mst, top_level_co_word)

            plot_communities(graph_covariance_mst, second_level_co_word)

            plot_communities(graph_covariance_mst, third_level_co_word)

            11  設定閾值刪減邊

            11.1  選擇閾值

            刪掉多少邊比較好呢?我們先看看這些位置上的邊權重是多少:

            • 中位數
            • 10%位
            • 2%位

            coword_median = np.median(covariance)

            coword_median

            輸出結果:

            0.008842583189465455

            coword_max = np.max(covariance)

            coword_max

            輸出結果:

            2.4578551843200986

            coword_min = np.min(covariance)

            coword_min

            輸出結果:

            -0.060885718154429454

            coword_per10 = np.percentile(covariance, 90)

            coword_per10

            輸出結果:

            0.0691976828814191

            coword_per2 = np.percentile(covariance, 98)

            coword_per2

            輸出結果:

            0.22641354388815757

            11.2  刪除權重小于2%分位的邊

            我們不挨個嘗試刪減度了,直接實驗重度刪減后的效果

            graph_covariance_per2 = graph_covariance.copy()

            graph_covariance_per2.remove_edges_from([(n1, n2) for n1, n2, w in graph_covariance_per2.edges(data="weight") if w < coword_per2])

            pos = nx.spring_layout(graph_covariance_per2)

            plt.figure(1,figsize=(15,15)) 

            nx.draw(graph_covariance_per2, pos, node_size=10, with_labels=True, font_size=15, font_color="red")

            plt.show()

            11.3  刪除基于2%分位裁剪的圖的孤立點

            graph_covariance_per2.remove_nodes_from(list(nx.isolates(graph_covariance_per2)))

            #pos = nx.circular_layout(graph_covariance_per2)

            pos = nx.spring_layout(graph_covariance_per2)

            plt.figure(1,figsize=(15,15)) 

            nx.draw(graph_covariance_per2, pos, node_size=10, with_labels=True, font_size=15, font_color="blue")

            plt.show()

            11.4  社區發現

            11.4.1  分拆社區

            comm_gen = community.girvan_newman(graph_covariance_per2)

            top_level_cov_per2 = sorted(map(sorted, next(comm_gen)))

            top_level_cov_per2

            second_level_cov_per2 = sorted(map(sorted, next(comm_gen)))

            second_level_cov_per2

            third_level_cov_per2 = sorted(map(sorted, next(comm_gen)))

            third_level_cov_per2

            11.4.2  畫社區圖

            plot_communities(graph_covariance_per2, top_level_cov_per2)

            plot_communities(graph_covariance_per2, second_level_cov_per2)

            plot_communities(graph_covariance_per2, third_level_cov_per2)

            12  總結

            本文使用中介中心度作為Girvan-Newman算法的指標,看起來先進行MST計算得到的效果更好。其實不難分析,因為MST得到的是一棵樹,只要裁掉一條邊,就變成了兩棵不連通的樹(樹也是圖)。另外,已經用MST生成了語義骨干,再用Girvan-Newman算法結合上色顯示,僅僅是提升了一下顯示效果。相對來說,將Girvan-Newman算法用于根據閾值裁剪的圖的作用更大,因為即使做了大幅度裁剪,連通關系還是很復雜,使用Girvan-Newman算法可以進一步聚類一下。

            13  下載源代碼

            點擊下載Jupyter Notebook源代碼:社區發現算法Girvan-Newman(GN)學習-對比.zip


            鮮花

            握手

            雷人

            路過

            雞蛋

            最新評論

            GMT+8, 2022-11-23 09:56

            欧美一级午夜福利免费区