def _broadcast_shapes(shapes, axis=None): """ Broadcast shapes, ignoring incompatibility of specified axes """ if not shapes: return shapes # input validation if axis is not None: axis = np.atleast_1d(axis) axis_int = axis.astype(int) if not np.array_equal(axis_int, axis): raise np.AxisError('`axis` must be an integer, a ' 'tuple of integers, or `None`.') axis = axis_int # First, ensure all shapes have same number of dimensions by prepending 1s. n_dims = max([len(shape) for shape in shapes]) new_shapes = np.ones((len(shapes), n_dims), dtype=int) for row, shape in zip(new_shapes, shapes): row[len(row) - len(shape):] = shape # can't use negative indices (-0:) # Remove the shape elements of the axes to be ignored, but remember them. if axis is not None: axis[axis < 0] = n_dims + axis[axis < 0] axis = np.sort(axis) if axis[-1] >= n_dims or axis[0] < 0: message = (f"`axis` is out of bounds " f"for array of dimension {n_dims}") raise np.AxisError(message) if len(np.unique(axis)) != len(axis): raise np.AxisError("`axis` must contain only distinct elements") removed_shapes = new_shapes[:, axis] new_shapes = np.delete(new_shapes, axis, axis=1) # If arrays are broadcastable, shape elements that are 1 may be replaced # with a corresponding non-1 shape element. Assuming arrays are # broadcastable, that final shape element can be found with: new_shape = np.max(new_shapes, axis=0) # except in case of an empty array: new_shape *= new_shapes.all(axis=0) # Among all arrays, there can only be one unique non-1 shape element. # Therefore, if any non-1 shape element does not match what we found # above, the arrays must not be broadcastable after all. if np.any(~((new_shapes == 1) | (new_shapes == new_shape))): raise ValueError("Array shapes are incompatible for broadcasting.") if axis is not None: # Add back the shape elements that were ignored new_axis = axis - np.arange(len(axis)) new_shapes = [ tuple(np.insert(new_shape, new_axis, removed_shape)) for removed_shape in removed_shapes ] return new_shapes else: return tuple(new_shape)
def flip(a, axis): """Reverse the order of elements in an array along the given axis. Note that ``flip`` function has been introduced since NumPy v1.12. The contents of this document is the same as the original one. Args: a (~cupy.ndarray): Input array. axis (int): Axis in array, which entries are reversed. Returns: ~cupy.ndarray: Output array. .. seealso:: :func:`numpy.flip` """ a_ndim = a.ndim if a_ndim < 1: raise numpy.AxisError('Input must be >= 1-d') axis = int(axis) if not -a_ndim <= axis < a_ndim: raise numpy.AxisError('axis must be >= %d and < %d' % (-a_ndim, a_ndim)) return _flip(a, axis)
def test_inner_error(self): orig = cupy.ndarray with pytest.raises(numpy.AxisError): with testing.AssertFunctionIsCalled('cupy.ndarray'): cupy.ndarray((2, 3), numpy.float32) raise numpy.AxisError('foo') assert cupy.ndarray is orig
def flip(a, axis=None): """Reverse the order of elements in an array along the given axis. Note that ``flip`` function has been introduced since NumPy v1.12. The contents of this document is the same as the original one. Args: a (~cupy.ndarray): Input array. axis (int or tuple of int or None): Axis or axes along which to flip over. The default, ``axis=None``, will flip over all of the axes of the input array. If axis is negative it counts from the last to the first axis. If axis is a tuple of ints, flipping is performed on all of the axes specified in the tuple. Returns: ~cupy.ndarray: Output array. .. seealso:: :func:`numpy.flip` """ a_ndim = a.ndim if a_ndim < 1: raise numpy.AxisError('Input must be >= 1-d') axes = internal._normalize_axis_indices(axis, a_ndim) return _flip(a, axes)
def __call__(self, x: np.ndarray, axis: Optional[int] = None) -> np.ndarray: if axis is not None and (axis < -x.ndim or axis >= x.ndim): raise np.AxisError(axis, ndim=x.ndim) if x.ndim == 1: return self @ x elif x.ndim > 1: if axis is None: axis = -1 if axis < 0: axis += x.ndim if x.shape[axis] != self.__shape[1]: raise ValueError( f"Dimension mismatch. Expected array with {self.__shape[1]} " f"entries along axis {axis}, but got array with shape {x.shape}." ) if axis == (x.ndim - 1): return (self @ x[..., np.newaxis])[..., 0] elif axis == (x.ndim - 2): return self @ x else: if self.__apply is None: return np.moveaxis(self @ np.moveaxis(x, axis, -2), -2, axis) return self.__apply(x, axis) else: raise ValueError("The operand must be at least one dimensional.")
def __init__(self, axis_collate, list_signals=None, flag_debug=False): """ Create a collate function using the provided axis to concatenate the input tensors Parameter --------- axis_collate (string): either 'depth', 'time', or 'freq' list_signals (list, optionnal): if we want to use the same signal several times, add the names in a list. Examples ["Acc_norm", "Acc_norm"] to use the norm of accelerometer twice ["Acc_norm", "Gyr_y", "Gyr_y", "Gyr_y", "Mag_norm"] Defaults to None (in which case each signla is used once) flag_debug (bool): whether to printdebugging messages Attributes ------- self.axis_concat (string): either 'depth', 'time', or 'freq' self.flag_debug self.list_signals """ if axis_collate in ['depth', 'time', 'freq']: self.axis_concat = axis_collate else: error_message = "unknown axis for concatenation: {}. \n Choose either 'depth', 'time', or 'freq'".format( axis_collate) raise np.AxisError(error_message) self.flag_debug = flag_debug self.list_signals = list_signals
def zscore(array, axis=None, inplace=False): "Calculates zscore for an array. A cheap copy of scipy.stats.zscore." if axis is not None and axis >= array.ndim: raise _np.AxisError('array only has {} axes'.format(array.ndim)) if inplace and array.dtype not in (_np.float, _np.float16, _np.float32, _np.float64, _np.float128): raise TypeError('Cannot convert a non-float array to zscores') mean = array.mean(axis=axis) std = array.std(axis=axis) if axis is None: if std == 0: std = 1 # prevent divide by zero else: std[std == 0.0] = 1 # prevent divide by zero shape = tuple(dim if ax != axis else 1 for ax, dim in enumerate(array.shape)) mean.shape, std.shape = shape, shape if inplace: array -= mean array /= std return None else: return (array - mean) / std
def zscore(array, axis=None, inplace=False): """Calculates zscore for an array. A cheap copy of scipy.stats.zscore. Inputs: array: Numpy array to be normalized axis: Axis to operate across [None = entrie array] inplace: Do not create new array, change input array [False] Output: If inplace is True: None else: New normalized Numpy-array""" if axis is not None and axis >= array.ndim: raise _np.AxisError('array only has {} axes'.format(array.ndim)) if inplace and not _np.issubdtype(array.dtype, _np.floating): raise TypeError('Cannot convert a non-float array to zscores') mean = array.mean(axis=axis) std = array.std(axis=axis) if axis is None: if std == 0: std = 1 # prevent divide by zero else: std[std == 0.0] = 1 # prevent divide by zero shape = tuple(dim if ax != axis else 1 for ax, dim in enumerate(array.shape)) mean.shape, std.shape = shape, shape if inplace: array -= mean array /= std return None else: return (array - mean) / std
def _get_positive_axis(ndim, axis): a = axis if a < 0: a += ndim if a < 0 or a >= ndim: raise numpy.AxisError( 'axis {} out of bounds [0, {})'.format(axis, ndim)) return a
def _axis_fmt(axis, name, ndim): if axis < 0: t = ndim + axis if t < 0: msg = "{}: axis {} is out of bounds for array of dimension {}" raise np.AxisError(msg.format(name, axis, ndim)) axis = t return axis
def rollaxis(tensor, axis, start=0): """ Roll the specified axis backwards, until it lies in a given position. This function continues to be supported for backward compatibility, but you should prefer `moveaxis`. Parameters ---------- a : Tensor Input tensor. axis : int The axis to roll backwards. The positions of the other axes do not change relative to one another. start : int, optional The axis is rolled until it lies before this position. The default, 0, results in a "complete" roll. Returns ------- res : Tensor a view of `a` is always returned. See Also -------- moveaxis : Move array axes to new positions. roll : Roll the elements of an array by a number of positions along a given axis. Examples -------- >>> import mars.tensor as mt >>> a = mt.ones((3,4,5,6)) >>> mt.rollaxis(a, 3, 1).shape (3, 6, 4, 5) >>> mt.rollaxis(a, 2).shape (5, 3, 4, 6) >>> mt.rollaxis(a, 1, 4).shape (3, 5, 6, 4) """ n = tensor.ndim axis = validate_axis(n, axis) if start < 0: start += n msg = "'%s' arg requires %d <= %s < %d, but %d was passed in" if not (0 <= start < n + 1): raise np.AxisError(msg % ('start', -n, 'start', n + 1, start)) if axis < start: # it's been removed start -= 1 if axis == start: return tensor axes = list(range(0, n)) axes.remove(axis) axes.insert(start, axis) return tensor.transpose(axes)
def distance(x: NpArrayLike, y: NpArrayLike, name: str = 'frobenius', axes: IntPair = (0, 1), **kwds: Any) -> NpArray: """Calculate matrix distances of two arrays along given axes. A matrix distance function, is a function d(x, y), which quantifies the proximity of matrices in a vector space as non-negative real numbers. If the distance is zero, then the matrices are equivalent with respect to the distance function. Distance functions are often used as error, loss or risk functions, to evaluate statistical estimations. Args: x: Any sequence that can be interpreted as a numpy ndarray of two or more dimensions. This includes nested lists, tuples, scalars and existing arrays. y: Any sequence that can be interpreted as a numpy ndarray with the same dimension, shape and datatypes as 'x'. name: Name of used matrix distance. Accepted values are: 'frobenius': :term:`Frobenius distance` (default) axes: Pair (2-tuple) of integers, that identify the array axes, along which the function is evaluated. In a two-dimensional array the axis with ID 0 is running across the rows and the axis with ID 1 is running across the columns. The default value is (0, 1), which is an evaluation with respect to the first two axis in the array. **kwds: Parameters of the given distance or class of distances. The Parameters are documented within the respective 'dist' functions. Returns: :class:`numpy.ndarray` of dimension dim(*x*) - 2. """ # Try to create numpy arrays from 'x' and 'y' with contextlib.suppress(TypeError): if not isinstance(x, np.ndarray): x = np.array(x) if not isinstance(y, np.ndarray): y = np.array(y) # Check types of 'x', 'y' and 'axes' check.has_type("argument 'x'", x, np.ndarray) check.has_type("argument 'y'", y, np.ndarray) check.has_type("argument 'axes'", axes, tuple) # Check dimensions of 'x' and 'y' if x.shape != y.shape: raise ValueError("arrays 'x' and 'y' can not be broadcasted together") # Check value of 'axes' check.has_size("argument 'axes'", axes, size=2) if axes[0] == axes[1]: raise np.AxisError("first and second axis have to be different") # Evaluate function fname = _DIST_PREFIX + name.lower() return this.call_attr(fname, x=x, y=y, axes=axes, **kwds)
def unique(ar, return_index=False, return_inverse=False, return_counts=False, axis=None, stable=True): """ Find the unique elements of an array. The only difference from the numpy version is that this version will return a stable unique array (after sorting). For more details, see numpy's unique function. References ---------- https://github.com/numpy/numpy/blob/v1.17.0/numpy/lib/arraysetops.py#L151-L294 """ ar = np.asanyarray(ar) if axis is None: ret = _unique1d(ar, return_index, return_inverse, return_counts) return _unpack_tuple(ret) # axis was specified and not None try: ar = np.swapaxes(ar, axis, 0) except np.AxisError: # this removes the "axis1" or "axis2" prefix from the error message raise np.AxisError(axis, ar.ndim) # Must reshape to a contiguous 2D array for this to work... orig_shape, orig_dtype = ar.shape, ar.dtype ar = ar.reshape(orig_shape[0], -1) ar = np.ascontiguousarray(ar) # asvoid can make sorting stable, but This method might avoid the warnings mentioned in # https://stackoverflow.com/questions/22699756/python-version-of-ismember-with-rows-and-index if stable: dtype = np.dtype((np.void, ar.dtype.itemsize * ar.shape[1])) else: dtype = [('f{i}'.format(i=i), ar.dtype) for i in range(ar.shape[1])] try: consolidated = ar.view(dtype) except TypeError: # There's no good way to do this for object arrays, etc... msg = 'The axis argument to unique is not supported for dtype {dt}' raise TypeError(msg.format(dt=ar.dtype)) def reshape_uniq(uniq): uniq = uniq.view(orig_dtype) uniq = uniq.reshape(-1, *orig_shape[1:]) uniq = np.swapaxes(uniq, 0, axis) return uniq output = _unique1d(consolidated, return_index, return_inverse, return_counts) output = (reshape_uniq(output[0]), ) + output[1:] return _unpack_tuple(output)
def _normalize_axis_tuple(axis, ndim): """Normalizes an axis argument into a tuple of non-negative integer axes. """ for ax in axis: if ax >= ndim or ax < -ndim: raise numpy.AxisError('axis {} is out of bounds for array of ' 'dimension {}'.format(ax, ndim)) return tuple((ax % ndim) for ax in axis)
def test_attr(self, args): """Validate attribute types.""" exc = np.AxisError(*args) if len(args) == 1: assert exc.axis is None assert exc.ndim is None else: axis, ndim, *_ = args assert exc.axis == axis assert exc.ndim == ndim
def test_pickling(self, args): """Test that `AxisError` can be pickled.""" exc = np.AxisError(*args) exc2 = pickle.loads(pickle.dumps(exc)) assert type(exc) is type(exc2) for name in ("axis", "ndim", "args"): attr1 = getattr(exc, name) attr2 = getattr(exc2, name) assert attr1 == attr2, name
def addKeyframe(self, coords, duration): """ Adds a new keyframe to an existing TweenParams object. :param coords: keyframe camera coordinates, list of positions that camera will move between 3 acceptable input formats: * [x,y,z] single keyframe * [[x1,y1,z1],[x2,y2,z2],...] multiple keyframes * [x1,y1,z1,x2,y2,z2,...] multiple flattened keyframes :type coords: list of float :param duration: duration to approach keyframe, 3 acceptable input formats: * d single duration (will be repeated) * [d] single duration in list (will be repeated) * [d1,d2,...] multiple durations (corresponding to number of keyframes or raises an error) :type duration: float/list of float :raises np.AxisError: if len of coords is not divisible by 3 :raises np.AxisError: if len of durations does not match len of coords """ try: ## cast to numpy array and reorder coords at the same time for ## convenient input coords = np.array(coords).reshape(-1, 3) except: raise np.AxisError( "coords should either be a 2d Nx3 numpy array or" + "a 3N list/array.") ## convert duration to a 1d numpy array, however it was passed duration = np.array(duration).reshape(-1) if duration.shape == 1: duration = np.repeat(duration, coords.shape[0]) ## ensure there is a duration per keyframe transition ## TODO: shouldn't durations be 1 less than coordss? if duration.shape[0] != coords.shape[0]: raise np.AxisError( "Mismatching coords and duration shape (%d,%d)" % (coords.shape[0], duration.shape[0])) self.coordss = np.append(self.coordss, coords, axis=0) self.durations = np.append(self.durations, duration)
def zmm(x, keep, axis=0, fn=None): ''' Zero mask out rows/cols along axis not in keep index, applying fn(<kept>) if fn is provided. ''' r = np.zeros(x.shape) if axis == 0: i = x[keep, :] r[keep, :] = fn(i).reshape(i.shape) if fn else i elif axis == 1: i = x[:, keep] r[:, keep] = fn(i).reshape(i.shape) if fn else i else: raise np.AxisError(axis) return r
def permutation(random_state, x, axis=0, chunk_size=None): r""" Randomly permute a sequence, or return a permuted range. Parameters ---------- x : int or array_like If `x` is an integer, randomly permute ``mt.arange(x)``. If `x` is an array, make a copy and shuffle the elements randomly. axis : int, optional The axis which `x` is shuffled along. Default is 0. chunk_size : : int or tuple of int or tuple of ints, optional Desired chunk size on each dimension Returns ------- out : Tensor Permuted sequence or tensor range. Examples -------- >>> import mars.tensor as mt >>> rng = mt.random.RandomState() >>> rng.permutation(10).execute() array([1, 2, 3, 7, 9, 8, 0, 6, 4, 5]) # random >>> rng.permutation([1, 4, 9, 12, 15]).execute() array([ 9, 4, 12, 1, 15]) # random >>> arr = mt.arange(9).reshape((3, 3)) >>> rng.permutation(arr).execute() array([[3, 4, 5], # random [6, 7, 8], [0, 1, 2]]) >>> rng.permutation("abc") Traceback (most recent call last): ... numpy.AxisError: x must be an integer or at least 1-dimensional """ if isinstance(x, (Integral, np.integer)): from ..datasource import arange x = arange(x, chunk_size=chunk_size) else: x = astensor(x, chunk_size=chunk_size) if x.ndim < 1: raise np.AxisError( 'x must be an integer or at least 1-dimensional') axis = validate_axis(x.ndim, axis) op = TensorPermutation(state=random_state.to_numpy(), axis=axis, dtype=x.dtype, gpu=x.op.gpu) return op(x)
def validate_axis(axis, ndim): """Validate an input to axis= keywords""" if isinstance(axis, (tuple, list)): return tuple(validate_axis(ax, ndim) for ax in axis) if not isinstance(axis, numbers.Integral): raise TypeError("Axis value must be an integer, got %s" % axis) if axis < -ndim or axis >= ndim: raise np.AxisError( "Axis %d is out of bounds for array of dimension %d" % (axis, ndim)) if axis < 0: axis += ndim return axis
def _ols(x, y): """ 系数矩阵 = (Xt * X)^(-1) * Xt * Y """ if x.ndim < 3 or y.ndim < 3: raise np.AxisError("计算ols系数的x, y维度必须都>=3") i = x.ndim xt = x.swapaxes(i - 2, i - 1) # swap last 2 axes xtx = np.matmul(xt, x) xtxi = np.linalg.inv(xtx) xty = np.matmul(xt, y) result = np.matmul(xtxi, xty) return result
def _wls(x, y, w): """ 系数矩阵 = (Xt * W * X)^(-1) * Xt * W * Y """ if x.ndim < 3 or y.ndim < 3 or w.ndim < 3: raise np.AxisError("计算wls系数的x, y, w 维度必须都>=3") xt = x.swapaxes(-2, -1) # swap last 2 axes xtw = np.matmul(xt, w) xtwx = np.matmul(xtw, x) xtwxi = np.linalg.inv(xtwx) xtwy = np.matmul(xtw, y) result = np.matmul(xtwxi, xtwy) return result
def norm(x: NpArrayLike, name: str = 'frobenius', axes: IntPair = (0, 1), **kwds: Any) -> NpArray: """Calculate magnitude of matrix with respect to given norm. Args: x: Any sequence that can be interpreted as a numpy ndarray of two or more dimensions. This includes nested lists, tuples, scalars and existing arrays. name: Name of matrix norm. Accepted values are: :pq: :term:`pq-Norm`. Remark: requires additional parameters *p* and *q* :frobenius: The default norm is the :term:`Frobenius Norm` axes: Pair (2-tuple) of integers, that identify the array axes, along which the function is evaluated. In a two-dimensional array the axis with ID 0 is running across the rows and the axis with ID 1 is running across the columns. The default value is (0, 1), which is an evaluation with respect to the first two axis in the array. **kwds: Parameters of the given norm / class of norms. The norm Parameters are documented within the respective 'norm' functions. Returns: :class:`numpy.ndarray` of dimension dim(*x*) - 2. """ # Convert numpy array like 'x' to numpy array with contextlib.suppress(TypeError): if not isinstance(x, np.ndarray): x = np.array(x) # Check types of 'x' and 'axes' check.has_type("argument 'x'", x, np.ndarray) check.has_type("argument 'axes'", axes, tuple) # Check dimension of 'x' if x.ndim < 2: raise ValueError("'x' is required to have dimension > 1") # Check value of 'axes' check.has_size("argument 'axes'", axes, size=2) if axes[0] == axes[1]: raise np.AxisError("first and second axis have to be different") # Evaluate function fname = _NORM_PREFIX + name.lower() return this.call_attr(fname, x=x, axes=axes, **kwds)
def norm(x: NpArrayLike, name: str = 'frobenius', axes: IntPair = (0, 1), **kwds: Any) -> NpArray: """Calculate magnitude of matrix with respect to given norm. Args: x: Any sequence that can be interpreted as a numpy ndarray of two or more dimensions. This includes nested lists, tuples, scalars and existing arrays. name: Name of matrix norm. Accepted values are: :pq: :term:`pq-Norm`. Remark: requires additional parameters *p* and *q* :frobenius: The default norm is the :term:`Frobenius Norm` axes: Pair (2-tuple) of integers, that identify the array axes, along which the function is evaluated. In a two-dimensional array the axis with ID 0 is running across the rows and the axis with ID 1 is running across the columns. The default value is (0, 1), which is an evaluation with respect to the first two axis in the array. **kwds: Parameters of the given norm / class of norms. The norm Parameters are documented within the respective 'norm' functions. Returns: :class:`numpy.ndarray` of dimension dim(*x*) - 2. """ # Try to cast 'x' as array x = array.cast(x) # Check type of 'axes' check.has_type("'axes'", axes, tuple) # Check dimension of 'x' if x.ndim < 2: raise ValueError("'x' is required to have dimension > 1") # Check value of 'axes' check.has_size("argument 'axes'", axes, size=2) if axes[0] == axes[1]: raise np.AxisError("first and second axis have to be different") # Get function from catalog f = catalog.pick(Norm, name=name) # Evaluate function return call.safe_call(f, x=x, axes=axes, **kwds)
def sum(self, **kwargs): # Not recommended, use the Q_num.sum function instead sum_axis = kwargs.pop('axis', None) if sum_axis: if sum_axis < 0: sum_axis -= 1 elif sum_axis > self.ndim: raise np.AxisError( 'axis %d is out of bounds for array of dimension %d' % (sum_axis, self.ndim)) else: sum_axis = 0 kwargs['axis'] = sum_axis if not self.shape: q_mat_sum = self.matrixform else: q_mat_sum = np.sum(self.matrixform, **kwargs) return q_mat_sum.view(self.qn_dtype).view(qn)
def nansum(*qn_array, **kwargs): # Same as np.nansum, calculate the sum but ignore nan numbers sum_axis = kwargs.pop('axis', None) if sum_axis: if sum_axis < 0: sum_axis -= 1 elif sum_axis > qn_array[0].ndim: raise np.AxisError( 'axis %d is out of bounds for array of dimension %d' % (sum_axis, qn_array[0].ndim)) else: sum_axis = 0 kwargs['axis'] = sum_axis qmatStack = np.squeeze(np.stack([x for x in qn_array], **kwargs)) if not qmatStack.shape: qmatSum = qmatStack.view(qn).matrixform else: qmatSum = np.nansum(qmatStack.view(qn).matrixform, **kwargs) return qmatSum.view(qn_array[0].qn_dtype).view(qn)
def filterDictionary(dict0, mask, dict1=None, key_exceptions=[]): if mask.dtype != bool: raise TypeError("arg 1: mask must have dtype bool") shape_to_match = mask.shape[0] indices = np.argwhere(mask)[:, 0] if dict1 is None: dict1 = {} for key in list(dict0.keys()): if key in key_exceptions: continue try: ## shape might fail if it's a constant so we wrap in a try if np.shape(dict0[key])[0] == shape_to_match: dict1[key] = np.take(dict0[key], indices, axis=0) ## get to the else branch by raising an exception else: raise np.AxisError("Save this array verbatim") except (np.AxisError, IndexError): dict1[key] = dict0[key] return dict1
def squeeze(self, dim): """ add a squeeze transformation in the OfflineDataList :param dim: dimension to squeeze """ if self._shape is None: raise Warning('Tried to squeeze %s, but shape is missing') if self._shape[dim] != 1: raise ValueError( 'cannot select an axis to squeeze out which has size not equal to one' ) if dim >= len(self._shape): raise np.AxisError( 'axis 4 is out of bounds for array of dimension 3' % (dim, len(self._shape))) self._transforms.append((np.squeeze, {'axis': dim})) new_shape = list(self._shape) del new_shape[dim] self._shape = tuple(new_shape)
def check_axis(X, *args, axis=0, min_size=0, **kwargs): shape = X.shape if X.ndim > 2: warn('currently, array of dimensions larger than 2 are not ' 'supported, it may lead to some issues') if shape[axis] < min_size: raise ArraySizeError(shape[axis], axis=axis, min_size=min_size) elif X.ndim <= axis: raise np.AxisError(axis, len(X.shape)) elif axis == 1 and X.ndim == 2: return func(X.T, *args, axis=0, **kwargs).T return func(X, *args, axis=axis, **kwargs)
def mean(*qn_array, **kwargs): # Same as np.mean sum_axis = kwargs.pop('axis', None) if sum_axis: if sum_axis < 0: sum_axis -= 1 elif sum_axis > qn_array[0].ndim: raise np.AxisError( 'axis %d is out of bounds for array of dimension %d' % (sum_axis, qn_array[0].ndim)) else: sum_axis = 0 kwargs['axis'] = sum_axis q_mat_stack = np.squeeze(np.stack([x for x in qn_array], **kwargs)) if not q_mat_stack.shape: q_mat_sum = q_mat_stack.view(qn).matrixform else: q_mat_sum = np.mean(q_mat_stack.view(qn).matrixform, **kwargs) return q_mat_sum.view(qn_array[0].qn_dtype).view(qn)