Python構建共現矩陣並將其三元組形式存儲至csv文件

引言:共現矩陣有什麼用?

主要用於發現主題,解決詞向量相近關係的表示;
將共現矩陣行(列)作爲詞向量,其表現形式類似於數據結構中圖論裏學的鄰接矩陣。在本文中,筆者主要用來統計會議論文作者之間的合作關係。
【舉例】:假設有四篇論文,每篇論文作者名字如下。
在這裏插入圖片描述
我們根據上述原始數據構建如下共現矩陣,由如下矩陣可以看出,Yang LiuWenwu Zhu在上述窗口中共同出現(co-occurrence)過3次,其實際含義爲這兩個作者進行過3次合作,共現的次數越多,我們就認爲這兩個人的合作關係越緊密,對應權值也就越高。同理,Yang LiuHao Chen共現過1次、Wenwu ZhuHao Chen共現過2次。
在這裏插入圖片描述
當數據規模很龐大的時候(如2000+個作者),再用矩陣的形式來表示其關係就不太合適,而對於稀疏矩陣的存儲方法,可以借用數據結構中三元組的形式來存儲,具體方式如下圖:
在這裏插入圖片描述
而Python(其他語言也可)自帶的數據結構——字典,就可以很方便的將原始數據轉換成三元組形式。

Tips

欲看完整代碼,請移步我的Github

一、原始數據準備

原始數據按照每篇論文一作、二作依次順序排列,兩兩作者之間使用逗號分隔,存儲在csv文件中。

本例共有節點2958個邊6040個

如何《將含有特殊字符的xlsx表格數據轉化成utf-8編碼的csv文件》請見此。
在這裏插入圖片描述

二、構建共現矩陣並以三元組形式存儲到csv文件中

【思路】:遍歷每行的作者,對於兩兩作者A,B以’A,B’爲鍵,以合作頻數爲值。對於’B,A’形式的鍵需反轉爲’A,B’形式,最後可對字典的值進行降序排序。

1)讀取並分割數據

注意此處讀取文件的編碼方式需設置爲utf-8-sig,不然得到的列表首個元素會含有\ufeffUnicode字符,具體原因百度有。

def get_Co_authors(filePath):
    '''
    讀取csv文件獲取作者信息並存儲到列表中
    :param filePath: csv文件路徑
    :return co_authors_list: 一個包含所有作者的列表
    '''
    # 設置編碼爲utf-8-sig防止首部\ufeff的出現,它是windows系統自帶的BOM,用於區分大端和小端UTF-16編碼
    with open(filePath, 'r', encoding='utf-8-sig') as f:
        text = f.read()
        co_authors_list = text.split('\n')  # 分割數據中的換行符'\n'兩邊的數據
        co_authors_list.remove('')          # 刪除列表結尾的空字符
        return co_authors_list
2)統計節點和關係頻數並構建共現矩陣

最終返回兩個字典:
①節點字典(包含節點名稱+詞頻數)
②邊字典(包含兩兩節點關係+關係頻數)

構建算法如下,已寫好詳細註釋:

def build_matrix(co_authors_list, is_reverse):
    '''
    根據共同作者列表,構建共現矩陣(存儲到字典中),並將該字典按照權值排序
    :param co_authors_list: 共同作者列表
    :param is_reverse: 排序是否倒序
    :return node_str: 三元組形式的節點字符串(且符合csv逗號分隔格式)
    :return edge_str: 三元組形式的邊字符串(且符合csv逗號分隔格式)
    '''
    node_dict = {}  # 節點字典,包含節點名+節點權值(頻數)
    edge_dict = {}  # 邊字典,包含起點+目標點+邊權值(頻數)
    # 第1層循環,遍歷整表的每行作者信息
    for row_authors in co_authors_list:
        row_authors_list = row_authors.split(',') # 依據','分割每行所有作者,存儲到列表中
        # 第2層循環,遍歷當前行所有作者中每個作者信息
        for index, pre_au in enumerate(row_authors_list): # 使用enumerate()以獲取遍歷次數index
            # 統計單個作者出現的頻次
            if pre_au not in node_dict:
                node_dict[pre_au] = 1
            else:
                node_dict[pre_au] += 1
            # 若遍歷到倒數第一個元素,則無需記錄關係,結束循環即可
            if pre_au == row_authors_list[-1]:
                break
            connect_list = row_authors_list[index+1:]
            # 第3層循環,遍歷當前行該作者後面所有的合作者,以統計兩兩作者合作的頻次
            for next_au in connect_list:
                A, B = pre_au, next_au
                # 固定兩兩作者的順序
                if A > B:
                    A, B = B, A
                key = A+','+B  # 格式化爲逗號分隔A,B形式,作爲字典的鍵
                # 若該關係不在字典中,則初始化爲1,表示作者間的合作次數
                if key not in edge_dict:
                    edge_dict[key] = 1
                else:
                    edge_dict[key] += 1
    # 對得到的字典按照value進行排序
    node_str = sortDictValue(node_dict, is_reverse)  # 節點
    edge_str = sortDictValue(edge_dict, is_reverse)   # 邊
    return node_str, edge_str
3)對結果字典按照值進行倒序排序
def sortDictValue(dict, is_reverse):
    '''
    將字典按照value排序
    :param dict: 待排序的字典
    :param is_reverse: 是否按照倒序排序
    :return s: 符合csv逗號分隔格式的字符串
    '''
    # 對字典的值進行倒序排序,items()將字典的每個鍵值對轉化爲一個元組,key輸入的是函數,item[1]表示元組的第二個元素,reverse爲真表示倒序
    tups = sorted(dict.items(), key=lambda item: item[1], reverse=is_reverse)
    s = ''
    for tup in tups:  # 合併成csv需要的逗號分隔格式
        s = s + tup[0] + ',' + str(tup[1]) + '\n'
    return s

本算法共使用3次for循環,時間複雜度爲O(n³),共用時0.63秒。
執行結果如下:
在這裏插入圖片描述

4)寫入到csv文件
def str2csv(filePath, s):
    '''
    將字符串寫入到本地csv文件中
    :param filePath: csv文件路徑
    :param s: 待寫入字符串(逗號分隔格式)
    '''
    with open(filePath, 'w', encoding='utf-8') as f:
        f.write(s)
    print('寫入文件成功,請在'+filePath+'中查看')

結果如下:
在這裏插入圖片描述
【參考文獻】:
[1] LeoWood.Python-Pandas構建共現矩陣
[2] python構建關鍵詞共現矩陣
[3] python構建關鍵詞共現矩陣速度優化

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