code: def test_ndcg_at_k():
      # normal cases
      data = pd.DataFrame(
          [
              {
                  "target": [],
                  "prediction": [],
                  "k": [3],
                  "ndcg": 1,
              },  # no error is made
              {
                  "target": [],
                  "prediction": ["1", "2"],
                  "k": [3],
                  "ndcg": 0,
              },
              {"target": ["1"], "prediction": [], "k": [3], "ndcg": 0},
              {
                  "target": ["1"],
                  "prediction": ["1"],
                  "k": [3],
                  "ndcg": 1,
              },
              {
                  "target": ["1"],
                  "prediction": ["2"],
                  "k": [3],
                  "ndcg": 0,
              },
          ]
      )
      predictions = data["prediction"]
      targets = data["target"]
      result = ndcg_at_k(3).eval_fn(predictions, targets)
  
      assert result.scores == data["ndcg"].to_list()
      assert pytest.approx(result.aggregate_results["mean"]) == 0.4
      assert pytest.approx(result.aggregate_results["p90"]) == 1.0
      assert pytest.approx(result.aggregate_results["variance"]) == 0.24
  
      # test different k values
      predictions = pd.Series([["1", "2"]])
      targets = pd.Series([["1"]])
      ndcg = [1, 1, 1]
      for i in range(3):
          k = i + 1
          result = ndcg_at_k(k).eval_fn(predictions, targets)
          assert pytest.approx(result.scores[0]) == ndcg[i]
  
      # test different k values and prediction orders
      predictions = pd.Series([["2", "1", "3"]])
      targets = pd.Series([["1", "2", "3"]])
      ndcg = [1, 1, 1, 1]
      for i in range(4):
          k = i + 1
          result = ndcg_at_k(k).eval_fn(predictions, targets)
          assert pytest.approx(result.scores[0]) == ndcg[i]
  
      # test different k values
      predictions = pd.Series([["4", "5", "1"]])
      targets = pd.Series([["1", "2", "3"]])
      ndcg = [0, 0, 0.2346394, 0.2346394]
      for i in range(4):
          k = i + 1
          result = ndcg_at_k(k).eval_fn(predictions, targets)
          assert pytest.approx(result.scores[0]) == ndcg[i]
  
      # test duplicate predictions
      predictions = pd.Series(
          [["1", "1", "2", "5", "5"], ["1_1", "1_2", "2", "5", "6"]]
      )
      targets = pd.Series([["1", "2", "3"], ["1_1", "1_2", "2", "3"]])
      for i in range(4):
          k = i + 1
          result = ndcg_at_k(k).eval_fn(predictions, targets)
          # row 1 and 2 have the same ndcg score
          assert pytest.approx(result.scores[0]) == pytest.approx(
              result.scores[1]
          )
  
      # test duplicate targets
      predictions = pd.Series([["1", "2", "3"], ["1", "2", "3"]])
      targets = pd.Series([["1", "1", "1"], ["1"]])
      for i in range(4):
          k = i + 1
          result = ndcg_at_k(k).eval_fn(predictions, targets)
          # row 1 and 2 have the same ndcg score
          assert pytest.approx(result.scores[0]) == pytest.approx(
              result.scores[1]
          )
  
imports: from unittest import mock
  import pandas
  import pytest
  from mlflow.metrics import MetricValue, ari_grade_level, exact_match, f1_score, flesch_kincaid_grade_level, mae, mape, max_error, mse, ndcg_at_k, precision_at_k, precision_score, r2_score, recall_at_k, recall_score, rmse, rouge1, rouge2, rougeL, rougeLsum, toxicity
label_desc: Use image node_id 23 for calling a global function with example usage: test_ndcg_at_k() without return types