logo Netzschleuder network catalog, repository, and centrifuge

History of aminer_citation

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: aminer_citation by Tiago de Paula Peixoto ed9c342
diff --git a/entries/aminer_citation/__init__.py b/entries/aminer_citation/__init__.py
new file mode 100644
index 0000000..8c875a9
--- /dev/null
+++ b/entries/aminer_citation/__init__.py
@@ -0,0 +1,154 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2020-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 = "AMiner citation networks (2010-2016)"
+description = """Citation networks of scientific publications, mostly in computer science, extracted from DBLP, ACM and other sources by the AMiner (formerly ArnetMiner) academic search system of Tsinghua University, and released in several versions between 2010 and 2016 as the "AMiner Citation Network Dataset". Nodes are papers, and a directed edge $i \\to j$ indicates that paper $i$ cites paper $j$ (i.e. $j$ is in the reference list of $i$).
+
+| Network | Release | Source |
+|---|---|---|
+| `v1` | Citation-network V1, 2010-05-15 | DBLP, ACM and others |
+| `v2` | Citation-network V2, 2010-09-13 | DBLP, ACM and others |
+| `v3` | DBLP-Citation-network V3, 2010-10-22 | DBLP |
+| `v4` | DBLP-Citation-network V4, 2011-01-08 | DBLP (with ACM citations) |
+| `v5` | DBLP-Citation-network V5, 2011-02-21 | DBLP |
+| `v6` | DBLP-Citation-network V6, 2013-09-29 | DBLP |
+| `v7` | DBLP-Citation-network V7, 2014-05-25 | DBLP |
+| `v8` | DBLP-Citation-network V8, 2016 | DBLP |
+| `acm_v8` | ACM-Citation-network V8, 2016 | ACM |
+
+Only references to papers contained in the same data set are included as edges, and the numbers of papers and citations can differ from those stated by AMiner (e.g. the `v7` file contains 2,146,341 papers instead of the stated 2,244,021; many papers have no citations within the data set). Papers with identical identifiers in different versions are not necessarily the same paper.
+
+The networks have the following properties:
+
+- `index`: the identifier of the paper in the data set (a number, or a 24-digit hexadecimal string in `v8` and `acm_v8`).
+- `title`: the title of the paper.
+- `authors`: the list of authors.
+- `year`: the year of publication (-1 if missing).
+- `venue`: the publication venue (conference or journal).
+- `citations` (`v5`, `v6` only): the number of citations of the paper, according to AMiner (-1 or 0 if none).
+- `arnetid` (`v5`, `v6` only): the identifier of the paper in the AMiner database.
+
+The abstracts included in some versions are not stored. According to the source, the data are designed for research purposes only."""
+tags = ['Informational', 'Citation', 'Unweighted', 'Metadata']
+url = ['https://www.aminer.cn/citation',
+       'https://web.archive.org/web/20150109175754/http://arnetminer.org/citation']
+citation = [('J. Tang, J. Zhang, L. Yao, J. Li, L. Zhang, Z. Su, "ArnetMiner: extraction and mining of academic social networks." Proceedings of the 14th ACM SIGKDD International Conference on Knowledge Discovery and Data Mining, 990-998 (2008)', 'https://doi.org/10.1145/1401890.1402008')]
+icon_hash = '5944b2354ed8f1bb6022a4a1'
+upstream_license = None
+upstream_prefix = 'https://lfs.aminer.cn/lab-datasets/citation'
+# (upstream file, kind of archive, member)
+archives = {'v1': ('citation-network1.zip', 'zip', 'outputacm.txt'),
+            'v2': ('citation-network2.rar', 'rar', 'citation-network2.txt'),
+            # (compressed with bzip2, despite the extension)
+            'v3': ('DBLP-citation-network-Oct-19.tar.gz', 'tar', 'DBLPOnlyCitationOct19.txt'),
+            'v4': ('DBLP-citation-Jan8.tar.bz2', 'tar', 'DBLP-citation-Jan8.txt'),
+            'v5': ('DBLP-citation-Feb21.tar.bz2', 'tar', 'DBLP-citation-Feb21.txt'),
+            'v6': ('DBLP_citation_Sep_2013.rar', 'rar', 'acm_output.txt'),
+            'v7': ('DBLP_citation_2014_May.zip', 'zip', 'DBLP_Citation_2014_May/publications.txt'),
+            'v8': ('dblp.v8.tgz', 'tar', 'dblp.txt'),
+            'acm_v8': ('citation-acm-v8.txt.tgz', 'tar', 'citation-acm-v8.txt')}
+# The archives are stored under the names of the networks
+files = [(f'{alt}:{kind}:{member}', alt, None)
+         for alt, (fn, kind, member) in archives.items()]
+
+def fetch_upstream(force=False):
+    urls = {fname: f'{upstream_prefix}/{archives[alt][0]}'
+            for fname, alt, fmt in files}
+    return fetch_archived_files(__name__.split(".")[-1], urls, force, tries=3)
+
+def read_papers(f):
+    "Read the blocks of the AMiner text format (one per paper)."
+    p = None
+    for line in f:
+        line = line.decode("utf-8", "replace").rstrip("\r\n")
+        if line.startswith("#*"):
+            if p is not None:
+                yield p
+            p = {"title": line[2:].strip(), "refs": []}
+        elif p is None:
+            continue
+        elif line.startswith("#@"):
+            p["authors"] = [a.strip() for a in line[2:].split(",") if a.strip()]
+        elif line.startswith("#year"):
+            p["year"] = line[5:].strip()
+        elif line.startswith("#t"):
+            p["year"] = line[2:].strip()
+        elif line.startswith("#conf"):
+            p["venue"] = line[5:].strip()
+        elif line.startswith("#citation"):
+            p["citations"] = line[9:].strip()
+        elif line.startswith("#c"):
+            p["venue"] = line[2:].strip()
+        elif line.startswith("#index"):
+            p["index"] = line[6:].strip()
+        elif line.startswith("#arnetid"):
+            p["arnetid"] = line[8:].strip()
+        elif line.startswith("#%"):
+            r = line[2:].strip()
+            if r:
+                p["refs"].append(r)
+    if p is not None:
+        yield p
+
+def to_int(x):
+    try:
+        return int(x)
+    except (TypeError, ValueError):
+        return -1
+
+@cache_network()
+@coerce_props(vforce={'index': 'string'})
+@annotate()
+def parse(alts=None):
+    global files
+    name = __name__.split(".")[-1]
+    for fname, alt, fmt in files:
+        if alts is not None and alt not in alts:
+            continue
+        with open_upstream_file(name, fname, "rb") as f:
+            papers = [p for p in read_papers(f) if "index" in p]
+        idx = {}
+        for p in papers:
+            idx.setdefault(p["index"], len(idx))
+        g = Graph(directed=True)
+        g.add_vertex(len(idx))
+        edges = [(idx[p["index"]], idx[r]) for p in papers for r in p["refs"]
+                 if r in idx]
+        g.add_edge_list(numpy.array(edges, dtype="int64").reshape(-1, 2))
+        vs = [idx[p["index"]] for p in papers]
+        g.vp.index = g.new_vp("string")
+        g.vp.title = g.new_vp("string")
+        g.vp.authors = g.new_vp("vector<string>")
+        g.vp.year = g.new_vp("int")
+        g.vp.venue = g.new_vp("string")
+        with_cites = alt in ("v5", "v6")
+        if with_cites:
+            g.vp.citations = g.new_vp("int")
+            g.vp.arnetid = g.new_vp("int")
+        for v, p in zip(vs, papers):
+            g.vp.index[v] = p["index"]
+            g.vp.title[v] = p["title"]
+            g.vp.authors[v] = p.get("authors", [])
+            g.vp.year[v] = to_int(p.get("year"))
+            g.vp.venue[v] = p.get("venue", "")
+            if with_cites:
+                g.vp.citations[v] = to_int(p.get("citations"))
+                g.vp.arnetid[v] = to_int(p.get("arnetid"))
+        yield alt, g