一、通用函数:快速的元素级数组函数
通用函数(即ufunc)是一种对ndarray中的数据执行元素级运算的函数。(将只对一个元素的操作直接用在多维数组对象身上)
一元通用函数:许多ufunc都是简单的元素级变体,如sqrt和exp:
```python
In [137]: arr = np.arange(10)
In [138]: arr
Out[138]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [139]: np.sqrt(arr)
Out[139]:
array([ 0. , 1. , 1.4142, 1.7321, 2. , 2.2361, 2.4495,
2.6458, 2.8284, 3. ])
In [140]: np.exp(arr)
Out[140]:
array([ 1. , 2.7183, 7.3891, 20.0855, 54.5982,
148.4132, 403.4288, 1096.6332, 2980.958 , 8103.0839])
```
二元通用函数:另外一些通用函数(例如maximum)会接受2个数组(因此也叫二元(binary)ufunc),并返回一个结果数组:
```python
In [141]: x = np.random.randn(8)
In [142]: y = np.random.randn(8)
In [143]: x
Out[143]:
array([-0.0119, 1.0048, 1.3272, -0.9193, -1.5491, 0.0222, 0.7584,
-0.6605])
In [144]: y
Out[144]:
array([ 0.8626, -0.01 , 0.05 , 0.6702, 0.853 , -0.9559, -0.0235,
-2.3042])
In [145]: np.maximum(x, y)
Out[145]:
array([ 0.8626, 1.0048, 1.3272, 0.6702, 0.853 , 0.0222, 0.7584,
-0.6605])
```
ufunc函数的广播机制
广播(broadcasting)是指不同形状的数组之间执行算术运算的方式。广播机制需要遵循4个原则:
①所有输入的数组都向其中shape最长的数组看齐,shape中不足的部分通过在前面加1补齐;
②输出数组的shape是输入数组shape各个轴上的最大值;
③如果输入数组的某个轴 和 输出数组的对应轴 的长度相同或者其长度为1时,这个数组可以用来计算,否则会出错。
④当输入数组的某个轴的长度为1时,沿着此轴运算都用此轴上的第一组值
In[32]:
arr1 = np.array([[0,0,0],[1,1,1],[2,2,2]])
arr2 = np.array([1,2,3])
print('arr1:\n,arr1')
print('arr2:\n,arr2')
print('arr1+arr2:\n,arr1+arr2')
Out[32]:
arr1:
[[0 0 0]
[1 1 1]
[2 2 2]]
arr2:
[1 2 3]
arr1+arr2:
[[1 2 3]
[2 3 4]
[3 4 5]]
二、矢量化
Numpy数组可以将许多数据处理任务用简洁的数组表达式表示(避免循环)。
这种用数组表达式代替循环的做法,通常被叫做矢量化。矢量化数组运算比原始的Python速度快上一两个数量级,尤其在各种数值计算中。后面将介绍广播:一种针对矢量化的强大手段。
三、条件逻辑运算
条件循环:numpy.where函数是三元表达式x if condition else y的矢量化版本。
使用原始Python方法:
```python
In [165]: xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
In [166]: yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
In [167]: cond = np.array([True, False, True, True, False])
```python
In [168]: result = [(x if c else y)
.....: for x, y, c in zip(xarr, yarr, cond)]
In [169]: result
Out[169]: [1.1000000000000001, 2.2000000000000002, 1.3, 1.3999999999999999, 2.5]
```
使用np.where,则可以将该功能写得非常简洁:
```python
In [170]: result = np.where(cond, xarr, yarr)
In [171]: result
Out[171]: array([ 1.1, 2.2, 1.3, 1.4, 2.5])
```
np.where的第二个和第三个参数不必是数组,它们都可以是标量值。在数据分析工作中,where通常用于根据另一个数组而产生一个新的数组。
例如,假设有一个由随机数据组成的矩阵,你希望将所有正值替换为2,将所有负值替换为-2。若利用np.where,则会非常简单:
In [172]: arr = np.random.randn(4, 4)
In [173]: arr
Out[173]:
array([[-0.5031, -0.6223, -0.9212, -0.7262],
[ 0.2229, 0.0513, -1.1577, 0.8167],
[ 0.4336, 1.0107, 1.8249, -0.9975],
[ 0.8506, -0.1316, 0.9124, 0.1882]])
In [174]: arr > 0
Out[174]:
array([[False, False, False, False],
[ True, True, False, True],
[ True, True, True, False],
[ True, False, True, True]], dtype=bool)
In [175]: np.where(arr > 0, 2, -2) #传递给where的数组大小可以不相等,甚至可以是标量值。
Out[175]:
array([[-2, -2, -2, -2],
[ 2, 2, -2, 2],
[ 2, 2, 2, -2],
[ 2, -2, 2, 2]])
四、数学和统计方法
在多维数组中,累加函数(如cumsum)返回的是同样大小的数组,但是会根据每个低维的切片沿着标记轴计算部分聚类:
In [186]: arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
In [187]: arr
Out[187]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [188]: arr.cumsum(axis=0) #按行累加
Out[188]:
array([[ 0, 1, 2],
[ 3, 5, 7],
[ 9, 12, 15]])
In [189]: arr.cumprod(axis=1) #按列累乘
Out[189]:
array([[ 0, 0, 0],
[ 3, 12, 60],
[ 6, 42, 336]])
```