def encode_x(self, data):
        """
        :param data: unencoded input dataframe
        :return: a dict with encoded values
        """
        encoded = OrderedDict()
        if self.multiprocessing:
            pool = multiprocessing.Pool(self.workers)
            results = []
            for encoder in self.encoders:
                results.append((encoder, pool.apply_async(self.transform, (encoder, data))))

            for encoder, result in results:
                self.merged_transformed(encoded, encoder, result.get())

        else:
            for encoder in self.encoders:
                self.merged_transformed(encoded, encoder, self.transform(encoder, data), append_twin=False)
                if encoder.twin:
                    self.merged_transformed(encoded, encoder, self.transform(encoder, data, append_twin = True), append_twin=True)

        for column in self.index:
            encoded[column] = self.read_column(data, column)

        # Using a DataFrame as a container temporarily requires double the memory,
        # as pandas copies all data on __init__. This is justified by having a
        # type supported by all dependent libraries (heterogeneous dict is not)
        dataframe = pandas.DataFrame(encoded)
        if self.index:
            dataframe.set_index(self.index)
        return dataframe
:param data: unencoded input dataframe
        :return: a dict with encoded values