Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions data/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
*.zst
ml-*/
ms-web/
steam
!ml-latest-small/
*.parquet
1 change: 1 addition & 0 deletions docs/releases/2026.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ fixed issues and merged PRs is on `milestone 2026.3`_.
- Certain per-request warnings in batch inference are now aggregated (:issue:`1113`, :pr:`1168`).
- Added :class:`lenskit.metrics.UniqueItemCount` (:issue:`1005`, :pr:`1169`).
- Added support for ``interaction="default"`` to :meth:`~lenskit.data.DatasetBuilder.add_relationship_class` (:pr:`1174`).
- Fix Steam dataset import to properly import interactions (previously was incomplete and broken, :issue:`1176`, :pr:`1179`).

.. _milestone 2026.3: https://github.com/lenskit/lkpy/milestone/28?closed=1

Expand Down
27 changes: 25 additions & 2 deletions src/lenskit/data/sources/steam.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def load_steam(*files: Path, reviews: bool = False) -> Dataset:
return _load_au_steam(au_interactions, au_reviews if reviews else None)

elif all_reviews is not None:
_log.debug("looking for full-data inteactions")
_log.debug("looking for full-data interactions")
if au_reviews is not None:
_log.error("cannot specify both Australian and overall input files")
raise DataError("invalid combination of Steam input files")
Expand Down Expand Up @@ -142,7 +142,30 @@ def _load_au_steam(interactions: Path, reviews: Path | None) -> Dataset:
dsb.add_entities("user", users)

_log.info("adding user-item interactions")
# TODO: make DSB work better with CSR-shaped data
dsb.add_relationship_class(
"plays", ["user", "item"], allow_repeats=False, interaction="default"
)
for chunk in items.chunks:
assert isinstance(chunk, pa.ListArray)
# get the user that goes with each (nested) list element
chunk_user_nums = pc.list_parent_indices(chunk)
chunk_user_ids = ui_data.column("steam_id").take(chunk_user_nums)
# get the item IDs
assert isinstance(chunk.values, pa.StructArray)
chunk_item_ids = chunk.values.field("item_id")
assert len(chunk_user_ids) == len(chunk_item_ids)
chunk_playtime = chunk.values.field("playtime_forever")
chunk_playtime2 = chunk.values.field("playtime_2weeks")
chunk_tbl = pa.table(
{
"user_id": chunk_user_ids,
"item_id": chunk_item_ids,
"playtime": chunk_playtime,
"playtime_2weeks": chunk_playtime2,
}
)
_log.debug("adding %d interactions", chunk_tbl.num_rows)
dsb.add_interactions("plays", chunk_tbl, missing="error")

return dsb.build()

Expand Down
34 changes: 34 additions & 0 deletions tests/data/test_load_steam.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# This file is part of LensKit.
# Copyright (C) 2018-2023 Boise State University.
# Copyright (C) 2023-2026 Drexel University.
# Licensed under the MIT license, see LICENSE.md for details.
# SPDX-License-Identifier: MIT

import os
from pathlib import Path

import pandas as pd
import pyarrow as pa
import pyarrow.compute as pc

from pytest import mark

from lenskit.data import Vocabulary
from lenskit.data.sources.steam import load_steam

STEAM_DIR = Path("data/steam")
AU_FILE = STEAM_DIR / "australian_users_items.json.gz"


@mark.skipif(not AU_FILE.exists(), reason="input data does not exist")
@mark.realdata
def test_steam_australia():
data = load_steam(AU_FILE)

# do we have the right number of entities?
assert 87000 < data.user_count < 89000
assert 10000 < data.item_count < 12000

# do we about the right number of interactions?
ints = data.interactions()
assert ints.count() >= 1_000_000
Loading