def _cython_operation(self, kind, values, how, axis):
        assert kind in ['transform', 'aggregate']

        arity = self._cython_arity.get(how, 1)

        vdim = values.ndim
        swapped = False
        if vdim == 1:
            values = values[:, None]
            out_shape = (self.ngroups, arity)
        else:
            if axis > 0:
                swapped = True
                values = values.swapaxes(0, axis)
            if arity > 1:
                raise NotImplementedError("arity of more than 1 is not "
                                          "supported for the 'how' argument")
            out_shape = (self.ngroups,) + values.shape[1:]

        is_numeric = is_numeric_dtype(values.dtype)

        if is_datetime_or_timedelta_dtype(values.dtype):
            values = values.view('int64')
            is_numeric = True
        elif is_bool_dtype(values.dtype):
            values = _algos.ensure_float64(values)
        elif com.is_integer_dtype(values):
            values = values.astype('int64', copy=False)
        elif is_numeric and not com.is_complex_dtype(values):
            values = _algos.ensure_float64(values)
        else:
            values = values.astype(object)

        try:
            func, dtype_str = self._get_cython_function(
                kind, how, values, is_numeric)
        except __HOLE__:
            if is_numeric:
                values = _algos.ensure_float64(values)
                func, dtype_str = self._get_cython_function(
                    kind, how, values, is_numeric)
            else:
                raise

        if is_numeric:
            out_dtype = '%s%d' % (values.dtype.kind, values.dtype.itemsize)
        else:
            out_dtype = 'object'

        labels, _, _ = self.group_info

        if kind == 'aggregate':
            result = _maybe_fill(np.empty(out_shape, dtype=out_dtype),
                                 fill_value=np.nan)
            counts = np.zeros(self.ngroups, dtype=np.int64)
            result = self._aggregate(
                result, counts, values, labels, func, is_numeric)
        elif kind == 'transform':
            result = _maybe_fill(np.empty_like(values, dtype=out_dtype),
                                 fill_value=np.nan)

            # temporary storange for running-total type tranforms
            accum = np.empty(out_shape, dtype=out_dtype)
            result = self._transform(
                result, accum, values, labels, func, is_numeric)

        if com.is_integer_dtype(result):
            if len(result[result == tslib.iNaT]) > 0:
                result = result.astype('float64')
                result[result == tslib.iNaT] = np.nan

        if kind == 'aggregate' and \
           self._filter_empty_groups and not counts.all():
            if result.ndim == 2:
                try:
                    result = lib.row_bool_subset(
                        result, (counts > 0).view(np.uint8))
                except ValueError:
                    result = lib.row_bool_subset_object(
                        com._ensure_object(result),
                        (counts > 0).view(np.uint8))
            else:
                result = result[counts > 0]

        if vdim == 1 and arity == 1:
            result = result[:, 0]

        if how in self._name_functions:
            # TODO
            names = self._name_functions[how]()
        else:
            names = None

        if swapped:
            result = result.swapaxes(0, axis)

        return result, names
dataset/ETHPy150Open pydata/pandas/pandas/core/groupby.py/BaseGrouper._cython_operation