CPNC-S---reader_utils.py

__author__ = "chaitanya"

import torch
import numpy as np
import string
def create_word_vocab(network):
    word_vocab = {}
    word_freqs = {}
    #分别用于存储词汇表和词频字典的初始内容。

    word_vocab["PAD"] = len(word_vocab)
    #将特殊标记 "PAD"(用于填充文本序列的标记)添加到词汇表,并分配给它一个数字 ID。数字 ID 是词汇表中每个单词的唯一标识符。

    for node in network.graph.iter_nodes():
    #遍历图中的所有节点
        for word in node.name.split():
        #将节点的名称(name)分割成单词,并遍历每个单词。
            word = word.lower()
            #将单词转换为小写字母,以确保不区分大小写。
            if word not in word_vocab:
            #检查单词是否已经在词汇表中。
                word_vocab[word] = len(word_vocab)
            #如果单词不在词汇表中,将其添加到词汇表,并分配一个唯一的数字 ID。
            if word not in word_freqs:
                word_freqs[word] = 1
                #如果单词不在词频字典中,将其添加,并将其初始频率设置为 1。
            else:
                word_freqs[word] += 1

    word_vocab["UNK"] = len(word_vocab)
    #将特殊标记 "UNK"(用于表示未知单词的标记)添加到词汇表,并分配一个数字 ID。
    return word_vocab, word_freqs

创建一个词汇表(word vocabulary)和一个词频字典(word frequency dictionary),用于将文本数据映射到数字 ID。

def create_vocab(network):
    word_vocab = {}
    word_freqs = {}
    #存储词汇表和词频字典的初始内容。

    for node in network.graph.iter_nodes():
    #遍历图中的所有节点。
        if node.name not in word_vocab:
            word_vocab[node.name] = len(word_vocab)
        if node.name not in word_freqs:
            word_freqs[node.name] = 1
        else:
            word_freqs[node.name] += 1

    word_vocab["UNK"] = len(word_vocab)
    return word_vocab, word_freqs

创建一个节点名称的词汇表(word vocabulary)和节点名称的词频字典(word frequency dictionary),用于将节点名称映射到数字 ID。

def get_vocab_idx(vocab, token):
    if token not in vocab:
        return vocab["UNK"]
    else:
        return vocab[token]

这个函数的目的是从给定的词汇表中获取一个词汇(token)对应的数字 ID。以下是代码的详细解释:

  1. vocab 是一个词汇表,通常是一个字典,其中包含了词汇(token)到数字 ID 的映射关系。

  2. token 是要查询的词汇,也就是要获取其对应的数字 ID。

  3. if token not in vocab::这是一个条件语句,检查要查询的词汇是否在词汇表中。

  4. return vocab["UNK"]:如果要查询的词汇不在词汇表中,那么返回特殊标记 "UNK"(通常表示未知词汇)对应的数字 ID。

  5. else::如果要查询的词汇在词汇表中,执行以下操作:

    • return vocab[token]:返回词汇在词汇表中对应的数字 ID。

总之,这个函数的作用是根据给定的词汇表,将输入的词汇(token)转换成相应的数字 ID。如果词汇表中存在该词汇,就返回它的数字 ID;如果词汇表中不存在,就返回特殊标记 "UNK" 对应的数字 ID。这对于将文本数据映射成数字数据,以供深度学习模型处理,非常有用

def map_to_ids(vocab, seq):
    return [get_vocab_idx(vocab, word) for word in seq]

这个函数的目的是将一个文本序列中的词汇(tokens)映射成相应的数字 ID 列表,使用了之前定义的 get_vocab_idx 函数。以下是代码的详细解释:

  1. vocab 是一个词汇表,通常是一个字典,其中包含了词汇(token)到数字 ID 的映射关系。

  2. seq 是一个文本序列,通常是一个由词汇组成的列表。

  3. 列表推导式 [get_vocab_idx(vocab, word) for word in seq]:这行代码使用列表推导式遍历 seq 中的每个词汇 word,然后调用 get_vocab_idx(vocab, word) 函数来获取每个词汇对应的数字 ID。最终,返回一个包含了数字 ID 的列表。

总之,这个函数的作用是将文本序列中的每个词汇映射成其对应的数字 ID,返回一个包含数字 ID 的列表。这个列表通常用于深度学习模型的输入,以便模型能够处理文本数据。

def get_relation_id(rel_name, train_network):
#rel_name 是要查询的关系名,即要获取其对应的关系 ID。
#train_network 是图数据对象,通常包含了图的结构和关系信息。
    rel_id = train_network.graph.find_relation(rel_name)
    #用 train_network 中的 graph 属性的 find_relation 方法,尝试查找关系名 rel_name 对应的关系 ID。如果找到了,rel_id 将存储关系 ID;如果找不到,rel_id 将被设置为 -1,表示关系名不存在。
    if rel_id == -1: 
        return len(train_network.rel2id)
    #返回关系表 train_network.rel2id 的长度,通常表示关系表中的新关系的下一个可用 ID。
    else:
        return rel_id

根据给定的关系名和图数据对象,获取关系名对应的关系 ID。如果关系名不存在,函数将返回下一个可用的关系 ID;如果关系名存在,函数将返回相应的关系 ID。这对于处理图数据中的关系非常有用。

def prepare_batch_nodes(vocab, batch):
#vocab 是一个词汇表,通常是一个字典,其中包含了词汇(token)到数字 ID 的映射关系。
    lens = [len(name) for name in batch]
    #计算了批次中每个节点名称的长度,并将结果存储在列表 lens 中。
    max_len = max(lens)
    #找到了批次中最长的节点名称的长度,用于确定填充的长度。
    sorted_batch = [x for _, x in sorted(zip(lens, batch), reverse=True, key=lambda x: x[0])]
    #根据节点名称的长度从大到小对批次进行排序,以便后面的填充操作。
    all_lens = []    
    word_ids_batch = []
    #分别用于存储所有节点的长度和映射后的数字 ID。

    for node in sorted_batch:
        word_ids = map_to_ids(vocab, node)
        #将节点名称 node 映射成数字 ID,并将结果存储在 word_ids 列表中。
        padding_length = max_len - len(word_ids)
        #计算需要添加的填充长度,以使节点具有相同的长度。
        all_lens.append(len(word_ids))
        #将节点的原始长度添加到 all_lens 列表中,以便后续使用。
        word_ids += [get_vocab_idx(vocab, "PAD")] * padding_length
        #将填充的 "PAD" 标记的数字 ID 添加到 word_ids 列表中,以使其长度等于 max_len。
        word_ids_batch.append(word_ids)
        #将映射后的数字 ID 列表添加到 word_ids_batch 列表中。
    
    return torch.LongTensor(word_ids_batch), torch.LongTensor(all_lens)

准备一个批次(batch)的节点数据,将节点名称映射成数字 ID,并进行填充以使其具有相同的长度。

def prepare_batch_dgl(vocab, test_network, train_network):
    all_edges = []
    all_labels = []
    #分别用于存储所有的图边和对应的标签。
    for edge in test_network.graph.iter_edges():
        src_id = get_vocab_idx(vocab, edge.src.name)
        #获取边的源节点名称,并使用 get_vocab_idx 函数将其映射成数字 ID。
        tgt_id = get_vocab_idx(vocab, edge.tgt.name)
        #获取边的目标节点名称,并使用 get_vocab_idx 函数将其映射成数字 ID。
        rel_id = get_relation_id(edge.relation.name, train_network)
        #获取边的关系名称,并使用 get_relation_id 函数将其映射成关系 ID。需要注意,这里使用了训练集的图数据对象 train_network 来获取关系 ID。
        all_edges.append(np.array([src_id, rel_id, tgt_id]))
        #将源节点 ID、关系 ID、目标节点 ID 组成一个三元组,并添加到 all_edges 列表中。
        all_labels.append(edge.label)
        #将当前边的标签添加到 all_labels 列表中。
    return np.array(all_edges), all_labels

从测试集的图数据中提取边和标签,并将它们准备成一个批次。这通常用于深度学习模型的测试和评估。

def create_entity_dicts(all_tuples, num_rels, sim_relations=False):
    e1_to_multi_e2 = {}
    e2_to_multi_e1 = {}

#all_tuples 是一个包含三元组的列表,每个三元组由实体1、关系和实体2组成。
#num_rels 表示关系的总数。
#sim_relations 是一个布尔值,表示是否考虑相似关系。如果为 True,则将减去相似关系的偏移量,以便在创建字典时不考虑相似关系。
#e1_to_multi_e2 和 e2_to_multi_e1 是两个字典,分别用于存储实体1到多个实体2的映射以及实体2到多个实体1的映射。

    for tup in all_tuples:
        e1, rel, e2 = tup
        #将三元组拆分为实体1、关系和实体2。

        # No need to use sim edges for decoding
        if rel == num_rels-1 and sim_relations:
            continue
        #如果关系是相似关系(sim_relations 为 True),则跳过当前三元组的处理,不将其考虑在内。

        rel_offset = num_rels
        #rel_offset 是一个关系偏移量,用于处理相似关系。

        if sim_relations:
            rel_offset -= 1

        if (e1, rel) in e1_to_multi_e2:
            e1_to_multi_e2[(e1, rel)].append(e2)
        else:
            e1_to_multi_e2[(e1, rel)] = [e2]
如果 (e1, rel) 已经存在于 e1_to_multi_e2 字典中,表示已经有了相同的关系 (e1, rel),那么将实体2 e2 添加到对应的列表中;否则,创建一个新的关系 (e1, rel) 并将 e2 添加到列表中。

        if (e2, rel+rel_offset) in e1_to_multi_e2:
            e1_to_multi_e2[(e2, rel+rel_offset)].append(e1)
        else:
            e1_to_multi_e2[(e2, rel+rel_offset)] = [e1]

        if (e2, rel+rel_offset) in e2_to_multi_e1:
            e2_to_multi_e1[(e2, rel+rel_offset)].append(e1)
        else:
            e2_to_multi_e1[(e2, rel+rel_offset)] = [e1]
 
    return e1_to_multi_e2, e2_to_multi_e1

 根据给定的三元组(实体1、关系、实体2)列表创建两个字典,用于存储实体之间的多对多关系

def preprocess_atomic_sentence(sent):

    puncts = list(string.punctuation)
    puncts.remove('-')

    sent = [c for c in sent.lower() if c not in puncts or c == "'"]
    sent = ''.join([c for c in sent if not c.isdigit()])
    sent = sent.replace("person x", "personx").replace(" x's", " personx's").replace(" x ", " personx ")
    if sent[:2] == "x " or sent[:2] == "x'":
        sent = sent.replace("x ", "personx ", 1).replace("x'", "personx'")
    if sent[-3:] == " x\n":
        sent = sent.replace(" x\n", "personx\n")

    sent = sent.replace("person y", "persony").replace(" y's", " persony's").replace(" y ", " persony ")
    if sent[:2] == "y " or sent[:2] == "y'":
        sent = sent.replace("y ", "persony ", 1).replace("y'", "persony'")
    if sent[-3:] == " y\n":
        sent = sent.replace(" y\n", "persony\n")

    return sent.replace("personx", "John").replace("persony", "Tom")

这个函数用于对原始句子进行预处理,以进行后续的文本处理。以下是对函数中的操作的解释:

  1. puncts 是一个包含标点符号的列表,通过 string.punctuation 获取,但去掉了连字符 '-'。标点符号用于后续的文本处理。

  2. sent 是输入的原始句子。

  3. sent = [c for c in sent.lower() if c not in puncts or c == "'"]:将句子中的字符全部转换为小写,并且保留连字符 '-',但去除其他标点符号。这个步骤的目的是标准化文本。

  4. sent = ''.join([c for c in sent if not c.isdigit()]):去除句子中的数字字符。这个步骤的目的是去除数字,以便更好地处理文本。

  5. sent = sent.replace("person x", "personx").replace(" x's", " personx's").replace(" x ", " personx "):将句子中的 "person x" 替换为 "personx",将 " x's" 替换为 " personx's",将 " x " 替换为 " personx "。这个步骤似乎是将 "x" 视为代表一个人名(例如,John)的标识符。

  6. 如果句子以 "x " 或 "x'" 开头,会执行以下操作:

    • sent = sent.replace("x ", "personx ", 1).replace("x'", "personx'"):将句子中的第一个 "x " 替换为 "personx ",将第一个 "x'" 替换为 "personx'"。
  7. 如果句子以 " x\n" 结尾,会执行以下操作:

    • sent = sent.replace(" x\n", "personx\n"):将句子中的 " x\n" 替换为 "personx\n"。
  8. 类似地,对于 "person y","y's","y " 的处理步骤与 "person x" 相同,只是将 "y" 视为另一个人名(例如,Tom)的标识符。

  9. 最后,将 "personx" 替换为 "John",将 "persony" 替换为 "Tom"。这个步骤将之前处理过的 "person x" 和 "person y" 替换为实际的人名。

总之,这个函数的主要作用是对原始句子进行一系列预处理操作,以标准化和清理文本,并将 "person x" 和 "person y" 替换为具体的人名 "John" 和 "Tom"。这种预处理通常用于自然语言处理任务,以准备文本数据进行后续的分析或建模。

你可能感兴趣的:(常识知识图谱补全,c#,开发语言)