Performs mean imputation on a pandas dataframe.
    Args:
        train: an optional training mask with which to compute the mean
        value: instead of computing the mean, use this as the value argument to fillna
        dropna: whether to drop all null columns
        inplace: whether to perform the imputation inplace
    Returns: the imputed DataFrame

def impute(X, value=None, train=None, dropna=True, inplace=True):
    """
    Performs mean imputation on a pandas dataframe.
    Args:
        train: an optional training mask with which to compute the mean
        value: instead of computing the mean, use this as the value argument to fillna
        dropna: whether to drop all null columns
        inplace: whether to perform the imputation inplace
    Returns: the imputed DataFrame
    """
    if value is None:
        Xfit = X[train] if train is not None else X
        value = Xfit.mean()
    else:
        if train is not None:
            raise ValueError("Cannot pass both train and value arguments")

    if dropna:
        null_columns = value.index[value.isnull()]
        if len(null_columns) > 0:
            logging.info('Dropping null columns: \n\t%s' % null_columns)
            if inplace:
                X.drop(null_columns, axis=1, inplace=True)
            else:
                X = X.drop(null_columns, axis=1, inplace=False)

    if inplace:
        X.fillna(value.dropna(), inplace=True)
    else:
        X = X.fillna(value.dropna(), inplace=False)

    return X