make_test_edge(將圖轉為鏈路預測二分類問題)


def mask_test_edges(adj):
    # Function to build test set with 10% positive links
    # NOTE: Splits are randomized and results might slightly deviate from reported numbers in the paper.
    # TODO: Clean up.

    # Remove diagonal elements
    adj = adj - sp.dia_matrix((adj.diagonal()[np.newaxis, :], [0]), shape=adj.shape)
    adj.eliminate_zeros()
    # Check that diag is zero:  檢查對角線元素是否為0
    assert np.diag(adj.todense()).sum() == 0

    adj_triu = sp.triu(adj)  # triu 取出稀疏矩陣的上三角部分的非零元素 元素值及其坐標
    adj_tuple = sparse_to_tuple(adj_triu)  # 將上三角轉為tuple 返回三元組形式
    edges = adj_tuple[0]   # 返回坐標值 coords
    # train_edges = adj_tuple[0]
    edges_all = sparse_to_tuple(adj)[0]   # 這是從整個鄰接矩陣得到的邊的坐標
    # num_test = int(np.floor(edges.shape[0] / 10.)) # 10%數(shù)量的邊作為測試集
    num_val = int(np.floor(edges.shape[0] / 10.))  # 5%數(shù)量的邊作為驗證集

    all_edge_idx = list(range(edges.shape[0]))   # edges應該是一個兩位數(shù)組 每一行是一個坐標 列數(shù)就是所有邊的總個數(shù)
    np.random.shuffle(all_edge_idx)   # 哇塞 通過打亂索引 來進行shuffle 而不是直接shuffle原數(shù)據(jù)
    val_edge_idx = all_edge_idx[:num_val]    # 驗證集邊的索引
    # test_edge_idx = all_edge_idx[num_val:(num_val + num_test)]   # 測試集邊的索引
    # test_edges = edges[test_edge_idx]   # 通過索引指定對應的測試集的邊
    val_edges = edges[val_edge_idx]    # 通過索引指定對應的驗證集的邊
    train_edges = np.delete(edges, np.hstack([val_edge_idx]), axis=0) # 把test和val刪掉就是訓練集的邊
    ### ?。?! 注意 因為adj確認了沒有0 所以所有的test val 和train edge都是正例!


    def ismember(a, b, tol=5):
        rows_close = np.all(np.round(a - b[:, None], tol) == 0, axis=-1)
        return np.any(rows_close)
        # np.all 測試沿給定軸的所有數(shù)組元素是否都計算為True
        # 這里axis=-1 就是沿著縱向找,如果這一行的元素都不為0,則返回True,否則返回False
        # np.any 測試沿給定軸的所有數(shù)組元素是否有計算為True
        # 這里axis=-1 就是沿著縱向找,如果這一行的元素有一個不為0,則返回True,否則返回False
        # 這個函數(shù)的作用是 如果坐標a是坐標集合b的其中一個,則返回True 也就是is member

    
    test_edges_false = []
    # 如果不滿足while后面的條件 則跳出循環(huán)
    # 這個應該是生成和正樣本數(shù)量相等的負樣本(也就是沒有連接的邊)
    # continue是跳過本次循環(huán) 但是循環(huán)繼續(xù) 循環(huán)沒有終止
    # break是循環(huán)終止
    while len(test_edges_false) < len(test_edges):
        idx_i = np.random.randint(0, adj.shape[0])
        idx_j = np.random.randint(0, adj.shape[0])
        if idx_i == idx_j:
            continue
        if ismember([idx_i, idx_j], edges_all):
            # 這個循環(huán)是為了排除掉所有正樣本 包括上三角和下三角 因為我們最終是要得到負樣本的
            continue
        if test_edges_false:  # 這個判別是 只要test_edges_false這個數(shù)組非空 就進入到下面這個循環(huán)
            if ismember([idx_j, idx_i], np.array(test_edges_false)):
                continue
            if ismember([idx_i, idx_j], np.array(test_edges_false)):
                continue
        test_edges_false.append([idx_i, idx_j])
        # 如果上述的所有判別條件都沒有讓這個跳出這次循環(huán) 則把這個符合規(guī)則的樣本加入到負樣本集里面
    

    i = 0
    val_edges_false = []
    while len(val_edges_false) < len(val_edges):
        idx_i = np.random.randint(0, adj.shape[0])
        idx_j = np.random.randint(0, adj.shape[0])
        if idx_i == idx_j:
            continue
        if ismember([idx_i, idx_j], train_edges):
            continue
        if ismember([idx_j, idx_i], train_edges):
            continue
        if ismember([idx_i, idx_j], val_edges):
            continue
        if ismember([idx_j, idx_i], val_edges):
            continue
        if val_edges_false:
            if ismember([idx_j, idx_i], np.array(val_edges_false)):
                continue
            if ismember([idx_i, idx_j], np.array(val_edges_false)):
                continue
        val_edges_false.append([idx_i, idx_j])
        print(i)
        i +=1
        # 如果上述的所有判別條件都沒有讓這個跳出這次循環(huán) 則把這個符合規(guī)則的樣本加入到負樣本集里面

    # ~是取反的意思
    # 以下五句話分別是確認:
    # 為測試集、驗證集生成的負樣本的邊坐標不在所有正樣本邊集合里面
    # 驗證集正樣本和測試集正樣本都不在訓練集里面
    # 驗證集測試集正樣本木有重疊
    # 但是用上下面的五句話往往會造成內(nèi)存爆炸
    # assert ~ismember(test_edges_false, edges_all)
    # assert ~ismember(val_edges_false, edges_all)
    # assert ~ismember(val_edges, train_edges)
    # assert ~ismember(test_edges, train_edges)
    # assert ~ismember(val_edges, test_edges)


    data = np.ones(train_edges.shape[0])
    # data為訓練集正樣本個數(shù)

    # Re-build adj matrix
    # 這個很好理解 就是根據(jù)之前切好的訓練集正樣本 重構鄰接矩陣 只有訓練集樣本對應的位置為1
    adj_train = sp.csr_matrix((data, (train_edges[:, 0], train_edges[:, 1])), shape=adj.shape)
    adj_train = adj_train + adj_train.T
    # 第一行的adj_train是上三角矩陣 加上轉置之后的(下三角矩陣)變成完整的重構鄰接矩陣

    # NOTE: these edge lists only contain single direction of edge!
    return adj_train, train_edges, val_edges, val_edges_false
    # return adj_train, train_edges, val_edges, val_edges_false, test_edges, test_edges_false

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容