class_docstr: Handmade PCA to bypass sklearn dependency.
  
  Attributes:
      n_components:
          Number of principal components to keep.
      eps:
          Epsilon for numerical stability.
docstr: Uses PCA to transform data in X.
  
  Args:
      X:
          Datapoints stored in numpy array of size n x d.
  
  Returns:
      Numpy array of n x p datapoints where p <= d.
  
  Raises:
      ValueError: If PCA was not fitted before.
docstr_tok: ["Uses","PCA","to","transform","data","in","X.","Args",":","X",":","Datapoints","stored","in","numpy","array","of","size","n","x","d.","Returns",":","Numpy","array","of","n","x","p","datapoints","where","p","<","=","d.","Raises",":","ValueError",":","If","PCA","was","not","fitted","before","."]
code: def transform(self, X: NDArray[np.float32]) -> NDArray[np.float32]:
      """Uses PCA to transform data in X.
  
      Args:
          X:
              Datapoints stored in numpy array of size n x d.
  
      Returns:
          Numpy array of n x p datapoints where p <= d.
  
      Raises:
          ValueError: If PCA was not fitted before.
      """
      if self.mean is None or self.w is None:
          raise ValueError(
              "PCA not fitted yet. Call fit() before transform()."
          )
      X = X.astype(np.float32)
      X = X - self.mean + self.eps
      transformed: NDArray[np.float32] = X.dot(self.w)[
          :, : self.n_components
      ]
      return np.asarray(transformed)
  
file_path: lightly/lightly/utils/embeddings_2d.py
imports: from __future__ import annotations
  from typing import Optional, Tuple
  import numpy
  from numpy.typing import NDArray
label_desc: Use image node_id 3 for calling the PCA obj's underlying member method code with example usage: obj.transform(X) and returns: np