'Create a Model from a formula and dataframe.
Parameters
formula : str or generic Formula object
The formula specifying the model
data : array-like
The data for the model. See Notes.
subset : array-like
An array-like object of booleans, integers, or index values that
indicate the subset of df to use in the model. Assumes df is a
`pandas.DataFrame`
drop_cols : array-like
Columns to drop from the design matrix.  Cannot be used to
drop terms involving categoricals.
args : extra arguments
These are passed to the model
kwargs : extra keyword arguments
These are passed to the model with one exception. The
``eval_env`` keyword is passed to patsy. It can be either a
:class:`patsy:patsy.EvalEnvironment` object or an integer
indicating the depth of the namespace to use. For example, the
default ``eval_env=0`` uses the calling namespace. If you wish
to use a "clean" environment set ``eval_env=-1``.
Returns
model : Model instance
Notes
data must define __getitem__ with the keys in the formula terms
args and kwargs are passed on to the model instantiation. E.g.,
a numpy structured or rec array, a dictionary, or a pandas DataFrame.'

@classmethod
def from_formula(cls, formula, data, subset=None, drop_cols=None, *args, **kwargs):

    if (subset is not None):
        data = data.loc[subset]
    eval_env = kwargs.pop('eval_env', None)
    if (eval_env is None):
        eval_env = 2
    elif (eval_env == (-1)):
        from patsy import EvalEnvironment
        eval_env = EvalEnvironment({})
    else:
        eval_env += 1
    missing = kwargs.get('missing', 'drop')
    if (missing == 'none'):
        missing = 'raise'
    tmp = handle_formula_data(data, None, formula, depth=eval_env, missing=missing)
    ((endog, exog), missing_idx, design_info) = tmp
    if ((drop_cols is not None) and (len(drop_cols) > 0)):
        cols = [x for x in exog.columns if (x not in drop_cols)]
        if (len(cols) < len(exog.columns)):
            exog = exog[cols]
            cols = list(design_info.term_names)
            for col in drop_cols:
                try:
                    cols.remove(col)
                except ValueError:
                    pass
            design_info = design_info.builder.subset(cols).design_info
    kwargs.update({'missing_idx': missing_idx, 'missing': missing, 'formula': formula, 'design_info': design_info})
    mod = cls(endog, exog, *args, **kwargs)
    mod.formula = formula
    mod.data.frame = data
    return mod
