logo Netzschleuder network catalog, repository, and centrifuge

History of epinions_massa

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/epinions_massa/__init__.py b/entries/epinions_massa/__init__.py
index 87b20f2..5db8a19 100644
--- a/entries/epinions_massa/__init__.py
+++ b/entries/epinions_massa/__init__.py
@@ -37,7 +37,7 @@ The networks have the following properties:
 tags = ['Social', 'Online', 'Economic', 'Preferences', 'Bipartite', 'Weighted', 'Unweighted']
 url = ['https://web.archive.org/web/20100308104815/http://www.trustlet.org/wiki/Downloaded_Epinions_dataset']
 citation = [('P. Massa, P. Avesani, "Trust-aware recommender systems." Proceedings of the 2007 ACM Conference on Recommender Systems (RecSys), 17-24 (2007)', 'https://doi.org/10.1145/1297231.1297235')]
-icon_hash = None
+date_added = '2026-10-31'
 upstream_license = None
 # trustlet.org no longer exists, so the files are obtained from the
 # Internet Archive (each file is a tar archive of one text file, compressed
[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/epinions_massa/__init__.py b/entries/epinions_massa/__init__.py
index 73537f3..87b20f2 100644
--- a/entries/epinions_massa/__init__.py
+++ b/entries/epinions_massa/__init__.py
@@ -30,9 +30,10 @@ Other Epinions data in the repository: `epinions` is the larger dataset that the
 
 The networks have the following properties:
 
-- `ratings`, nodes: `is_user`, whether the node is a user (otherwise an item); `id`, the id of the user or item.
-- `ratings`, edges: `rating`, the rating (1 to 5).
-- `trust`, nodes: `id`, the id of the user."""
+- (Node) `is_user` (`ratings`): whether the node is a user (otherwise an item).
+- (Node) `id` (`ratings`): the id of the user or item.
+- (Edge) `rating` (`ratings`): the rating (1 to 5).
+- (Node) `id` (`trust`): the id of the user."""
 tags = ['Social', 'Online', 'Economic', 'Preferences', 'Bipartite', 'Weighted', 'Unweighted']
 url = ['https://web.archive.org/web/20100308104815/http://www.trustlet.org/wiki/Downloaded_Epinions_dataset']
 citation = [('P. Massa, P. Avesani, "Trust-aware recommender systems." Proceedings of the 2007 ACM Conference on Recommender Systems (RecSys), 17-24 (2007)', 'https://doi.org/10.1145/1297231.1297235')]
[entries] Remove unneeded code from the entries by Tiago de Paula Peixoto 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/epinions_massa/__init__.py b/entries/epinions_massa/__init__.py
index 32611b2..73537f3 100644
--- a/entries/epinions_massa/__init__.py
+++ b/entries/epinions_massa/__init__.py
@@ -76,7 +76,6 @@ def read_rows(name, fname):
 @coerce_props()
 @annotate()
 def parse(alts=None):
-    global files
     name = __name__.split(".")[-1]
     ratings = trust = None
     for fnames, alt, fmt in files:
[entries] New entry: epinions_massa by Tiago de Paula Peixoto 39c0d08
diff --git a/entries/epinions_massa/__init__.py b/entries/epinions_massa/__init__.py
new file mode 100644
index 0000000..32611b2
--- /dev/null
+++ b/entries/epinions_massa/__init__.py
@@ -0,0 +1,111 @@
+#! /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 *
+
+import tarfile
+
+title = "Epinions product ratings and trust (2003)"
+description = """The "downloaded Epinions dataset" of Paolo Massa, collected in a 5-week crawl of the consumer review site Epinions.com in November and December 2003, and distributed on the TrustLet wiki: the ratings that the users gave to products (items) when reviewing them, and the trust statements among the users (their "web of trust"). Users and items are identified by anonymized numeric ids, from 1 to 49,289 for the users (the documentation gives 49,290 users, but no id above 49,289 appears in the files) and from 1 to 139,738 for the items. The distrust statements (the "block list") are not included, since the site kept them private.
+
+- `ratings`: a bipartite network of the users and the items, with 664,824 ratings (no pair of user and item is repeated). An edge connects a user to an item they rated, on a scale of 1 to 5. All the users of the dataset are included, also the 9,126 who rated no item (but appear in the trust statements), so that the user nodes are the same as in `trust`.
+- `trust`: a directed network of the 487,183 trust statements among the users (the documentation gives 487,181), where an edge from user A to user B means that A trusts B. All the users are included, also those making or receiving no statement; 181 users trust themselves.
+
+Other Epinions data in the repository: `epinions` is the larger dataset that the Epinions staff gave to Massa (2001-2003), with the helpfulness ratings of the reviews (not of the products), and the trust and distrust statements with their dates; `epinions_trust` is the trust network collected by Richardson, Agrawal and Domingos in 2003; and the network `epinions` of `signed_social_media` is the same trust and distrust network as in `epinions`, without the dates. The user ids differ between these datasets.
+
+The networks have the following properties:
+
+- `ratings`, nodes: `is_user`, whether the node is a user (otherwise an item); `id`, the id of the user or item.
+- `ratings`, edges: `rating`, the rating (1 to 5).
+- `trust`, nodes: `id`, the id of the user."""
+tags = ['Social', 'Online', 'Economic', 'Preferences', 'Bipartite', 'Weighted', 'Unweighted']
+url = ['https://web.archive.org/web/20100308104815/http://www.trustlet.org/wiki/Downloaded_Epinions_dataset']
+citation = [('P. Massa, P. Avesani, "Trust-aware recommender systems." Proceedings of the 2007 ACM Conference on Recommender Systems (RecSys), 17-24 (2007)', 'https://doi.org/10.1145/1297231.1297235')]
+icon_hash = None
+upstream_license = None
+# trustlet.org no longer exists, so the files are obtained from the
+# Internet Archive (each file is a tar archive of one text file, compressed
+# with bzip2)
+archived_urls = {
+    'ratings_data.txt.bz2':
+    'https://web.archive.org/web/20161228000730id_/http://www.trustlet.org/datasets/downloaded_epinions/ratings_data.txt.bz2',
+    'trust_data.txt.bz2':
+    'https://web.archive.org/web/20161228001201id_/http://www.trustlet.org/datasets/downloaded_epinions/trust_data.txt.bz2'}
+files = [(('ratings_data.txt.bz2', 'trust_data.txt.bz2'), 'ratings', None),
+         (('ratings_data.txt.bz2', 'trust_data.txt.bz2'), 'trust', None)]
+
+# Limit of rows of each file to read, for quick checks
+_check_rows = None
+
+def fetch_upstream(force=False):
+    return fetch_archived_files(__name__.split(".")[-1], archived_urls, force,
+                                tries=3)
+
+def read_rows(name, fname):
+    "The rows of three integers of the text file in the tar archive `fname`."
+    rows = []
+    with open_upstream_file(name, fname, "rb") as f:
+        with tarfile.open(fileobj=f, mode="r|bz2") as tf:
+            for m in tf:
+                if not m.isfile():
+                    continue
+                for n, line in enumerate(tf.extractfile(m)):
+                    if _check_rows is not None and n >= _check_rows:
+                        break
+                    if line.strip():
+                        rows.append([int(x) for x in line.split()])
+    rows = numpy.array(rows, dtype="int64").reshape(-1, 3)
+    return rows
+
+@cache_network()
+@coerce_props()
+@annotate()
+def parse(alts=None):
+    global files
+    name = __name__.split(".")[-1]
+    ratings = trust = None
+    for fnames, alt, fmt in files:
+        if alts is not None and alt not in alts:
+            continue
+        if ratings is None:
+            ratings = read_rows(name, fnames[0])
+            trust = read_rows(name, fnames[1])
+        # the user nodes (ids 1 to N_u) are the same in both networks
+        N_u = max(ratings[:, 0].max(), trust[:, :2].max())
+        if alt == "ratings":
+            N_i = ratings[:, 1].max()
+            g = Graph(directed=False)
+            g.add_vertex(N_u + N_i)
+            g.vp.is_user = g.new_vp("bool")
+            g.vp.is_user.a[:N_u] = True
+            g.vp.id = g.new_vp("int")
+            g.vp.id.a[:N_u] = numpy.arange(1, N_u + 1)
+            g.vp.id.a[N_u:] = numpy.arange(1, N_i + 1)
+            g.ep.rating = g.new_ep("int")
+            g.add_edge_list(numpy.column_stack((ratings[:, 0] - 1,
+                                                N_u + ratings[:, 1] - 1,
+                                                ratings[:, 2])),
+                            eprops=[g.ep.rating])
+        else:
+            # the third column is always 1 (trust)
+            assert (trust[:, 2] == 1).all()
+            g = Graph(directed=True)
+            g.add_vertex(N_u)
+            g.vp.id = g.new_vp("int", vals=range(1, N_u + 1))
+            g.add_edge_list(trust[:, :2] - 1)
+        yield alt, g