logo Netzschleuder network catalog, repository, and centrifuge

History of twitch_social

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 by Tiago de Paula Peixoto 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/twitch_social/__init__.py b/entries/twitch_social/__init__.py
index 4340e12..97aa39f 100644
--- a/entries/twitch_social/__init__.py
+++ b/entries/twitch_social/__init__.py
@@ -49,7 +49,7 @@ url = ['https://snap.stanford.edu/data/twitch-social-networks.html',
        'https://github.com/benedekrozemberczki/datasets']
 citation = [('B. Rozemberczki, C. Allen, and R. Sarkar, "Multi-scale attributed node embedding." Journal of Complex Networks 9(2), cnab014 (2021).', 'https://doi.org/10.1093/comnet/cnab014'),
             ('B. Rozemberczki and R. Sarkar, "Twitch Gamers: a Dataset for Evaluating Proximity Preserving and Structural Role-based Node Embeddings." arXiv:2101.03091 (2021).', 'https://doi.org/10.48550/arXiv.2101.03091')]
-icon_hash = None
+date_added = '2026-10-27'
 upstream_license = ('MIT License', 'https://github.com/benedekrozemberczki/datasets/blob/3b19135105432cbca65765c1113b91c395ed9d44/LICENSE')
 upstream_prefix = 'https://snap.stanford.edu/data'
 # the features of DE are in musae_DE.json, those of the others in
[entries] Prefix the properties in the descriptions with (Node), (Edge) or (Graph) by Tiago de Paula Peixoto 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/twitch_social/__init__.py b/entries/twitch_social/__init__.py
index edc4bbf..4340e12 100644
--- a/entries/twitch_social/__init__.py
+++ b/entries/twitch_social/__init__.py
@@ -32,8 +32,17 @@ description = r"""Social networks of users of the live streaming platform Twitch
 
 The networks have the following properties:
 
-- Language networks: `twitch_id`, the numeric Twitch identifier of the user; `days`, the age of the account in days (as given in the data); `mature`, whether the user streams explicit (mature) content; `views`, the number of views; `partner`, whether the user is a Twitch partner; `features`, the indices of the user's binary features (as listed in the data, in which a few lists contain repeated indices).
-- `twitch_gamers`: `views`, the number of views; `mature`, whether the user streams explicit content; `life_time`, the age of the account in days; `created_at` and `updated_at`, the dates of creation and of the last update of the account, as Unix time (at midnight UTC); `dead_account`, whether the account is inactive; `language`, the broadcaster language (a two-letter code, or "OTHER"); `affiliate`, whether the user is a Twitch affiliate."""
+- (Node) `twitch_id` (language networks): the numeric Twitch identifier of the user.
+- (Node) `days` (language networks): the age of the account in days (as given in the data).
+- (Node) `mature`: whether the user streams explicit (mature) content.
+- (Node) `views`: the number of views.
+- (Node) `partner` (language networks): whether the user is a Twitch partner.
+- (Node) `features` (language networks): the indices of the user's binary features (as listed in the data, in which a few lists contain repeated indices).
+- (Node) `life_time` (`twitch_gamers`): the age of the account in days.
+- (Node) `created_at`, `updated_at` (`twitch_gamers`): the dates of creation and of the last update of the account, as Unix time (at midnight UTC).
+- (Node) `dead_account` (`twitch_gamers`): whether the account is inactive.
+- (Node) `language` (`twitch_gamers`): the broadcaster language (a two-letter code, or "OTHER").
+- (Node) `affiliate` (`twitch_gamers`): whether the user is a Twitch affiliate."""
 tags = ['Social', 'Online', 'Unweighted', 'Metadata']
 url = ['https://snap.stanford.edu/data/twitch-social-networks.html',
        'https://snap.stanford.edu/data/twitch_gamers.html',
[entries] New entry: twitch_social by Tiago de Paula Peixoto b01ffa5
diff --git a/entries/twitch_social/__init__.py b/entries/twitch_social/__init__.py
new file mode 100644
index 0000000..edc4bbf
--- /dev/null
+++ b/entries/twitch_social/__init__.py
@@ -0,0 +1,121 @@
+#! /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 *
+
+import csv
+import calendar
+import json
+import time
+
+title = "Twitch mutual follower networks (2018)"
+description = r"""Social networks of users of the live streaming platform Twitch, collected from its public API in 2018 by B. Rozemberczki and collaborators for benchmarks of node embedding and classification methods. Nodes are Twitch users, and an undirected edge connects two users who follow each other (a mutual follower relationship). The user identifiers were replaced by consecutive indices. There are two data sets:
+
+- Language networks (MUSAE, collected in May 2018): six networks of users who stream in a given language, `DE` (German), `ENGB` (English), `ES` (Spanish), `FR` (French), `PTBR` (Portuguese) and `RU` (Russian). Each node has a list of binary features, shared by all six networks, which the authors extracted from the games played and liked, the location and the streaming habits of the user; only the indices of the features are given, not their meaning. The supervised task proposed with the data is to predict whether a streamer uses explicit language (`mature`). In `FR`, two users appear twice in the node table (with the same values, except for a difference of 1 in the views of one of them); the first row is used.
+- `twitch_gamers` (collected in spring 2018): a larger network of 168,114 users of all languages, which forms a single connected component. It has no feature lists, but more user attributes.
+
+The networks have the following properties:
+
+- Language networks: `twitch_id`, the numeric Twitch identifier of the user; `days`, the age of the account in days (as given in the data); `mature`, whether the user streams explicit (mature) content; `views`, the number of views; `partner`, whether the user is a Twitch partner; `features`, the indices of the user's binary features (as listed in the data, in which a few lists contain repeated indices).
+- `twitch_gamers`: `views`, the number of views; `mature`, whether the user streams explicit content; `life_time`, the age of the account in days; `created_at` and `updated_at`, the dates of creation and of the last update of the account, as Unix time (at midnight UTC); `dead_account`, whether the account is inactive; `language`, the broadcaster language (a two-letter code, or "OTHER"); `affiliate`, whether the user is a Twitch affiliate."""
+tags = ['Social', 'Online', 'Unweighted', 'Metadata']
+url = ['https://snap.stanford.edu/data/twitch-social-networks.html',
+       'https://snap.stanford.edu/data/twitch_gamers.html',
+       'https://github.com/benedekrozemberczki/datasets']
+citation = [('B. Rozemberczki, C. Allen, and R. Sarkar, "Multi-scale attributed node embedding." Journal of Complex Networks 9(2), cnab014 (2021).', 'https://doi.org/10.1093/comnet/cnab014'),
+            ('B. Rozemberczki and R. Sarkar, "Twitch Gamers: a Dataset for Evaluating Proximity Preserving and Structural Role-based Node Embeddings." arXiv:2101.03091 (2021).', 'https://doi.org/10.48550/arXiv.2101.03091')]
+icon_hash = None
+upstream_license = ('MIT License', 'https://github.com/benedekrozemberczki/datasets/blob/3b19135105432cbca65765c1113b91c395ed9d44/LICENSE')
+upstream_prefix = 'https://snap.stanford.edu/data'
+# the features of DE are in musae_DE.json, those of the others in
+# musae_<lang>_features.json
+langs = ['DE', 'ENGB', 'ES', 'FR', 'PTBR', 'RU']
+files = [((f'twitch.zip:twitch/{l}/musae_{l}_edges.csv',
+           f'twitch.zip:twitch/{l}/musae_{l}_target.csv',
+           f'twitch.zip:twitch/{l}/musae_{l}{"" if l == "DE" else "_features"}.json'),
+          l, None) for l in langs]
+files += [(('twitch_gamers.zip:large_twitch_edges.csv',
+            'twitch_gamers.zip:large_twitch_features.csv'), 'twitch_gamers', None)]
+
+def fetch_upstream(force=False):
+    return fetch_upstream_files(__name__.split(".")[-1], upstream_prefix, files,
+                                force)
+
+def _bool(x):
+    return {"True": True, "False": False, "1": True, "0": False}[x]
+
+def _date(x):
+    return calendar.timegm(time.strptime(x, "%Y-%m-%d"))
+
+@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
+        with open_upstream_file(name, fnames[0], "rb") as f:
+            E = numpy.loadtxt(f, delimiter=",", skiprows=1, dtype="int64")
+        with open_upstream_file(name, fnames[1], "r") as f:
+            rows = list(csv.DictReader(f))
+        g = Graph(directed=False)
+        if alt == "twitch_gamers":
+            idx = [int(r["numeric_id"]) for r in rows]
+        else:
+            idx = [int(r["new_id"]) for r in rows]
+        N = max(idx) + 1
+        assert sorted(set(idx)) == list(range(N)) and E.max() < N
+        g.add_vertex(N)
+        g.add_edge_list(E)
+
+        if alt == "twitch_gamers":
+            props = [("views", "int64_t", int), ("mature", "bool", _bool),
+                     ("life_time", "int32_t", int),
+                     ("created_at", "int64_t", _date),
+                     ("updated_at", "int64_t", _date),
+                     ("dead_account", "bool", _bool),
+                     ("language", "string", str),
+                     ("affiliate", "bool", _bool)]
+            key = "numeric_id"
+        else:
+            props = [("id", "int64_t", int), ("days", "int32_t", int),
+                     ("mature", "bool", _bool), ("views", "int64_t", int),
+                     ("partner", "bool", _bool)]
+            key = "new_id"
+        renames = {"id": "twitch_id"}
+        for p, t, conv in props:
+            g.vp[renames.get(p, p)] = g.new_vp(t)
+        seen = set()
+        for r in rows:
+            v = int(r[key])
+            if v in seen:       # duplicated rows in FR: keep the first
+                continue
+            seen.add(v)
+            for p, t, conv in props:
+                g.vp[renames.get(p, p)][v] = conv(r[p])
+
+        if alt != "twitch_gamers":
+            with open_upstream_file(name, fnames[2], "r") as f:
+                feats = json.load(f)
+            assert len(feats) == N
+            g.vp.features = g.new_vp("vector<int32_t>")
+            for v, x in feats.items():
+                g.vp.features[int(v)] = x
+        yield alt, g