code: def build(self):
      data, k = self.data, self.k
  
      timer = utils.Timer(
          f"Finding {k} nearest neighbors using NN descent approximate search using "
          f"{self.metric} distance...",
          verbose=self.verbose,
      )
      timer.__enter__()
  
      # These values were taken from UMAP, which we assume to be sensible defaults
      n_trees = 5 + int(round((data.shape[0]) ** 0.5 / 20))
      n_iters = max(5, int(round(np.log2(data.shape[0]))))
  
      # Numba takes a while to load up, so there's little point in loading it
      # unless we're actually going to use it
      import pynndescent
  
      # Will use query() only for k>15
      if k <= 15:
          n_neighbors_build = k + 1
      else:
          n_neighbors_build = 15
  
      self.index = pynndescent.NNDescent(
          data,
          n_neighbors=n_neighbors_build,
          metric=self.metric,
          metric_kwds=self.metric_params,
          random_state=self.random_state,
          n_trees=n_trees,
          n_iters=n_iters,
          max_candidates=60,
          n_jobs=self.n_jobs,
          verbose=self.verbose > 1,
      )
  
      # -1 in indices means that pynndescent failed
      indices, distances = self.index.neighbor_graph
      mask = np.sum(indices == -1, axis=1) > 0
  
      if k > 15:
          indices, distances = self.index.query(data, k=k + 1)
  
      # As a workaround, we let the failed points group together
      if np.sum(mask) > 0:
          if self.verbose:
              opt = np.get_printoptions()
              np.set_printoptions(threshold=np.inf)
              warnings.warn(
                  f"`pynndescent` failed to find neighbors for some of the points. "
                  f"As a workaround, openTSNE considers all such points similar to "
                  f"each other, so they will likely form a cluster in the embedding."
                  f"The indices of the failed points are:\n{np.where(mask)[0]}"
              )
              np.set_printoptions(**opt)
          else:
              warnings.warn(
                  f"`pynndescent` failed to find neighbors for some of the points. "
                  f"As a workaround, openTSNE considers all such points similar to "
                  f"each other, so they will likely form a cluster in the embedding. "
                  f"Run with verbose=True, to see indices of the failed points."
              )
          distances[mask] = 1
          rs = check_random_state(self.random_state)
          fake_indices = rs.choice(
              np.sum(mask),
              size=np.sum(mask) * indices.shape[1],
              replace=True,
          )
          fake_indices = np.where(mask)[0][fake_indices]
          indices[mask] = np.reshape(
              fake_indices, (np.sum(mask), indices.shape[1])
          )
  
      timer.__exit__()
  
      return indices[:, 1:], distances[:, 1:]
  
imports: import logging
  import os
  import warnings
  import numpy
  from scipy.spatial.distance import cdist
  from sklearn import neighbors
  from sklearn.utils import check_random_state
  from openTSNE import utils
label_desc: Use image node_id 3 for calling the NNDescent obj's underlying member method code with example usage: obj.build() and returns: indices,  distances