History of ogbn_mag
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] Add the date when each entry was added, and remove icon_hash beff7c9
The dates are those of the commits that first added the entries' files (2020-08-11 for the entries of the initial commit); renamed entries keep the date of their first name. Changed: none
diff --git a/entries/ogbn_mag/__init__.py b/entries/ogbn_mag/__init__.py
index 8e33d20..4dfe1fd 100644
--- a/entries/ogbn_mag/__init__.py
+++ b/entries/ogbn_mag/__init__.py
@@ -45,7 +45,7 @@ url = ['https://ogb.stanford.edu/docs/nodeprop/#ogbn-mag',
'https://snap.stanford.edu/ogb/data/']
citation = [('W. Hu, M. Fey, M. Zitnik, Y. Dong, H. Ren, B. Liu, M. Catasta, J. Leskovec, "Open Graph Benchmark: Datasets for Machine Learning on Graphs." Advances in Neural Information Processing Systems 33, 22118-22133 (2020)', 'https://doi.org/10.48550/arXiv.2005.00687'),
('K. Wang, Z. Shen, C. Huang, C.-H. Wu, Y. Dong, A. Kanakia, "Microsoft Academic Graph: When experts are not enough." Quantitative Science Studies 1(1), 396-413 (2020)', 'https://doi.org/10.1162/qss_a_00021')]
-icon_hash = None
+date_added = '2026-10-27'
upstream_license = ('ODC-BY 1.0', 'https://opendatacommons.org/licenses/by/1-0/')
upstream_prefix = 'https://snap.stanford.edu/ogb/data'
[entries] Prefix the properties in the descriptions with (Node), (Edge) or (Graph) bc3dbbd
The lists of properties at the end of the descriptions marked edge properties with "Edge" but left node properties unmarked, or grouped them in "Nodes: `a`, ...; `b`, ..." items, so the kind of a property was often unclear. Every item now starts with (Node), (Edge) or (Graph), followed by the property names, a colon and the explanation, one item per property or group of properties; qualifications (kinds of nodes, networks) follow the names in parentheses. Properties that were only named got a short explanation, and a few items that named the wrong kind of property were corrected.
diff --git a/entries/ogbn_mag/__init__.py b/entries/ogbn_mag/__init__.py
index 7383c4b..8e33d20 100644
--- a/entries/ogbn_mag/__init__.py
+++ b/entries/ogbn_mag/__init__.py
@@ -34,12 +34,12 @@ The papers also have the node features of the benchmark: a 128-dimensional vecto
The network has the following properties:
-- `kind`: the kind of the node (`paper`, `author`, `institution` or `field_of_study`).
-- `mag_id`: the identifier of the node (paper, author, institution or field of study) in the Microsoft Academic Graph.
-- `year`: the publication year of a paper (-1 for other nodes).
-- `venue`: the MAG identifier of the venue (conference or journal) of a paper (-1 for other nodes).
-- `features`: the 128-dimensional feature vector of a paper (the average of the word2vec embeddings of the words of its title and abstract; empty for other nodes).
-- Edge `kind`: the relation (`writes`, `cites`, `has_topic` or `affiliated_with`)."""
+- (Node) `kind`: the kind of the node (`paper`, `author`, `institution` or `field_of_study`).
+- (Node) `mag_id`: the identifier of the node (paper, author, institution or field of study) in the Microsoft Academic Graph.
+- (Node) `year`: the publication year of a paper (-1 for other nodes).
+- (Node) `venue`: the MAG identifier of the venue (conference or journal) of a paper (-1 for other nodes).
+- (Node) `features`: the 128-dimensional feature vector of a paper (the average of the word2vec embeddings of the words of its title and abstract; empty for other nodes).
+- (Edge) `kind`: the relation (`writes`, `cites`, `has_topic` or `affiliated_with`)."""
tags = ['Informational', 'Citation', 'Social', 'Collaboration', 'Academic graph', 'Unweighted', 'Metadata']
url = ['https://ogb.stanford.edu/docs/nodeprop/#ogbn-mag',
'https://snap.stanford.edu/ogb/data/']
[entries] Remove unneeded code from the entries 2c69f19
Unneeded "global files" statements, unused imports and variables, f-strings without placeholders, duplicate keys in foodweb_little_rock (keeping the order and the values used), and the second definition of get_lines() in twitter_higgs. Nothing changes in the networks or descriptions. Changed: none
diff --git a/entries/ogbn_mag/__init__.py b/entries/ogbn_mag/__init__.py
index 94da35e..7383c4b 100644
--- a/entries/ogbn_mag/__init__.py
+++ b/entries/ogbn_mag/__init__.py
@@ -101,7 +101,6 @@ def set_features(g, name, fname, n):
@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:
[entries] New entry: ogbn_mag fe8c30a
diff --git a/entries/ogbn_mag/__init__.py b/entries/ogbn_mag/__init__.py
new file mode 100644
index 0000000..94da35e
--- /dev/null
+++ b/entries/ogbn_mag/__init__.py
@@ -0,0 +1,151 @@
+#! /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/>.
+
+
+
+import pandas
+import pyarrow
+import pyarrow.csv
+
+from .. import *
+
+
+title = "Microsoft Academic Graph, heterogeneous subset (ogbn-mag, 2020)"
+description = """A heterogeneous network of papers, their authors, the institutions of the authors, and the fields of study of the papers, a subset of the Microsoft Academic Graph (MAG), from the `ogbn-mag` dataset of the Open Graph Benchmark (OGB), a benchmark for node classification (version 2, of June 2020, from which duplicate edges were removed). The benchmark task is to predict the venue (conference or journal) of each paper, one of 349 venues, which the papers are labeled with.
+
+The network has nodes of four kinds: 736,389 papers, 1,134,649 authors, 8,740 institutions and 59,965 fields of study, and directed edges of four kinds: an author *writes* a paper (7,145,660 edges), a paper *cites* another paper (5,416,271), a paper *has_topic* a field of study (7,505,078), and an author is *affiliated_with* an institution (1,043,998). The nodes are identified by their MAG identifiers only (the data do not include titles, names, or the names of the fields of study and venues).
+
+The papers also have the node features of the benchmark: a 128-dimensional vector obtained by averaging the word2vec embeddings of the words in the title and abstract of the paper (the embeddings were trained by the OGB authors on the MAG corpus); the other nodes have no features. The splits of the benchmark (by year) are also left out.
+
+The network has the following properties:
+
+- `kind`: the kind of the node (`paper`, `author`, `institution` or `field_of_study`).
+- `mag_id`: the identifier of the node (paper, author, institution or field of study) in the Microsoft Academic Graph.
+- `year`: the publication year of a paper (-1 for other nodes).
+- `venue`: the MAG identifier of the venue (conference or journal) of a paper (-1 for other nodes).
+- `features`: the 128-dimensional feature vector of a paper (the average of the word2vec embeddings of the words of its title and abstract; empty for other nodes).
+- Edge `kind`: the relation (`writes`, `cites`, `has_topic` or `affiliated_with`)."""
+tags = ['Informational', 'Citation', 'Social', 'Collaboration', 'Academic graph', 'Unweighted', 'Metadata']
+url = ['https://ogb.stanford.edu/docs/nodeprop/#ogbn-mag',
+ 'https://snap.stanford.edu/ogb/data/']
+citation = [('W. Hu, M. Fey, M. Zitnik, Y. Dong, H. Ren, B. Liu, M. Catasta, J. Leskovec, "Open Graph Benchmark: Datasets for Machine Learning on Graphs." Advances in Neural Information Processing Systems 33, 22118-22133 (2020)', 'https://doi.org/10.48550/arXiv.2005.00687'),
+ ('K. Wang, Z. Shen, C. Huang, C.-H. Wu, Y. Dong, A. Kanakia, "Microsoft Academic Graph: When experts are not enough." Quantitative Science Studies 1(1), 396-413 (2020)', 'https://doi.org/10.1162/qss_a_00021')]
+icon_hash = None
+upstream_license = ('ODC-BY 1.0', 'https://opendatacommons.org/licenses/by/1-0/')
+upstream_prefix = 'https://snap.stanford.edu/ogb/data'
+
+kinds = ['paper', 'author', 'institution', 'field_of_study']
+relations = [('author', 'writes', 'paper'), ('paper', 'cites', 'paper'),
+ ('paper', 'has_topic', 'field_of_study'),
+ ('author', 'affiliated_with', 'institution')]
+z = 'nodeproppred/mag.zip:mag'
+files = [((f'{z}/raw/num-node-dict.csv.gz',
+ f'{z}/raw/node-feat/paper/node_year.csv.gz',
+ f'{z}/raw/node-label/paper/node-label.csv.gz',
+ f'{z}/mapping/labelidx2venuename.csv.gz') +
+ tuple(f'{z}/mapping/{k}_entidx2name.csv.gz' for k in kinds) +
+ tuple(f'{z}/raw/relations/{s}___{r}___{t}/edge.csv.gz'
+ for s, r, t in relations) +
+ (f'{z}/raw/node-feat/paper/node-feat.csv.gz',),
+ None, None)]
+
+def fetch_upstream(force=False):
+ return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+ force)
+
+def read_csv_gz(name, fname, header=None):
+ "The gzipped CSV member `fname`, as an integer array."
+ with open_upstream_file(name, fname, "rb") as f:
+ return pandas.read_csv(f, compression="gzip", header=header,
+ dtype="int64").values
+
+def set_features(g, name, fname, n):
+ """Store the node features of the gzipped CSV member `fname` (one line of
+ 128 numbers per node, for the first `n` vertices) as the vector<double>
+ vertex property `features`, read in blocks."""
+ p = g.new_vp("vector<double>")
+ i = 0
+ with open_upstream_file(name, fname, "rb") as f, gzip.open(f) as gf:
+ reader = pyarrow.csv.open_csv(
+ gf,
+ read_options=pyarrow.csv.ReadOptions(autogenerate_column_names=True,
+ block_size=1 << 26),
+ convert_options=pyarrow.csv.ConvertOptions(
+ column_types={f"f{j}": pyarrow.float64() for j in range(128)}))
+ for batch in reader:
+ assert batch.num_columns == 128 and i + batch.num_rows <= n
+ x = numpy.column_stack([c.to_numpy() for c in batch.columns])
+ for row in x:
+ p[i] = row
+ i += 1
+ del x
+ assert i == n, (i, n)
+ g.vp.features = p
+
+@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
+ # "paper,author,institution,field_of_study" and their numbers
+ with open_upstream_file(name, fnames[0], "rb") as f:
+ header, counts = gzip.decompress(f.read()).decode().split()
+ assert header.split(",") == kinds
+ counts = [int(x) for x in counts.split(",")]
+ offsets = numpy.concatenate([[0], numpy.cumsum(counts)])
+ years = read_csv_gz(name, fnames[1])[:, 0]
+ labels = read_csv_gz(name, fnames[2])[:, 0]
+ venues = read_csv_gz(name, fnames[3], header=0)
+ assert (venues[:, 0] == numpy.arange(len(venues))).all()
+
+ g = Graph(directed=True)
+ g.add_vertex(offsets[-1])
+ g.vp.kind = g.new_vp("string", vals=[k for k, n in zip(kinds, counts)
+ for i in range(n)])
+ g.vp.mag_id = g.new_vp("int64_t")
+ for i, k in enumerate(kinds):
+ ids = read_csv_gz(name, fnames[4 + i], header=0)
+ assert len(ids) == counts[i] and (ids[:, 0] == numpy.arange(counts[i])).all()
+ g.vp.mag_id.a[offsets[i]:offsets[i + 1]] = ids[:, 1]
+ npapers = counts[0]
+ assert len(years) == len(labels) == npapers
+ g.vp.year = g.new_vp("int", val=-1)
+ g.vp.year.a[:npapers] = years
+ g.vp.venue = g.new_vp("int64_t", val=-1)
+ g.vp.venue.a[:npapers] = venues[labels, 1]
+
+ ekinds = []
+ for i, (s, r, t) in enumerate(relations):
+ edges = read_csv_gz(name, fnames[8 + i])
+ assert edges[:, 0].max() < counts[kinds.index(s)]
+ assert edges[:, 1].max() < counts[kinds.index(t)]
+ edges[:, 0] += offsets[kinds.index(s)]
+ edges[:, 1] += offsets[kinds.index(t)]
+ g.add_edge_list(edges)
+ ekinds += [r] * len(edges)
+ del edges
+ g.ep.kind = g.new_ep("string", vals=ekinds)
+ del ekinds
+ # Only the papers (the first nodes) have features; the other nodes
+ # have empty vectors
+ set_features(g, name, fnames[12], npapers)
+ yield alt, g