def encode_categorical(df):
    """
    Compresses the size of the dataframe by changing column data type to minimum required size
    that can accommodate the values. This is done only for categorical columns.
    If a numeric column is expected to have very few values, change that to categorical first
    and then use this method.
    :param df: input dataframe
    :return: modified dataframe
    """
    cat_cols = df.select_dtypes("category").columns
    for col in cat_cols:
        df[col] = df[col].cat.codes + 1
        unique_no = len(df[col].unique())
        if unique_no < 50:
            df[col] = df[col].astype("uint8")
        elif unique_no < 16000:
            df[col] = df[col].astype("int16")
        else:
            df[col] = df[col].astype("int32")
    return df