Chris@87: """ Chris@87: =================== Chris@87: Universal Functions Chris@87: =================== Chris@87: Chris@87: Ufuncs are, generally speaking, mathematical functions or operations that are Chris@87: applied element-by-element to the contents of an array. That is, the result Chris@87: in each output array element only depends on the value in the corresponding Chris@87: input array (or arrays) and on no other array elements. Numpy comes with a Chris@87: large suite of ufuncs, and scipy extends that suite substantially. The simplest Chris@87: example is the addition operator: :: Chris@87: Chris@87: >>> np.array([0,2,3,4]) + np.array([1,1,-1,2]) Chris@87: array([1, 3, 2, 6]) Chris@87: Chris@87: The unfunc module lists all the available ufuncs in numpy. Documentation on Chris@87: the specific ufuncs may be found in those modules. This documentation is Chris@87: intended to address the more general aspects of unfuncs common to most of Chris@87: them. All of the ufuncs that make use of Python operators (e.g., +, -, etc.) Chris@87: have equivalent functions defined (e.g. add() for +) Chris@87: Chris@87: Type coercion Chris@87: ============= Chris@87: Chris@87: What happens when a binary operator (e.g., +,-,\\*,/, etc) deals with arrays of Chris@87: two different types? What is the type of the result? Typically, the result is Chris@87: the higher of the two types. For example: :: Chris@87: Chris@87: float32 + float64 -> float64 Chris@87: int8 + int32 -> int32 Chris@87: int16 + float32 -> float32 Chris@87: float32 + complex64 -> complex64 Chris@87: Chris@87: There are some less obvious cases generally involving mixes of types Chris@87: (e.g. uints, ints and floats) where equal bit sizes for each are not Chris@87: capable of saving all the information in a different type of equivalent Chris@87: bit size. Some examples are int32 vs float32 or uint32 vs int32. Chris@87: Generally, the result is the higher type of larger size than both Chris@87: (if available). So: :: Chris@87: Chris@87: int32 + float32 -> float64 Chris@87: uint32 + int32 -> int64 Chris@87: Chris@87: Finally, the type coercion behavior when expressions involve Python Chris@87: scalars is different than that seen for arrays. Since Python has a Chris@87: limited number of types, combining a Python int with a dtype=np.int8 Chris@87: array does not coerce to the higher type but instead, the type of the Chris@87: array prevails. So the rules for Python scalars combined with arrays is Chris@87: that the result will be that of the array equivalent the Python scalar Chris@87: if the Python scalar is of a higher 'kind' than the array (e.g., float Chris@87: vs. int), otherwise the resultant type will be that of the array. Chris@87: For example: :: Chris@87: Chris@87: Python int + int8 -> int8 Chris@87: Python float + int8 -> float64 Chris@87: Chris@87: ufunc methods Chris@87: ============= Chris@87: Chris@87: Binary ufuncs support 4 methods. Chris@87: Chris@87: **.reduce(arr)** applies the binary operator to elements of the array in Chris@87: sequence. For example: :: Chris@87: Chris@87: >>> np.add.reduce(np.arange(10)) # adds all elements of array Chris@87: 45 Chris@87: Chris@87: For multidimensional arrays, the first dimension is reduced by default: :: Chris@87: Chris@87: >>> np.add.reduce(np.arange(10).reshape(2,5)) Chris@87: array([ 5, 7, 9, 11, 13]) Chris@87: Chris@87: The axis keyword can be used to specify different axes to reduce: :: Chris@87: Chris@87: >>> np.add.reduce(np.arange(10).reshape(2,5),axis=1) Chris@87: array([10, 35]) Chris@87: Chris@87: **.accumulate(arr)** applies the binary operator and generates an an Chris@87: equivalently shaped array that includes the accumulated amount for each Chris@87: element of the array. A couple examples: :: Chris@87: Chris@87: >>> np.add.accumulate(np.arange(10)) Chris@87: array([ 0, 1, 3, 6, 10, 15, 21, 28, 36, 45]) Chris@87: >>> np.multiply.accumulate(np.arange(1,9)) Chris@87: array([ 1, 2, 6, 24, 120, 720, 5040, 40320]) Chris@87: Chris@87: The behavior for multidimensional arrays is the same as for .reduce(), Chris@87: as is the use of the axis keyword). Chris@87: Chris@87: **.reduceat(arr,indices)** allows one to apply reduce to selected parts Chris@87: of an array. It is a difficult method to understand. See the documentation Chris@87: at: Chris@87: Chris@87: **.outer(arr1,arr2)** generates an outer operation on the two arrays arr1 and Chris@87: arr2. It will work on multidimensional arrays (the shape of the result is Chris@87: the concatenation of the two input shapes.: :: Chris@87: Chris@87: >>> np.multiply.outer(np.arange(3),np.arange(4)) Chris@87: array([[0, 0, 0, 0], Chris@87: [0, 1, 2, 3], Chris@87: [0, 2, 4, 6]]) Chris@87: Chris@87: Output arguments Chris@87: ================ Chris@87: Chris@87: All ufuncs accept an optional output array. The array must be of the expected Chris@87: output shape. Beware that if the type of the output array is of a different Chris@87: (and lower) type than the output result, the results may be silently truncated Chris@87: or otherwise corrupted in the downcast to the lower type. This usage is useful Chris@87: when one wants to avoid creating large temporary arrays and instead allows one Chris@87: to reuse the same array memory repeatedly (at the expense of not being able to Chris@87: use more convenient operator notation in expressions). Note that when the Chris@87: output argument is used, the ufunc still returns a reference to the result. Chris@87: Chris@87: >>> x = np.arange(2) Chris@87: >>> np.add(np.arange(2),np.arange(2.),x) Chris@87: array([0, 2]) Chris@87: >>> x Chris@87: array([0, 2]) Chris@87: Chris@87: and & or as ufuncs Chris@87: ================== Chris@87: Chris@87: Invariably people try to use the python 'and' and 'or' as logical operators Chris@87: (and quite understandably). But these operators do not behave as normal Chris@87: operators since Python treats these quite differently. They cannot be Chris@87: overloaded with array equivalents. Thus using 'and' or 'or' with an array Chris@87: results in an error. There are two alternatives: Chris@87: Chris@87: 1) use the ufunc functions logical_and() and logical_or(). Chris@87: 2) use the bitwise operators & and \\|. The drawback of these is that if Chris@87: the arguments to these operators are not boolean arrays, the result is Chris@87: likely incorrect. On the other hand, most usages of logical_and and Chris@87: logical_or are with boolean arrays. As long as one is careful, this is Chris@87: a convenient way to apply these operators. Chris@87: Chris@87: """ Chris@87: from __future__ import division, absolute_import, print_function