@classmethod
def by_col(cls, df, e, b, inplace=False, **kwargs):
    """
        Compute smoothing by columns in a dataframe.

        Parameters
        -----------
        df      :  pandas.DataFrame
                   a dataframe containing the data to be smoothed
        e       :  string or list of strings
                   the name or names of columns containing event variables to be
                   smoothed
        b       :  string or list of strings
                   the name or names of columns containing the population
                   variables to be smoothed
        inplace :  bool
                   a flag denoting whether to output a copy of `df` with the
                   relevant smoothed columns appended, or to append the columns
                   directly to `df` itself.
        **kwargs:  optional keyword arguments
                   optional keyword options that are passed directly to the
                   smoother.

        Returns
        ---------
        a copy of `df` containing the columns. Or, if `inplace`, this returns
        None, but implicitly adds columns to `df`.
        """
    if not inplace:
        new = df.copy()
        cls.by_col(new, e, b, inplace=True, **kwargs)
        return new
    if isinstance(e, str):
        e = [e]
    if isinstance(b, str):
        b = [b]
    if len(b) == 1 and len(e) > 1:
        b = b * len(e)
    try:
        assert len(e) == len(b)
    except AssertionError:
        raise ValueError(
            'There is no one-to-one mapping between event variable and population at risk variable!'
            )
    for ei, bi in zip(e, b):
        ename = ei
        bname = bi
        ei = df[ename]
        bi = df[bname]
        outcol = '_'.join(('-'.join((ename, bname)), cls.__name__.lower()))
        df[outcol] = cls(ei, bi, **kwargs).r
