History of codex_kg
The changes to the source code of this entry in the repository, newest first, each with the differences it made to the entry's files. They are also listed on GitLab.
[entries] New entry: codex_kg c22b165
diff --git a/entries/codex_kg/__init__.py b/entries/codex_kg/__init__.py
new file mode 100644
index 0000000..8a6ca64
--- /dev/null
+++ b/entries/codex_kg/__init__.py
@@ -0,0 +1,106 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2026 Tiago de Paula Peixoto <tiago@skewed.de>
+#
+# This program is free software: you can redistribute it and/or modify it under
+# the terms of the GNU Affero General Public License as published by the Free
+# Software Foundation, either version 3 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Affero General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+
+from .. import *
+
+
+title = "Wikidata knowledge graph benchmarks (CoDEx, 2020)"
+description = """Knowledge graphs extracted from Wikidata by Safavi and Koutra as benchmarks for knowledge graph completion (link prediction and triple classification), the CoDEx datasets. Each node is an entity of Wikidata (e.g. a person, a country, an organization, a language or a disease), and a directed edge from entity A to entity B is a triple (A, relation, B), e.g. that a person has the country of citizenship B. Pairs of entities may be connected by several edges with different relations.
+
+The authors first defined a seed set of entity types and relations of 13 domains (e.g. business, geography, medicine, music, politics, science, sports), and queried Wikidata for the statements whose subject has a seed type and whose relation is a seed relation, which gives the raw dump (`raw`: 380,038 entities, 75 relations, 1,156,222 triples). From it, they extracted three benchmarks of increasing size, as k-cores of the raw graph, from which they removed the relations that largely overlap with the inverse of another one:
+
+- `codex_s` (k = 15): 2,034 entities and 42 relations;
+- `codex_m` (k = 10): 17,050 entities and 51 relations;
+- `codex_l` (k = 5): 77,951 entities and 69 relations.
+
+The triples of the benchmarks are divided into training, validation and test sets; all of them are included, and the set is given as an edge property. The "hard negatives" of `codex_s` and `codex_m`, triples verified to be false that are used for triple classification, are left out, as are the Wikipedia page extracts of the entities and the labels in other languages than English.
+
+The labels, descriptions, URLs and types are given by the data only for the entities of `codex_l`, so they are empty for the other entities of `raw` (302,087 of them).
+
+The networks have the following properties:
+
+- `wikidata_id`: the Wikidata identifier of the entity, e.g. `Q7604`.
+- `label`: the English label of the entity (empty if absent).
+- `description`: the English description of the entity in Wikidata (empty if absent).
+- `wikipedia_url`: the URL of the English Wikipedia article of the entity (empty if absent).
+- `types`: the English labels of the types of the entity in Wikidata (e.g. `human`).
+- Edge `relation_id`: the Wikidata property of the relation, e.g. `P27`.
+- Edge `relation`: the English label of the relation, e.g. `country of citizenship` (empty for the relations of `raw` that are not described in the data).
+- Edge `split` (not for `raw`): the set of the benchmark the triple belongs to: `train`, `valid` or `test`."""
+tags = ['Informational', 'Relatedness', 'Unweighted', 'Multigraph', 'Metadata']
+url = 'https://github.com/tsafavi/codex'
+citation = [('T. Safavi, D. Koutra, "CoDEx: A Comprehensive Knowledge Graph Completion Benchmark." Proceedings of the 2020 Conference on Empirical Methods in Natural Language Processing (EMNLP), 8328-8350 (2020)', 'https://doi.org/10.18653/v1/2020.emnlp-main.669')]
+icon_hash = None
+upstream_license = ('MIT', 'https://github.com/tsafavi/codex/blob/3132e426c2a6b643b70bad679905a3a6270be440/LICENSE')
+upstream_prefix = 'https://raw.githubusercontent.com/tsafavi/codex/3132e426c2a6b643b70bad679905a3a6270be440/data'
+meta = ('entities/en/entities.json', 'relations/en/relations.json',
+ 'types/entity2types.json', 'types/en/types.json')
+files = [(tuple(f'triples/codex-{s}/{t}.txt' for t in ['train', 'valid', 'test']) +
+ meta, f'codex_{s}', None) for s in ['s', 'm', 'l']]
+files += [(('triples/raw.zip:raw/triples.txt',) + meta, 'raw', None)]
+
+def fetch_upstream(force=False):
+ return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+ force)
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+ global files
+ name = __name__.split(".")[-1]
+ for fnames, alt, fmt in files:
+ if alts is not None and alt not in alts:
+ continue
+ tfiles, mfiles = fnames[:-4], fnames[-4:]
+ meta = []
+ for fname in mfiles:
+ with open_upstream_file(name, fname, "r") as f:
+ meta.append(json.load(f))
+ entities, relations, e2t, types = meta
+
+ triples = []
+ splits = []
+ for fname, split in zip(tfiles, ["train", "valid", "test"]):
+ with open_upstream_file(name, fname, "r") as f:
+ for line in f:
+ if not line.strip():
+ continue
+ h, r, t = line.rstrip("\n").split("\t")
+ triples.append((h, t, r))
+ splits.append(split)
+ g = Graph(directed=True)
+ g.vp.wikidata_id = g.add_edge_list(triples, hashed=True,
+ eprops=[("relation_id", "string")])
+ g.ep.relation_id = g.ep["relation_id"]
+ g.ep.relation = g.new_ep("string", vals=[relations.get(r, {}).get("label", "")
+ for h, t, r in triples])
+ ids = list(g.vp.wikidata_id)
+ for k, p in [("label", "label"), ("description", "description"),
+ ("wiki", "wikipedia_url")]:
+ g.vp[p] = g.new_vp("string", vals=[entities.get(i, {}).get(k, "")
+ for i in ids])
+ g.vp.types = g.new_vp("vector<string>")
+ for v, i in zip(g.vertices(), ids):
+ g.vp.types[v] = [types.get(t, {}).get("label") or t
+ for t in e2t.get(i, [])]
+ if alt != "raw":
+ g.ep.split = g.new_ep("string", vals=splits)
+ yield alt, g