class_docstr: MPCA implementation compatible with scikit-learn
  
  Args:
      var_ratio (float, optional): Percentage of variance explained (between 0 and 1). Defaults to 0.97.
      max_iter (int, optional): Maximum number of iteration. Defaults to 1.
      vectorize (bool): Whether return the transformed/projected tensor in vector. Defaults to False.
      n_components (int): Number of components to keep. Applies only when vectorize=True. Defaults to None.
  
  Attributes:
      proj_mats (list of arrays): A list of transposed projection matrices, shapes (P_1, I_1), ...,
          (P_N, I_N), where P_1, ..., P_N are output tensor shape for each sample.
      idx_order (array-like): The ordering index of projected (and vectorized) features in decreasing variance.
      mean_ (array-like): Per-feature empirical mean, estimated from the training set, shape (I_1, I_2, ..., I_N).
      shape_in (tuple): Input tensor shapes, i.e. (I_1, I_2, ..., I_N).
      shape_out (tuple): Output tensor shapes, i.e. (P_1, P_2, ..., P_N).
  
  Reference:
      Haiping Lu, K.N. Plataniotis, and A.N. Venetsanopoulos, "MPCA: Multilinear Principal Component Analysis of
      Tensor Objects", IEEE Transactions on Neural Networks, Vol. 19, No. 1, Page: 18-39, January 2008. For initial
      Matlab implementation, please go to https://uk.mathworks.com/matlabcentral/fileexchange/26168.
  
  Examples:
      >>> import numpy as np
      >>> from kale.embed.factorization import MPCA
      >>> x = np.random.random((40, 20, 25, 20))
      >>> x.shape
      (40, 20, 25, 20)
      >>> mpca = MPCA()
      >>> x_projected = mpca.fit_transform(x)
      >>> x_projected.shape
      (40, 18, 23, 18)
      >>> x_projected = mpca.transform(x)
      >>> x_projected.shape
      (40, 7452)
      >>> x_projected = mpca.transform(x)
      >>> x_projected.shape
      (40, 50)
      >>> x_rec = mpca.inverse_transform(x_projected)
      >>> x_rec.shape
      (40, 20, 25, 20)
docstr: Reconstruct projected data to the original shape and add the estimated mean back
  
  Args:
      x (array-like tensor): Data to be reconstructed, shape (n_samples, P_1, P_2, ..., P_N), if
          self.vectorize == False, where P_1, P_2, ..., P_N are the reduced dimensions of corresponding
          mode (1, 2, ..., N), respectively. If self.vectorize == True, shape (n_samples, self.n_components)
          or shape (n_samples, P_1 * P_2 * ... * P_N).
  
  Returns:
      array-like tensor:
          Reconstructed tensor in original shape, shape (n_samples, I_1, I_2, ..., I_N)
docstr_tok: ["Reconstruct","projected","data","to","the","original","shape","and","add","the","estimated","mean","back","Args",":","x","(","array-like","tensor",")",":","Data","to","be","reconstructed",",","shape","(","n_samples",",","P_1",",","P_2",",","...",",","P_N",")",",","if","self.vectorize","==","False",",","where","P_1",",","P_2",",","...",",","P_N","are","the","reduced","dimensions","of","corresponding","mode","(","1",",","2",",","...",",","N",")",",","respectively",".","If","self.vectorize","==","True",",","shape","(","n_samples",",","self.n_components",")","or","shape","(","n_samples",",","P_1","*","P_2","*","...","*","P_N",")",".","Returns",":","array-like","tensor",":","Reconstructed","tensor","in","original","shape",",","shape","(","n_samples",",","I_1",",","I_2",",","...",",","I_N",")"]
code: def inverse_transform(self, x):
      """Reconstruct projected data to the original shape and add the estimated mean back
  
      Args:
          x (array-like tensor): Data to be reconstructed, shape (n_samples, P_1, P_2, ..., P_N), if
              self.vectorize == False, where P_1, P_2, ..., P_N are the reduced dimensions of corresponding
              mode (1, 2, ..., N), respectively. If self.vectorize == True, shape (n_samples, self.n_components)
              or shape (n_samples, P_1 * P_2 * ... * P_N).
  
      Returns:
          array-like tensor:
              Reconstructed tensor in original shape, shape (n_samples, I_1, I_2, ..., I_N)
      """
      # reshape x to tensor in shape (n_samples, self.shape_out) if x has been unfolded
      if x.ndim <= 2:
          if x.ndim == 1:
              # reshape x to a 2D matrix (1, n_components) if x in shape (n_components,)
              x = x.reshape((1, -1))
          n_samples = x.shape[0]
          n_features = x.shape[1]
          if n_features <= np.prod(self.shape_out):
              x_ = np.zeros((n_samples, np.prod(self.shape_out)))
              x_[:, self.idx_order[:n_features]] = x[:]
          else:
              msg = "Feature dimension exceeds the shape upper limit."
              logging.error(msg)
              raise ValueError(msg)
  
          x = fold(x_, mode=0, shape=((n_samples,) + self.shape_out))
  
      x_rec = multi_mode_dot(
          x,
          self.proj_mats,
          modes=[m for m in range(1, self.n_dims)],
          transpose=True,
      )
  
      x_rec = x_rec + self.mean_
  
      return x_rec
  
imports: import logging
  import warnings
  import numpy
  from numpy.linalg import multi_dot
  from scipy import linalg
  from sklearn.base import BaseEstimator, TransformerMixin
  from sklearn.metrics.pairwise import pairwise_kernels
  from sklearn.preprocessing import KernelCenterer, LabelBinarizer
  from sklearn.utils.validation import check_is_fitted
  from tensorly.base import fold, unfold
  from tensorly.tenalg import multi_mode_dot
label_desc: Use image node_id 5 for calling the MPCA obj's underlying member method code with example usage: obj.inverse_transform(x) and returns: x_rec