code: def fit(self, X, y=None):
      # Separate numerical columns from categorical columns
      self.num_cols_ = X.select_dtypes(
          include=["float"]
      ).columns.tolist()
      if not self.num_cols_:
          raise ValueError(
              "All variables are qualitative: MCA should be used"
          )
      self.cat_cols_ = X.columns.difference(self.num_cols_).tolist()
      if not self.cat_cols_:
          raise ValueError(
              "All variables are quantitative: PCA should be used"
          )
  
      # Preprocess numerical columns
      X_num = X[self.num_cols_].copy()
      self.num_scaler_ = preprocessing.StandardScaler().fit(X_num)
      X_num[:] = self.num_scaler_.transform(X_num)
  
      # Preprocess categorical columns
      X_cat = X[self.cat_cols_]
      self.cat_scaler_ = preprocessing.OneHotEncoder(
          handle_unknown=self.handle_unknown
      ).fit(X_cat)
      X_cat_oh = pd.DataFrame.sparse.from_spmatrix(
          self.cat_scaler_.transform(X_cat),
          index=X_cat.index,
          columns=self.cat_scaler_.get_feature_names_out(
              self.cat_cols_
          ),
      )
      prop = X_cat_oh.sum() / X_cat_oh.sum().sum() * 2
      X_cat_oh_norm = X_cat_oh.sub(X_cat_oh.mean(axis="rows")).div(
          prop**0.5, axis="columns"
      )
  
      # PCA.fit doesn't work with sparse matrices. Well, it accepts them, but it densifies them.
      # We pre-densify them here to avoid a warning.
      # TODO: In the future, PCA should be able to handle sparse matrices.
      X_cat_oh_norm = X_cat_oh_norm.sparse.to_dense()
  
      Z = pd.concat([X_num, X_cat_oh_norm], axis=1)
      super().fit(Z)
  
      # Determine column_coordinates_
      # This is based on line 184 in FactoMineR's famd.R file
      rc = self.row_coordinates(X)
      weights = np.ones(len(X_cat_oh)) / len(X_cat_oh)
      norm = (rc**2).multiply(weights, axis=0).sum()
      eta2 = pd.DataFrame(index=rc.columns)
      for i, col in enumerate(self.cat_cols_):
          # TODO: there must be a better way to select a subset of the one-hot encoded matrix
          tt = X_cat_oh[
              [f"{col}_{i}" for i in self.cat_scaler_.categories_[i]]
          ]
          ni = (tt / len(tt)).sum()
          eta2[col] = (
              rc.apply(
                  lambda x: (
                      tt.multiply(x * weights, axis=0).sum() ** 2 / ni
                  ).sum()
              )
              / norm
          ).values
      self.column_coordinates_ = pd.concat(
          [self.column_coordinates_.loc[self.num_cols_] ** 2, eta2.T]
      )
      self.column_coordinates_.columns.name = "component"
      self.column_coordinates_.index.name = "variable"
  
      return self
  
file_path: prince/prince/famd.py
imports: from __future__ import annotations
  import numpy
  import pandas
  import sklearn.utils
  from sklearn import preprocessing
  from prince import pca, utils
label_desc: Use image node_id 3 for calling the FAMD obj's underlying member method code with example usage: obj.fit(X, y) and returns: self