docs: def knn_tree(self):
          """KNN tree object (cached)
  
          Builds or returns the fitted KNN tree.
          TODO: can we be more clever than sklearn when it comes to choosing
          between KD tree, ball tree and brute force?
  
          Returns
          -------
          knn_tree : `sklearn.neighbors.NearestNeighbors`
          """
          try:
              return self._knn_tree
          except AttributeError:
              try:
                  self._knn_tree = NearestNeighbors(
                      n_neighbors=self.knn + 1,
                      algorithm='ball_tree',
                      metric=self.distance,
                      n_jobs=self.n_jobs).fit(self.data_nu)
              except ValueError:
                  # invalid metric
                  warnings.warn(
                      "Metric {} not valid for `sklearn.neighbors.BallTree`. "
                      "Graph instantiation may be slower than normal.".format(
                          self.distance),
                      UserWarning)
                  self._knn_tree = NearestNeighbors(
                      n_neighbors=self.knn + 1,
                      algorithm='auto',
                      metric=self.distance,
                      n_jobs=self.n_jobs).fit(self.data_nu)
              return self._knn_tree