def reconstruct_data(self, Z_df):
     """
     Input: n x (k+1) data frame with ID column and k latent components
     Output: n x (d+1) data frame with ID column and data projected into the original (post-processed) space
     """
     Z = remove_id_and_get_mat(Z_df)
     X = Z.dot(self.U.T)
     df = add_id(Z=X, df_with_id=Z_df)
     df.columns = ['individual_id'] + self.feature_names
     return df
    def get_projections(self, df, **projection_kwargs):
        """
        use the fitted model to get projections for df. 
        """
        print("Getting projections using method %s." % self.__class__.__name__)
        X = self.data_preprocessing_function(df)
        Z = self._get_projections_from_processed_data(X, **projection_kwargs)
        Z_df = add_id(
            Z, df)  # Z_df will have the same index and individual id as df.
        Z_df.columns = ['individual_id'
                        ] + ['z%s' % i for i in range(Z.shape[1])]

        return Z_df
    def get_projections(self, df, project_onto_mean, **projection_kwargs):
        """
        use the fitted model to get projections for df. 
        if project_onto_mean=True, projects onto the mean value of Z (Z_mu). Otherwise, samples Z.
        """
        #print("Getting projections using method %s." % self.__class__.__name__)
        X = self.data_preprocessing_function(df)
        ages = self.get_ages(df)
        Z = self._get_projections_from_processed_data(X, ages, project_onto_mean, **projection_kwargs)
        Z_df = add_id(Z, df) # Z_df and df will have the same id and individual_id. 
        Z_df.columns = ['individual_id'] + ['z%s' % i for i in range(Z.shape[1])]

        return Z_df