1. 快捷導航

            社區發現算法Girvan-Newman(GN)是否能應用于共詞矩陣?

            2022-10-20 18:56| 發布者: Fuller| 查看: 425| 評論: 0

            摘要: 我們將用多個notebook和文章演示社群劃分的方法。本篇notebook先演示用Python實現Girvan-Newman算法。演示了兩種方法:1,手工寫Girvan-Newman算法;2,使用networkx的函數。手工寫Girvan-Newman算法僅作演示用,不 ...

            1  前言

            此前,我們學習了一篇和Gephi相關的研究范文《基于引文網絡和語義分析的技術演化路徑識別及拓展研究》,該范例作者使用Gephi軟件作為網絡分析的工具,同時運用Girvan-Newman算法對引文網絡進行社群劃分和主路徑提取。接下來我們將用多個notebook和文章演示社群劃分的方法。本篇notebook先演示用Python實現Girvan-Newman算法。演示了兩種方法:1,手工寫Girvan-Newman算法;2,使用networkx的函數。手工寫Girvan-Newman算法僅作演示用,不建議在實際項目項目中使用。下面手工寫的Girvan-Newman算法也沒有經過大量測試,所以,要采用第二種方法。

            我們今天就Girvan-Newman算法做一次編程練習和實驗,期望能夠形成一個初步認識:針對什么樣的數據可以做社>**(不當用詞)現。

            另外,Gephi也有社群分析功能,我們將在接下來的文章中介紹Gephi的用法,這里先做個簡單介紹。

            Gephi是一款很強的網絡可視化分析軟件,下面是Gephi官網提到的幾個功能:

            • 社交網絡分析:輕松創建社交數據連接器,以映射社區組織和小世界網絡。
            • 探索性數據分析:通過網絡操作進行實時直覺分析。
            • 鏈接分析:揭示對象之間關聯的底層結構。
            • 生物網絡分析:表示生物數據的模式。
            • 海報制作:通過高質量的可打印地圖進行科學的工作推廣。

            有關Gephi的學習,可以參考我們發布的系列文章:

            另外,我們也發布了多篇Jupyter Notebook,使用Python進行各種算法的演練,比如在這篇《對共詞關系求協方差矩陣后是否有更好的社會網絡分析結果?》中,我們演練了怎樣用協方差矩陣表示共詞矩陣,同時講解了使用協方差矩陣的意義,并且設想了更進一步編程探索的方向。

            2  Girvan-Newman算法是什么?

            Girvan-Newman算法是一種社交網絡的聚類方法,簡稱GN算法。

            以下對社區發現和GN算法的解釋和圖片,參考了這2篇知乎文章:《Girvan和Newman社團發現算法》,《社區發現算法-GN》。

            2.1  網絡中的社區/社群是什么?

            所謂社區/社群就是:其內部頂點的連接稠密,而與其他社區內的頂點連接稀疏。

            這就意味著社區與社區之間聯系的通道比較少,一個社區到另一個社區至少要通過這些通道中的一條。

            下面,我們將混用“社區”和“社群”,當成一回事。

            2.2  什么是社區發現

            一個社區由一組連接緊密的結點組成,同時這些結點與社區外部的結點連接稀疏,如下圖所示。那么,社區發現就是在復雜網絡中發現這些連接緊密的社區結構。其實,社區發現可以理解為網絡中的結點聚類。下圖引用自《社區發現算法-GN

            2.3  什么是Girvan-Newman算法(GN算法)?

            GN算法是社區發現中的第一個算法,也就是它開啟了這個研究領域。它的基本思想是刪除掉那些社區之間的連接,那么剩下的每個連通部分就是一個社區。那么問題來了,就是哪些是社區之間的邊呢?作者巧妙地借助最短路徑解決了這個問題,他們定義一條邊的介數(betweeness)為網絡中所有結點之間的最短路徑中通過這條邊的數量,而介數高的邊要比介數低的邊更可能是社區之間的邊。其實,這也比較好理解,因為兩個社區中的結點之間的最短路徑都要經過那些社區之間的邊,所以它們的介數會很高。

            GN算法每次都刪除網絡中介數最大的邊,直至網絡中的所有邊都被刪除。這樣GN的過程對應著一顆自頂向下構建的層次樹。在層次樹中選擇一個合適的層次分割即可。下圖引用自《社區發現算法-GN

            GN算法的基本流程如下:

            1. 計算網絡中各條邊的邊介數;
            2. 找出邊介數最大的邊,并將它移除(如果最大邊介數的邊不唯一,那么既可以隨機挑選一條邊斷開也可以將這些邊同時斷開);
            3. 重新計算網絡中剩余各條邊的邊介數;
            4. 重復第2)、3)步,直到網絡中所有的邊都被移除。

            3  使用方法

            操作順序是:

            1. 在GooSeeker分詞和文本分析軟件上創建文本分析任務并導入包含待分析內容的excel,分析完成后導出共詞矩陣表
            2. 將導出的excel表放在本notebook的data/raw文件夾中
            3. 從頭到尾執行本notebook的單元

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

            4  實驗數據

            本Notebook針對不同的實驗數據使用不同的計算方法做了多個實驗,通過對比選擇最好的方法:

            實驗一:使用了networkx自帶的空手道俱樂部數據,分別實驗自定義Girvan-Newman算法和networkx提供的算法

            實驗二:使用了從知乎采集得到的有關話題“二舅”的社交媒體數據,經GooSeeker分詞軟件選詞處理后導出的共詞矩陣表(一共100個詞頻數高并且文檔頻數也高的詞)。

            實驗三:針對“二舅”數據,不使用缺省的中介中心度,而是采用其他指標進行社區發現

            5  修改歷史

            2022-10-15:第一版發布

            6  版權說明

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

            7  準備運行環境

            7.1  引入需要用到的庫

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

            ?

            import networkx as nx

            import matplotlib.pyplot as plt

            import os

            import numpy as np

            import pandas as pd

            import pylab

            ?

            %xmode Verbose

            import warnings

            ?

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

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

            ?

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

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

            %matplotlib inline

            7.2  設置中文字體

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

            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)

            這是因為找不到中文字體,所以在圖上的中文顯示不出來,為了解決pyplot顯示找不到字體的問題,參看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

            # 下面的配置用于解決windows下畫圖不顯示中文的問題

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

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

            8  實驗一:基于networkx自帶數據

            networkx自帶的空手道俱樂部測試數據做Girvan-Newman算法實驗,從下面的網絡圖可以看到,這個數據集有很好的分群特征。

            8.1  基于測試數據生成圖并顯示

            # load the graph

            G = nx.karate_club_graph()

            nx.draw(G, with_labels = True)

            8.2  輸出圖的節點數和邊條數

            len(G.nodes), len(G.edges)

            輸出結果:

            (34, 78)

            8.3  算法1: 使用自定義Girvan Newman算法

            僅作為演示和體驗算法原理只用,在實際項目中盡量采用networkx和numpy等程序庫現有的算法,以獲得更好的性能。

            自定義算法有下面特點:

            • 只根據介數進行分拆
            • 只要分拆到非連通圖,就停止分拆

            8.3.1  定義函數:執行后返回目前需要刪除的邊

            按GN算法的定義,選擇介數中心性最大的邊作為需要刪除的邊

            def edge_to_remove(graph):

              G_dict = nx.edge_betweenness_centrality(graph)

              edge = ()

            ?

              # extract the edge with highest edge betweenness centrality score

              for key, value in sorted(G_dict.items(), key=lambda item: item[1], reverse = True):

                  edge = key

                  break

            ?

              return edge

            8.3.2  定義函數:實現GN算法

            1. 計算網絡中各條邊的邊介數;
            2. 找出邊介數最大的邊,并將它移除(如果最大邊介數的邊不唯一,那么既可以隨機挑選一條邊斷開也可以將這些邊同時斷開);
            3. 重新計算網絡中剩余各條邊的邊介數;
            4. 重復第2)、3)步,直到網絡中所有的邊都被移除。

            def girvan_newman(graph):

              # find number of connected components

              sg = nx.connected_components(graph)

              sg_count = nx.number_connected_components(graph)

            ?

              while(sg_count == 1):

                to_remove = edge_to_remove(graph)

                graph.remove_edge(to_remove[0], to_remove[1])

                sg = nx.connected_components(graph)

                sg_count = nx.number_connected_components(graph)

            ?

              return sg

            8.3.3  針對已經生成的測試圖,尋找社區并輸出節點

            # find communities in the graph

            c = girvan_newman(G.copy())

            ?

            # find the nodes forming the communities

            node_groups = []

            ?

            for i in c:

              node_groups.append(list(i))

            8.3.4  輸出圖,不同社區的節點以不同顏色顯示

            # plot the communities

            color_map = []

            for node in G:

                if node in node_groups[0]:

                    color_map.append('blue')

                else: 

                    color_map.append('green')  

            ?

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

            plt.show()

            8.4  算法2: 使用networkx提供的算法

            networkx的community算法有很多,不只是Girvan Newman算法,所以盡量采用networkx提供的算法,熟練使用networkx以期獲得最大能力和性能。

            networkx提供的girvan_newman算法生成了分層的社區,根據需要選擇深入觀察到第幾層??梢园l現,如果觀察到第一層,那么結果跟自定義算法是一樣的

            from networkx.algorithms import community

            8.4.1  拆分社區

            communities_generator = community.girvan_newman(G.copy())

            top_level_communities = next(communities_generator)

            top_level_communities

            輸出結果:

            ({0, 1, 3, 4, 5, 6, 7, 10, 11, 12, 13, 16, 17, 19, 21},

             {2, 8, 9, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33})

            如果拆分到第二層,看到的結果是這樣的

            next_level_communities = next(communities_generator)

            next_level_communities

            輸出結果:

            ({0, 1, 3, 4, 5, 6, 7, 10, 11, 12, 13, 16, 17, 19, 21},

             {2, 8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33},

             {9})

            還可以繼續拆分成第三層,是這樣的

            third_level_communities = next(communities_generator)

            third_level_communities

            輸出結果:

            ({0, 1, 3, 7, 11, 12, 13, 17, 19, 21},

             {2, 8, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33},

             {4, 5, 6, 10, 16},

             {9})

            8.4.2  轉換成數組

            因為數組比較好處理

            top_level_array = sorted(map(sorted, top_level_communities))

            top_level_array

            輸出結果:

            [[0, 1, 3, 4, 5, 6, 7, 10, 11, 12, 13, 16, 17, 19, 21],

             [2, 8, 9, 14, 15, 18, 20, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]]

            8.4.3  定義更通用的標注社區的畫圖程序

            # 用這個函數,可以最多畫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')

            ?

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

                plt.show()

            一層層畫圖

            plot_communities(G, top_level_array)

            plot_communities(G, sorted(map(sorted, next_level_communities)))

            plot_communities(G, sorted(map(sorted, third_level_communities)))

            9  實驗二:發現GooSeeker分詞軟件導出的共詞矩陣表中的社群

            使用GooSeeker分詞軟件導出的共詞矩陣表做Girvan-Newman算法實驗,下面不再使用自定義函數,而是使用networkx自帶的函數。

            9.1  常量和配置

            在我們發布的一系列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 = ''

            9.2  檢測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[5] in item_filename:

                    file_co_word_matrix = item_filename

                    continue

            ?

            if file_co_word_matrix:

                print("共詞矩陣表:", "data/raw/", file_co_word_matrix)

            else:

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


            輸出結果如下:

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

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

            9.3  讀取共詞矩陣表并存入矩陣

            讀入過程不展開講解,具體參看《共詞分析中的共詞關系是怎么得到的?》。這篇文章也對比了共詞矩陣和選詞矩陣的不同使用場合。為了更好的分辨社區,本notebook也會展示用選詞矩陣得到的分析效果。

            9.3.1  用pandas dataframe讀入共詞矩陣

            df_co_word_matrix = pd.read_excel(os.path.join(raw_data_dir, file_co_word_matrix))

            df_co_word_matrix.head(2)

            9.3.2  提取字段名

            將用于給graph的node命名

            coword_names = df_co_word_matrix.columns.values[1:]

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

            coword_names

            輸出結果如下:

            There are  100  words

            array(['世界', '時候', '作品', '東西', '故事', '現實', '個人', '時間', '人生', '時代', '人民',

                   '事情', '社會', '苦難', '感覺', '人們', '中國', '問題', '精神', '年輕人', '底層', '回村',

                   '內耗', '作者', '一生', '孩子', '命運', '態度', '殘疾', '經歷', '普通人', '農村', '價值',

                   '原因', '媒體', '城市', '房子', '力量', '母親', '觀眾', '地方', '本質', '評論', '國家',

                   '意義', '角度', '辦法', '老人', '內心', '文案', '流量', '方式', '雞湯', '能量', '醫生',

                   '能力', '年代', '內容', '電影', '環境', '情況', '老師', '農民', '關系', '視角', '大眾',

                   '情緒', '條件', '壓力', '文化', '分鐘', '朋友', '窮人', '人物', '村里', '資本', '想法',

                   '觀點', '大學', '心理', '思想', '父母', '群眾', '文藝創作', '個體', '機會', '悲劇', '歷史',

                   '藝術', '勵志', '殘疾人', '文藝', '平臺', '生命', '身體', '編劇', '物質', '熱度', '醫療',

                   '官方'], dtype=object)

            9.3.3  生成矩陣數據結構

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

            array_co_word_matrix = df_co_word_matrix.values[:, 1:].astype(float)

            array_co_word_matrix

            word_num = len(array_co_word_matrix)

            word_num

            輸出結果如下:

            100

            9.3.4  對角線賦0

            為了避免對角線上畫出來自環邊。

            np.fill_diagonal(array_co_word_matrix, 0)

            array_co_word_matrix

            9.4  生成圖并進行探索

            9.4.1  從NumPy數組生成networkx圖

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

            #graph_co_word_df = nx.from_pandas_adjacency(df_co_word_matrix)

            graph_co_word_matrix = nx.from_numpy_array(array_co_word_matrix)

            print(nx.info(graph_co_word_matrix))

            #graph_co_word_matrix.edges(data=True)

            輸出結果如下:

            Name: 

            Type: Graph

            Number of nodes: 100

            Number of edges: 4746

            Average degree:  94.9200

            9.4.2  給node加上label

            如果不加label,畫出來的圖上的每個節點只是一個編號,加上label可以看到節點對應的詞。

            根據get_node_attributes,查看現在的note labels

            coword_labels = nx.get_node_attributes(graph_co_word_matrix,'labels')

            coword_labels

            輸出結果如下:

            {}

            根據How-do-I-label-a-node-using-networkx-in-python,重新命名labels

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

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

                coword_labels[node] = coword_names[idx]

            graph_co_word_matrix = nx.relabel_nodes(graph_co_word_matrix, coword_labels)

            sorted(graph_co_word_matrix)

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

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

            9.4.3  畫圖

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

            # 方案1:用pylab畫圖

            #pos=nx.shell_layout(graph_co_word_matrix)

            #nx.draw(graph_co_word_matrix,pos,with_labels=True, node_color='white', edge_color='grey', node_size=1200, alpha=1 )

            #pylab.title('co-word matrix',fontsize=25)

            #pylab.show()

            ?

            # 方案2

            #pos = nx.circular_layout(maximum_tree)

            pos = nx.spring_layout(graph_co_word_matrix)

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

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

            #nx.draw(graph_co_word_matrix, pos, with_labels=True)

            #nx.draw_networkx_labels(graph_co_word_matrix, pos, labels)

            plt.show()

            graph_co_word_dis_15 = graph_co_word_matrix.copy()

            edges = graph_co_word_dis_15.edges(data=True)

            for u, v, d in edges:

                d["weight"] //= 15

            ?

            pos = nx.spring_layout(graph_co_word_dis_15)

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

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

            plt.show()

            9.5  社區發現

            針對已經生成的圖,尋找社區并輸出節點。你會發現效果很不好,在每一層只能分出一個詞。因為這個數據集從知乎上用網絡爬蟲采集下來的,每篇內容都很長,那么,詞與詞之間的關系十分稠密,從上圖就能看出來,幾乎都全互聯的,那么介數這個指標幾乎沒有太大區分的作用。

            9.5.1  分拆社區

            communities_generator = community.girvan_newman(graph_co_word_matrix.copy())

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

            top_level_co_word

            第一層的效果很不好,只有一個詞“官方”分出來了。因為“二舅”這批數據是用網絡爬蟲從知乎回答爬下來的,每個回答比較長,所有的詞之間的連接很稠密,不同詞之間的中介中心性基本一致。

            試試第二層

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

            second_level_co_word

            9.5.2  畫社區圖

            雖然分到第二層,效果依然不好。前面已經分析了原因,繼續分拆下去也不會有理想的結果,所以,我們要嘗試其他計算指標。暫時先畫一下第二層的社區圖,幾乎看不到有意義的信息。

            plot_communities(graph_co_word_matrix, second_level_co_word)

            10  實驗三:為共詞矩陣定義其他社區發現指標

            networkx提供的girvan_newman函數,允許提供一個函數參數,這個函數用來計算其他指標。參看networkx community案例

            我們自然會想到圖上面的邊的權重。在共詞矩陣中,權重表示共現發生的次數,用這個權重疊加到中介中心性上,可以將原先中介中心性相同的區分開來。

            10.1  利用權重屬性

            10.1.1  定義most_valuable_edge函數

            我們定義了兩個函數。如果權重越大越重要,那么就應該使用第二個,把權重小的先剔除。

            from operator import itemgetter

            def heaviest(G):

                u, v, w = max(G.edges(data="weight"), key=itemgetter(2))

                return (u, v)


            from operator import itemgetter

            def lightest(G):

                u, v, w = min(G.edges(data="weight"), key=itemgetter(2))

                return (u, v)

            10.1.2  探索edge屬性

            edges = graph_co_word_matrix.edges(data=True)

            for edge in edges:

                print(edge)

            #for u, v in edges:

            #    print("u = ", u, "\nv = ", v)

            graph_co_word_matrix.edges(data="weight")

            print("u = ", u, "; v = ", v, ", w = ", w)

            輸出結果如下:

            u =  精神 ; v =  內耗 , w =  147.0

            10.1.3  使用權重分拆社區

            #com_gen = community.girvan_newman(graph_co_word_matrix.copy(), most_valuable_edge=heaviest)

            com_gen = community.girvan_newman(graph_co_word_matrix.copy(), most_valuable_edge=lightest)

            top_level_co_word_weight = sorted(map(sorted, next(com_gen)))

            top_level_co_word_weight

            second_level_co_word_weight = sorted(map(sorted, next(com_gen)))

            second_level_co_word_weight

            third_level_co_word_weight = sorted(map(sorted, next(com_gen)))

            third_level_co_word_weight

            10.1.4  畫社區圖

            可以看到,經過三輪分拆,每次拆出一個詞,分拆速度太慢了,畫圖效果如下,很不好。需要想辦法提高分拆速度。

            plot_communities(graph_co_word_matrix, third_level_co_word_weight)

            10.2  壓縮權重的層級

            前面我們在畫原始數據圖的時候,嘗試了壓縮權重的層級。原先最大權重是147,也就是說,可能有147級。如果壓縮成7級,分拆速度是否會快很多?

            經過實驗發現,社區發現算法其實也在逐步裁剪邊,但是,這個算法不是為裁剪邊設計的,用它來裁剪邊的速度太低了,一次裁掉一個。

            graph_co_word_dis_5 = graph_co_word_matrix.copy()

            edges = graph_co_word_dis_5.edges(data=True)

            for u, v, d in edges:

                d["weight"] //= 20

                

            pos = nx.spring_layout(graph_co_word_dis_5)

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

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

            plt.show()

            edges

            com_gen = community.girvan_newman(graph_co_word_dis_5.copy(), most_valuable_edge=lightest)

            top_level_co_word_dis_5 = sorted(map(sorted, next(com_gen)))

            top_level_co_word_dis_5

            second_level_co_word_dis_5 = sorted(map(sorted, next(com_gen)))

            second_level_co_word_dis_5

            third_level_co_word_dis_5 = sorted(map(sorted, next(com_gen)))

            third_level_co_word_dis_5

            forth_level_co_word_dis_5 = sorted(map(sorted, next(com_gen)))

            forth_level_co_word_dis_5

            fifth_level_co_word_dis_5 = sorted(map(sorted, next(com_gen)))

            fifth_level_co_word_dis_5

            sixth_level_co_word_dis_5 = sorted(map(sorted, next(com_gen)))

            sixth_level_co_word_dis_5

            10.3  權重加中介中心性

            10.3.1  定義most_valuable_edge函數

            from networkx import edge_betweenness_centrality as betweenness

            def most_central_edge(G):

                centrality = betweenness(G, weight="weight")

                return max(centrality, key=centrality.get)

            10.3.2  分拆社區

            下面的計算會花很長時間。因為這個數據集有100個節點,但是,計算結果依然沒有改善。因為由girvan_newman算法決定了不會有理想的結果,只會一層層把當前層數值最大的一個節點篩選出來。

            com_gen = community.girvan_newman(graph_co_word_matrix, most_valuable_edge=most_central_edge)

            top_level_co_word_bt_weight = sorted(map(sorted, next(com_gen)))

            top_level_co_word_bt_weight

            并沒有看到改善,再往下看一層試試:

            second_level_co_word_bt_weight = sorted(map(sorted, next(com_gen)))

            second_level_co_word_bt_weight

            11  總結

            經過上面的實驗過程,我們僅僅練習了networkx的社區發現的編程方法,但是,并沒有從GooSeeker分詞軟件導出的共詞矩陣中有所發現。

            我們期望能否發現多個詞從語義方面形成的聚集,但是,上述實驗沒有達到目的。每一層社區分解只能分出一個詞。因為這個數據集從知乎上用網絡爬蟲采集下來的,每篇內容都很長,那么,詞與詞之間的關系十分稠密,從上圖就能看出來,幾乎都全互聯的,那么介數這個指標幾乎沒有太大意義。

            我們嘗試了調整權重的值,最多取5個不同的值,但是,用發現社區算法效果依然不好。至此,我們自然會想到,可以先對圖進行裁剪,剩下骨干詞以后再進行社區發現。

            我們此前發布的Jupyter Notebook探索了文本處理中的選詞矩陣的作用,以及在其上進行協方差處理的意義,然后再對協方差矩陣形成的圖進行裁剪,可以觀察到很好的詞聚集現象。參看《對共詞關系求協方差矩陣后是否有更好的社會網絡分析結果?》。那么,接下來一個notebook將專門進行探索。

            12  下載源代碼

            下載Jupyter Notebook源代碼,請進入《對共詞關系求協方差矩陣后再用Girvan-Newman算法做社區發現


            鮮花

            握手

            雷人

            路過

            雞蛋

            最新評論

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

            欧美一级午夜福利免费区