Numpy数组使你可以将许多种数据处理任务表述为简洁的数组表达式。利用数组表达式代替循环的做法,通常被称为矢量化。一般来说,矢量化数组运算要比等价的纯Python方式快上一两个数量级(甚至更多)尤其是各种数值计算。

假如我们想要在一组值上计算函数sqrt(x^2+y^2)。np.meshgrid函数接受两个一维数组,并产生两个二维矩阵:

In [4]: points=np.arange(-5,5,0.01)

In [5]: xs,ys=np.meshgrid(points,points)  #产生1000个间隔相等的点

In [6]: ys
Out[6]:
array([[-5.  , -5.  , -5.  , ..., -5.  , -5.  , -5.  ],
       [-4.99, -4.99, -4.99, ..., -4.99, -4.99, -4.99],
       [-4.98, -4.98, -4.98, ..., -4.98, -4.98, -4.98],
       ...,
       [ 4.97,  4.97,  4.97, ...,  4.97,  4.97,  4.97],
       [ 4.98,  4.98,  4.98, ...,  4.98,  4.98,  4.98],
       [ 4.99,  4.99,  4.99, ...,  4.99,  4.99,  4.99]])

现在,对该函数的求值运算就好办了,把两个数组当做浮点数那样编写表达式即可:

In [8]: import matplotlib.pyplot as plt

In [9]: z=np.sqrt(xs ** 2 + ys ** 2)

In [10]: z
Out[10]:
array([[7.07106781, 7.06400028, 7.05693985, ..., 7.04988652, 7.05693985,
        7.06400028],
       [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,
        7.05692568],
       [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,
        7.04985815],
       ...,
       [7.04988652, 7.04279774, 7.03571603, ..., 7.0286414 , 7.03571603,
        7.04279774],
       [7.05693985, 7.04985815, 7.04278354, ..., 7.03571603, 7.04278354,
        7.04985815],
       [7.06400028, 7.05692568, 7.04985815, ..., 7.04279774, 7.04985815,

 In [20]: plt.title("Image plot of  for a grid of values")
 Out[20]: Text(0.5,1,'Image plot of  for a grid of values')
 
 In [21]: plt.imshow(z,cmap=plt.cm.gray)
 Out[21]: <matplotlib.image.AxesImage at 0x1b669f2ab38>
 
 In [22]: plt.colorbar()
 Out[22]: <matplotlib.colorbar.Colorbar at 0x1b669f77e80>
 
 In [23]: plt.title("Image plot of  for a grid of values")
 Out[23]: Text(0.5,1,'Image plot of  for a grid of values')

效果如下:

利用数组进行数据处理

函数值得图形结果如上所示,使用的是matlpltlib的imshow函数创建的,colorbar显示右侧的条形栏,title显示标题。

将条件逻辑表述为数组运算

numpy.where函数是三元表达式x if condition else y的矢量化版本。假设我们有一个布尔数组和两个值数组:

In [24]: xarr=np.array([1.1,1.2,1.3,1.4,1.5,])

In [25]: yarr=np.array([2.1,2.2,2.3,2.4,2.5])

In [26]: cond=np.array([True,False,True,True,False])

假设我们想要根据cond的值选取xarr和yarr的值:当cond种的值为True时,选取xarr的值,否则选取yarr值。那么:

In [27]: result=[(x if c else y)
    ...:            for x,y,c in zip(xarr,yarr,cond)]
    ...:

In [28]: result
Out[28]: [1.1, 2.2, 1.3, 1.4, 2.5]

这有几个问题。第一,它对大多数数组的处理速度不是很快(因为所有操作都是纯Python完成的)。第二,无法用于多维数组。若使用np.where,则该功能写的非常简洁:

In [30]: result=np.where(cond,xarr,yarr)

In [31]: result
Out[31]: array([1.1, 2.2, 1.3, 1.4, 2.5])

np.where的第二个和第三个参数不必是数组,它们都可以是标量值。在数据分析工作中,where通常用于根据另一个数组而产生一个新数组。假设有一个随机数数据组成的矩阵,你希望将所有正值替换成2,将所有负值替换成-2,。若利用np.where,则会非常简单:

In [32]: arr=randn(4,4)

In [33]: arr
Out[33]:
array([[-0.86420168,  0.46737262,  1.52870151,  0.87138646],
       [ 1.25042219, -1.26081875,  1.13138761,  0.30288777],
       [-0.17935329,  0.6377377 ,  2.94953378, -1.16395691],
       [ 0.71109135, -0.88708025,  2.25487302,  0.67770479]])

In [34]: np.where(arr>0,2,-2)
Out[34]:
array([[-2,  2,  2,  2],
       [ 2, -2,  2,  2],
       [-2,  2,  2, -2],
       [ 2, -2,  2,  2]])

In [36]: np.where(arr>0,2,arr) #只将正值设置为2
Out[36]:
array([[-0.86420168,  2.        ,  2.        ,  2.        ],
       [ 2.        , -1.26081875,  2.        ,  2.        ],
       [-0.17935329,  2.        ,  2.        , -1.16395691],
       [ 2.        , -0.88708025,  2.        ,  2.        ]])

传递给where的数组大小可以不相等,甚至可以是标量值。

假如我们有两个布尔型数组cond1和cond2。希望根据4种不同的布尔值组合实现不同的赋值操作:

 result=[]
 for i in range(n):
    ...:     if cond1[i] and cond2[i]:
    ...:         result.append(0)
    ...:     elif cond[1]:
    ...:         result.append(1)
    ...:     elif cond2[i]:
    ...:         result.append(2)
    ...:     else:
    ...:          result.append(3)

这个for循环可以改写成一个嵌套的where表达式:

np.where(cond1 & cond2,0,np.where(cond1,1,np.where(cond2,2,3)))

在这个特殊的例子里,我们还可以利用“布尔值在计算过程中可以被当做0或1处理”这个事实,所以还能将其写成这样的算术运算:

result= 1 * (cond1-cond2) +2 * (cond2 &  -cond1) + 3 * -(cond1 | cond2)

In [40]: cond1=True

In [41]: cond2=False

In [42]: result= 1 * (cond1-cond2) +2 * (cond2 &  -cond1) + 3 * -(cond1 | cond2)

In [43]: result
Out[43]: -2
例子

相关文章:

  • 2022-12-23
  • 2021-05-29
  • 2021-09-04
  • 2022-12-23
  • 2021-12-03
  • 2018-12-22
  • 2021-05-08
猜你喜欢
  • 2021-08-06
  • 2021-11-07
  • 2021-12-28
  • 2022-12-23
  • 2021-07-08
相关资源
相似解决方案