从文本和数字数据字典创建网络-训练GNN

时间:2020-10-06 01:42:29

标签: python dictionary graph networkx multilabel-classification

我一直在使用FUNSD数据集来预测非结构化文档中的序列标签:LayoutLM: Pre-training of Text and Layout for Document Image Understanding。清理并从dict移到数据框后的数据如下所示: FUNSD Dataframe数据集的布局如下:

  • id是每个单词组的唯一标识符 在文档中,显示在text列中(如Nodes)
  • label标识单词组是否归类为 “问题”或“答案”
  • linking表示单词组,它们已“链接”(如Edges),将相应的“问题”链接到“答案”
  • 表示位置的列'box' 单词组的坐标(x,y左上角,x,右下角) 相对于左上角(0.0)。
  • 'words'包含单词组内的每个 单个单词 及其位置(框)。

我的目标是训练一个分类器,以识别在'words'列中使用Graph Neural Net链接在一起的单词,第一步是要能够将我当前的数据集转换为Network。我的问题如下:

  1. 是否可以将列'words'中的每一行分成两列[box_word, text_word],每列 仅用于一个单词,而复制其余的其余列 相同:[id, label, text, box],导致最终数据帧包含以下列:[box,text,label,box_word, text_word]

  2. 我可以标记列'text'text_word,一个热编码列label,拆分具有多个数字box和{{1}的列}分成几列,但是如何拆分/重新排列列box_word以定义网络图的边缘?

  3. 我是否使用“使用数据帧生成网络并使用它来训练GNN”中的正确路线?

任何帮助和提示都将受到赞赏。

1 个答案:

答案 0 :(得分:1)

编辑:处理words列中的多个条目。

您的问题1和2在代码中得到回答。实际上非常简单(假设屏幕截图中显示的内容正确表示了数据格式)。摘要:

Q1:apply列上的拆分功能并按.tolist()拆包,以便可以创建单独的列。另请参见this post

第二季度:使用列表推导解压缩额外的列表层并仅保留非空边缘。

Q3:是和否。是的,因为pandas擅长组织异构类型的数据。例如,列表,字典,整型和浮点型可以出现在不同的列中。几个I / O功能(例如pd.read_csv()pd.read_json())也非常方便。

但是,数据访问存在开销,这对于遍历行(记录)而言尤其昂贵。因此,通常直接输入模型的转换数据通常会转换为numpy.array或更有效的格式。这样的格式转换任务是数据科学家的唯一责任。

代码和输出

我组成了自己的样本数据集。不相关的列被忽略(因为我没有义务也不应该这样做)。

import networkx as nx
import pandas as pd

# data
df = pd.DataFrame(
    data={
        "words": [
            [{"box": [1, 2, 3, 4], "text": "TO:"}, {"box": [7, 7, 7, 7], "text": "777"}],
            [{"box": [1, 2, 3, 4], "text": "TO:"}],
            [{"text": "TO:", "box": [1, 2, 3, 4]}, {"box": [4, 4, 4, 4], "text": "444"}],
            [{"text": "TO:", "box": [1, 2, 3, 4]}],
        ],
        "linking": [
            [[0, 4]],
            [],
            [[4, 6]],
            [[6, 0]],
        ]
    }
)


# Q1. split
def split(el):
    ls_box = []
    ls_text = []
    for dic in el:
        ls_box.append(dic["box"])
        ls_text.append(dic["text"])
    return ls_box, ls_text

# straightforward but receives a deprecation warning
df[["box_word", "text_word"]] = df["words"].apply(split).tolist()
# to avoid that,
ls_tup = df["words"].apply(split).tolist()  # len: 4x2
ls_tup_tr = list(map(list, zip(*ls_tup)))  # len: 2x4
df["box_word"] = ls_tup_tr[0]
df["text_word"] = ls_tup_tr[1]

# Q2. construct graph
ls_edges = [item[0] for item in df["linking"].values if len(item) > 0]
print(ls_edges)  # [[0, 4], [4, 6], [6, 0]]

g = nx.Graph()
g.add_edges_from(ls_edges)
list(g.nodes)  # [0, 4, 6]
list(g.edges)  # [(0, 4), (0, 6), (4, 6)]

第一季度输出

# trim the first column for printing
df_show = df.__deepcopy__()
df_show["words"] = df_show["words"].apply(lambda s: str(s)[:10])
df_show

Out[51]: 
        words   linking                      box_word   text_word
0  [{'box': [  [[0, 4]]  [[1, 2, 3, 4], [7, 7, 7, 7]]  [TO:, 777]
1  [{'box': [        []                [[1, 2, 3, 4]]       [TO:]
2  [{'text':   [[4, 6]]  [[1, 2, 3, 4], [4, 4, 4, 4]]  [TO:, 444]
3  [{'text':   [[6, 0]]                [[1, 2, 3, 4]]       [TO:]