code: def union_find(
      scored_pairs: Scores,
  ) -> numpy.typing.NDArray[numpy.int_]:
      root: dict[RecordID, int] = {}
  
      components = {}
  
      edgelist = scored_pairs["pairs"]
      labels = scored_pairs["label"]
  
      it = numpy.nditer(edgelist, ["external_loop"])
  
      n_edges = len(scored_pairs)
  
      array_type = "H"
      for array_type in ("H", "I", "L", "Q"):
          if (
              2 ** (8 * array.array(array_type).itemsize) - 1
          ) > n_edges:
              break
      else:
          raise ValueError(
              "You are making more comparisons than your machine can handle, try raising the threshold"
          )
  
      a: RecordID
      b: RecordID
  
      for i, (a, b) in enumerate(it):  # type: ignore
          root_a = root.get(a)
          root_b = root.get(b)
  
          if root_a is None and root_b is None:
              root[a] = root[b] = i
              components[i] = array.array(array_type, [i])
          elif root_a is None or root_b is None:
              if root_a is None:
                  b = a
                  root_a = root_b
              root_a = cast(int, root_a)
              components[root_a].append(i)
              root[b] = root_a
          elif root_a != root_b:
              if len(components[root_a]) < len(components[root_b]):
                  root_a, root_b = root_b, root_a
  
              components[root_a].extend(components[root_b])
              components[root_a].append(i)
  
              component_b = numpy.unique(edgelist[components[root_b]])
              for node in component_b:
                  root[node] = root_a
  
              del components[root_b]
  
          else:
              components[root_a].append(i)
  
      for label, component in components.items():
          labels[component] = label
  
      # we want our selections to remain memmapped arrays so we sort and
      # get the indices where the components change. This will allow us
      # to slice pieces of the memmapped array, and have those slices
      # also be memmaped arrays.
      #
      # Since we we might be calling union_find recursively it would be
      # good to use a stable sort to take advantage of sorting done in a
      # previous recursion.
      #
      # stable sorts in numpy take about n / 2 work space so we won't
      # do it if scored_pairs is too big
      if len(scored_pairs) > 2500000:
          scored_pairs.sort(order=("label", "score"))
      else:
          scored_pairs.sort(order=("label", "score"), kind="stable")
  
      return numpy.cumsum(
          numpy.unique(scored_pairs["label"], return_counts=True)[1]
      )
  
imports: from __future__ import annotations
  import array
  import itertools
  import logging
  import tempfile
  from collections import defaultdict
  from typing import Generator, Iterable, Sequence, cast
  import numpy
  import numpy.typing
  import scipy.cluster.hierarchy
  from dedupe._typing import ArrayLinks, Clusters, RecordID, Scores, TupleLinks
label_desc: Use image node_id 3 for calling a global function with example usage: union_find(scored_pairs) and returns: numpy