code: def test_spec_group_cols():
      rla = topn.RecListAnalysis(group_cols=["data", "user"])
      rla.add_metric(topn.precision)
      rla.add_metric(topn.recall)
      rla.add_metric(topn.ndcg)
  
      recs = pd.DataFrame(
          {
              "data": "a",
              "user": ["a", "a", "a", "b", "b"],
              "item": [2, 3, 1, 4, 5],
              "rank": [1, 2, 3, 1, 2],
              "wombat": np.random.randn(5),
          }
      )
      truth = pd.DataFrame(
          {
              "user": ["a", "a", "a", "b", "b", "b"],
              "item": [1, 2, 3, 1, 5, 6],
              "rating": [3.0, 5.0, 4.0, 3.0, 5.0, 4.0],
          }
      )
  
      res = rla.compute(recs, truth)
      print(res)
  
      assert len(res) == 2
      assert res.index.nlevels == 2
      assert res.index.names == ["data", "user"]
      assert all(res.index.levels[0] == "a")
      assert all(res.index.levels[1] == ["a", "b"])
      assert all(res.reset_index().user == ["a", "b"])
      partial_ndcg = _dcg([0.0, 5.0]) / _dcg([5, 4, 3])
      assert res.ndcg.values == approx([1.0, partial_ndcg])
      assert res.precision.values == approx([1.0, 1 / 2])
      assert res.recall.values == approx([1.0, 1 / 3])
  
imports: from pathlib import Path
  import logging
  import numpy
  import pandas
  from pytest import approx, mark
  from lenskit.algorithms.user_knn import UserUser
  from lenskit.algorithms.item_knn import ItemItem
  from lenskit.algorithms.basic import PopScore
  from lenskit.algorithms.ranking import PlackettLuce
  from lenskit.algorithms import Recommender
  from lenskit.util.test import ml_test, demo_recs
  from lenskit.metrics.topn import _dcg, precision, recall
  from lenskit import topn, batch, crossfold
label_desc: Use image node_id 6 for calling a global function with example usage: test_spec_group_cols() without return types