History of acl_anthology
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: acl_anthology b17c322
diff --git a/entries/acl_anthology/__init__.py b/entries/acl_anthology/__init__.py
new file mode 100644
index 0000000..36afe76
--- /dev/null
+++ b/entries/acl_anthology/__init__.py
@@ -0,0 +1,171 @@
+#! /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 re
+
+import pyarrow
+import pyarrow.parquet as pq
+import pyarrow.compute as pc
+
+from .. import *
+
+title = "ACL Anthology citations and authorships (ACL OCL, 1952-2022)"
+description = r"""Citations and authorships of the papers of the ACL Anthology, the digital archive of the publications in computational linguistics and natural language processing (the journals, conferences and workshops of the Association for Computational Linguistics and related organizations), from the ACL OCL corpus of S. Rohatgi et al. The corpus covers the 73,285 papers of the Anthology up to September 2022, with their metadata from the Anthology, and their references from Semantic Scholar, which identifies the papers (cited or citing) with its corpus identifiers.
+
+- `acl`: the citation network among the papers of the Anthology: a directed edge goes from a paper to a paper of the Anthology that it cites.
+- `full`: the citations to and from the papers of the Anthology, including those of papers outside the Anthology (citing papers of the Anthology, or cited by them), known only by their Semantic Scholar identifier. Citations between two papers outside the Anthology are not included.
+
+The citation networks include only the papers with at least one citation in these tables (64,185 papers of the Anthology in `acl`, 68,241 in `full`).
+- `authorship`: the undirected bipartite network of the authors and all the papers of the Anthology (including a few hundred without authors in the data), where an edge links a paper to each of its authors. Authors are identified by their names as written in the BibTeX records of the Anthology (as "Last, First", with the LaTeX markup of accented letters), which the Anthology partly normalizes; different persons with the same name are merged, and the same person under different spellings is split.
+
+In the upstream citation tables, every citation between two papers of the Anthology appears twice (as identical rows); it is included once here. A few hundred citations appear twice with different identifiers (as different references of the citing paper) and give parallel edges. The abstracts and full texts of the papers (extracted with GROBID), and the topic labels of the corpus (given only for a part of the papers, in Python pickle files), are left out.
+
+The networks have the following properties:
+
+- `s2_id` (citation networks): the Semantic Scholar corpus identifier of the paper (its page is `https://api.semanticscholar.org/CorpusID:<s2_id>`).
+- `is_acl` (`full`): whether the paper belongs to the ACL Anthology (the following properties are empty, or -1, for those that do not).
+- `is_paper` (`authorship`): whether the node is a paper (otherwise it is an author).
+- `name`: the title of the paper (with the LaTeX markup of the BibTeX record), or the name of the author.
+- `acl_id`: the identifier of the paper in the Anthology (its page is `https://aclanthology.org/<acl_id>`).
+- `year`: the year of publication.
+- `month`: the month of publication, as given (e.g. `August`).
+- `venue`: the proceedings (book title) or the journal in which the paper appeared.
+- `entry_type`: the BibTeX entry type (e.g. `inproceedings`, `article`).
+- `publisher`, `doi`, `url`: the publisher, the DOI, and the URL of the paper (e.g. its PDF).
+- `num_cited_by`: the number of citations of the paper according to Semantic Scholar (in September 2022), counting all citing papers.
+- Edge `id` (citation networks): the Semantic Scholar identifier of the citation."""
+tags = ['Informational', 'Citation', 'Collaboration', 'Bipartite', 'Unweighted', 'Metadata']
+url = ['https://huggingface.co/datasets/WINGNUS/ACL-OCL',
+ 'https://aclanthology.org/']
+citation = [('S. Rohatgi, Y. Qin, B. Aw, N. Unnithan, M.-Y. Kan, "The ACL OCL Corpus: Advancing Open Science in Computational Linguistics." Proceedings of the 2023 Conference on Empirical Methods in Natural Language Processing, 10348-10361 (2023)',
+ 'https://doi.org/10.18653/v1/2023.emnlp-main.640')]
+icon_hash = None
+# The metadata of the Hugging Face repository says MIT, but its dataset card
+# says CC BY-NC 4.0, which is the license given here
+upstream_license = ("CC BY-NC 4.0", "https://creativecommons.org/licenses/by-nc/4.0/")
+upstream_prefix = 'https://huggingface.co/datasets/WINGNUS/ACL-OCL/resolve/300ee6c5e5629d042bfc07cbc406e2f330b53659'
+_info = "acl-publication-info.74k.v2.parquet"
+files = [(("acl_onlygraph.parquet", _info), "acl", None),
+ (("acl_full_citations.parquet", _info), "full", None),
+ ((_info,), "authorship", None)]
+
+def fetch_upstream(force=False):
+ return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+ force)
+
+_info_cols = ["acl_id", "corpus_paper_id", "numcitedby", "url", "publisher",
+ "year", "month", "booktitle", "journal", "author", "title",
+ "doi", "ENTRYTYPE"]
+
+def read_parquet(name, fname, columns=None):
+ with open_upstream_file(name, fname, "rb", seekable=True) as f:
+ return pq.read_table(f, columns=columns)
+
+def set_paper_props(g, info, idx, mask=None):
+ """Set the metadata of the papers: vertex v gets row idx[v] of `info`
+ (if idx[v] >= 0)."""
+ cols = {"name": "title", "acl_id": "acl_id", "month": "month",
+ "publisher": "publisher", "doi": "doi", "url": "url",
+ "entry_type": "ENTRYTYPE"}
+ rows = {k: info.column(c).to_pylist() for k, c in cols.items()}
+ booktitle = info.column("booktitle").to_pylist()
+ journal = info.column("journal").to_pylist()
+ year = info.column("year").to_pylist()
+ ncited = info.column("numcitedby").to_pylist()
+ for k in list(cols) + ["venue"]:
+ g.vp[k] = g.new_vp("string")
+ g.vp.year = g.new_vp("int")
+ g.vp.num_cited_by = g.new_vp("int")
+ g.vp.year.a = -1
+ g.vp.num_cited_by.a = -1
+ for v, i in enumerate(idx):
+ if i < 0:
+ continue
+ for k in cols:
+ x = rows[k][i]
+ if x is not None:
+ g.vp[k][v] = x
+ g.vp.venue[v] = booktitle[i] or journal[i] or ""
+ if year[i] and year[i].strip().isdigit():
+ g.vp.year[v] = int(year[i])
+ if ncited[i] is not None:
+ g.vp.num_cited_by[v] = ncited[i]
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+ name = __name__.split(".")[-1]
+ for fnames, alt, fmt in files:
+ if alts is not None and alt not in alts:
+ continue
+ info = read_parquet(name, _info, _info_cols)
+ if alt == "authorship":
+ authors = {}
+ edges = []
+ for i, a in enumerate(info.column("author").to_pylist()):
+ if not a:
+ continue
+ names = [x.strip() for x in re.split(r"\s+and\s+", a.strip())]
+ for x in dict.fromkeys(n for n in names if n):
+ j = authors.setdefault(x, len(authors))
+ edges.append((i, j))
+ N = info.num_rows
+ g = Graph(directed=False)
+ g.add_vertex(N + len(authors))
+ g.add_edge_list([(i, N + j) for i, j in edges])
+ g.vp.is_paper = g.new_vp("bool")
+ g.vp.is_paper.a[:N] = 1
+ set_paper_props(g, info, list(range(N)) + [-1] * len(authors))
+ for x, j in authors.items():
+ g.vp.name[N + j] = x
+ yield alt, g
+ continue
+
+ t = read_parquet(name, fnames[0])
+ # every citation between two papers of the Anthology appears twice,
+ # as identical rows
+ t = t.drop_columns([c for c in t.column_names
+ if c.startswith("__index")])
+ _, first = numpy.unique(t.column("id").to_numpy(), return_index=True)
+ t = t.take(pyarrow.array(numpy.sort(first)))
+ papers = pc.unique(pyarrow.concat_arrays([t.column("citingpaperid").combine_chunks(),
+ t.column("citedpaperid").combine_chunks()]))
+ papers = pc.take(papers, pc.sort_indices(papers))
+ s = pc.index_in(t.column("citingpaperid"), value_set=papers).to_numpy()
+ u = pc.index_in(t.column("citedpaperid"), value_set=papers).to_numpy()
+ g = Graph(directed=True)
+ g.add_vertex(len(papers))
+ g.add_edge_list(numpy.column_stack([s, u]))
+ g.vp.s2_id = g.new_vp("int64_t", vals=papers.to_numpy())
+ g.ep.id = g.new_ep("int64_t", vals=t.column("id").to_numpy())
+ # Anthology papers, as given in the citation table
+ acl = numpy.zeros(len(papers), dtype=bool)
+ acl[s[t.column("is_citingpaperid_acl").to_numpy(zero_copy_only=False)]] = True
+ acl[u[t.column("is_citedpaperid_acl").to_numpy(zero_copy_only=False)]] = True
+ # metadata (if several papers of the Anthology have the same
+ # Semantic Scholar id, the first one)
+ idx = pc.index_in(papers, value_set=info.column("corpus_paper_id"))
+ idx = idx.fill_null(-1).to_numpy()
+ set_paper_props(g, info, idx)
+ if alt == "full":
+ g.vp.is_acl = g.new_vp("bool", vals=acl)
+ else:
+ assert acl.all()
+ yield alt, g