numpy基础操作(二)

一、数组转置和换轴

转置是一种特殊的数据重组形式,可以返回底层数据的视图而不需要复制任何内容。数组拥有transpose方法,也有特殊的T属性:

import numpy as np
arr = np.arange(15).reshape((3, 5))
arr
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
arr.T
array([[ 0,  5, 10],
       [ 1,  6, 11],
       [ 2,  7, 12],
       [ 3,  8, 13],
       [ 4,  9, 14]])
np.transpose(arr)
array([[ 0,  5, 10],
       [ 1,  6, 11],
       [ 2,  7, 12],
       [ 3,  8, 13],
       [ 4,  9, 14]])

当进行矩阵计算时,你可能会经常进行一些特定操作,例如,当计算矩阵内积会使用np.dot:

arr = np.random.randn(6, 3)
arr
array([[ 0.51674907,  0.14972018, -0.19700823],
       [-0.12662813,  0.72435835,  0.78049985],
       [ 1.7046739 , -0.00777044, -0.6994555 ],
       [ 0.76440228, -0.22231852,  0.0798294 ],
       [-0.37986392, -0.45803112, -0.93404632],
       [-0.92366358, -0.1957148 , -1.9926958 ]])
np.dot(arr.T, arr)
array([[ 4.77073923,  0.1572209 ,  0.86343221],
       [ 0.1572209 ,  0.84469385,  1.34137535],
       [ 0.86343221,  1.34137535,  5.98688207]])

对于更高维度的数组,transpose方法可以接收包含之后编号的元组,用于置换轴(拓展下思维):

arr = np.arange(16.).reshape((2, 2, 4))
arr
array([[[  0.,   1.,   2.,   3.],
        [  4.,   5.,   6.,   7.]],

       [[  8.,   9.,  10.,  11.],
        [ 12.,  13.,  14.,  15.]]])
arr.transpose((1, 0, 2))
array([[[  0.,   1.,   2.,   3.],
        [  8.,   9.,  10.,  11.]],

       [[  4.,   5.,   6.,   7.],
        [ 12.,  13.,  14.,  15.]]])

三个轴可以看成x,y,z轴,在这里,轴已经被重新排序,使得原先的y轴变成x,原先的x轴变成了y轴,z轴并没有改变。

使用.T进行转置是转轴的一个特殊案例。ndarray有一个swapaxes方法,该方法接收一对轴编号作为参数,并对轴进行调整用于重组数据:

arr
array([[[  0.,   1.,   2.,   3.],
        [  4.,   5.,   6.,   7.]],

       [[  8.,   9.,  10.,  11.],
        [ 12.,  13.,  14.,  15.]]])
arr.swapaxes(0, 1)
array([[[  0.,   1.,   2.,   3.],
        [  8.,   9.,  10.,  11.]],

       [[  4.,   5.,   6.,   7.],
        [ 12.,  13.,  14.,  15.]]])
arr.swapaxes(1, 2)
array([[[  0.,   4.],
        [  1.,   5.],
        [  2.,   6.],
        [  3.,   7.]],

       [[  8.,  12.],
        [  9.,  13.],
        [ 10.,  14.],
        [ 11.,  15.]]])

二、通用函数:快速的逐元素数组函数

通用函数,也称为ufunc,是一种在ndarray数据中进行逐元素操作的函数。某些简单函数接受一个或多个标量数值,并产生一个或多个标量结果,而通用函数就是对这些简单函数的向量化封装。

有很多ufunc是简单的逐元素转换,比如sqrt或exp函数:

arr = np.arange(10)
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.sqrt(arr)
array([ 0.        ,  1.        ,  1.41421356,  1.73205081,  2.        ,
        2.23606798,  2.44948974,  2.64575131,  2.82842712,  3.        ])
arr
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
np.exp(arr)
array([  1.00000000e+00,   2.71828183e+00,   7.38905610e+00,
         2.00855369e+01,   5.45981500e+01,   1.48413159e+02,
         4.03428793e+02,   1.09663316e+03,   2.98095799e+03,
         8.10308393e+03])

这些都是所谓的一元通用函数。还有一些通用函数,比如add或maxiumu则会接受两个数组并返回一个数组作为结果,因此称为二元通用函数:

x = np.random.randn(8)
y = np.random.randn(8)
x
array([ 0.25505513,  0.23616009, -0.83815435,  0.08750238,  1.44660586,
       -0.49278317,  0.01925976,  0.36114295])
y
array([-0.77039858,  0.5399858 , -0.10889914,  0.06090177, -0.85935897,
        0.72074658, -1.1126588 , -1.4409482 ])
np.maximum(x, y)
array([ 0.25505513,  0.5399858 , -0.10889914,  0.08750238,  1.44660586,
        0.72074658,  0.01925976,  0.36114295])

这里maximum逐个元素地将x和y中元素的最大值计算出来

也有一些通用函数返回多个数组。比如modf,是python内建函数divnod的向量化版本,它返回了一个浮点值数组的小数部分和整数部分:

arr = np.random.randn(7) * 5
arr
array([ 7.71099483, -0.88693267, -1.70675617, -1.52965618,  4.30903282,
       -2.30624022,  4.28942247])
remainder, whole_part = np.modf(arr)
remainder
array([ 0.71099483, -0.88693267, -0.70675617, -0.52965618,  0.30903282,
       -0.30624022,  0.28942247])
whole_part
array([ 7., -0., -1., -1.,  4., -2.,  4.])

通用函数接收一个可选参数out,允许对数组按位置操作:

arr
array([ 7.71099483, -0.88693267, -1.70675617, -1.52965618,  4.30903282,
       -2.30624022,  4.28942247])
np.sqrt(arr)
/home/cxd/.conda/envs/python36/lib/python3.6/site-packages/ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in sqrt
  """Entry point for launching an IPython kernel.





array([ 2.77686781,         nan,         nan,         nan,  2.075821  ,
               nan,  2.0710921 ])
arr
array([ 7.71099483, -0.88693267, -1.70675617, -1.52965618,  4.30903282,
       -2.30624022,  4.28942247])
np.sqrt(arr, arr)
/home/cxd/.conda/envs/python36/lib/python3.6/site-packages/ipykernel_launcher.py:1: RuntimeWarning: invalid value encountered in sqrt
  """Entry point for launching an IPython kernel.





array([ 2.77686781,         nan,         nan,         nan,  2.075821  ,
               nan,  2.0710921 ])
arr
array([ 2.77686781,         nan,         nan,         nan,  2.075821  ,
               nan,  2.0710921 ])

下表是常用的一元通用函数:

函数名描述
abs、fabs逐元素地计算整数、浮点数或复数的绝对值
sqrt计算每个元素的平方根(与arr ** 0.5相等)
square计算每个元素的平方(与arr ** 2 相等)
exp计算每个元素的自然指数
log、log10、log2、log1p分别对应:自然对数、对数10为底、对数2为底、log(1+x)
sign计算每个元素的符号值:1(正数)、0(0)、\1(负数)即符号函数
ceil计算每个元素的最高整数值(即大于等于给定熟知的最小整数)
floor计算每个元素的最小正数值
rint将元素保留到整数位,并保持dtype
modf分别将数组的小数部分和正数部分按数组形式返回
isnan返回数组中的元素是否是一个NaN(不是一个数值)、形式为布尔值数组
isfinite、isinf分别返回数组中的元素是否有限(非inf、非NaN)、是否无限的,形式为布尔值数组
cos、cosh、sin、sinh、tan、tanh、arccos、arccosh、arcsin、arcsinh、arctan、arctanh三角函数反三角函数
logical_not对数组的元素按位取反(与-arr效果一致)

二元通用函数:

函数名描述
np.add(ndarray, ndarray)相加
np.subtract(ndarray, ndarray)相减
np.multiply(ndarray, ndarray)相乘
np.divide(ndarray, ndarray)相除
np.floor_divide(ndarray, ndarray)地板除
np.power(ndarray, ndarray)次方
np.mod(ndarray, ndarray)取模
np.maximum(ndarray, ndarray)求最大值
np.fmax(ndarray, ndarray)求最大值(忽略NaN)
np.minimun(ndarray, ndarray)求最小值
np.fmin(ndarray, ndarray)求最小值(忽略NaN)
np.copysign(ndarray, ndarray)将参数2中的符号赋予参数1
np.greater(ndarray, ndarray)>
np.greater_equal(ndarray, ndarray)>=
np.less(ndarray, ndarray)<
np.less_equal(ndarray, ndarray)<=
np.equal(ndarray, ndarray)==
np.not_equal(ndarray, ndarray)!=
logical_and(ndarray, ndarray)&
logical_or(ndarray, ndarray)$
logical_xor(ndarray, ndarray)^
np.dot( ndarray, ndarray)计算两个ndarray的矩阵内积
np.ix_([x,y,m,n],…)生成一个索引器,用于Fancy indexing(花式索引)
arr1 = np.random.randn(2, 3)
arr2 = np.random.randn(2, 3)
print(arr1)
print(arr2)
np.mod(arr1, arr2)
[[-0.6468063   1.77175494  1.48766826]
 [-0.05857401 -0.14579956 -0.39975639]]
[[-0.85607957 -0.17774132  1.37001464]
 [-1.10156641  0.51484269  0.1242562 ]]





array([[-0.6468063 , -0.00565824,  0.11765362],
       [-0.05857401,  0.36904313,  0.09726842]])

三、使用数组进行面向数组编程

作为一个简单的示例,假设我们想要对一些网格数据来计算函数sqrt(x^2 + y^2)的值。np.meshgrid函数接收两个一位数组,并根据两个数组的所有(x, y)对生成一个二维矩阵:

points = np.arange(-5, 5, 0.01)
xs, ys = np.meshgrid(points, points)
ys
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]])
xs
array([[-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       ..., 
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99],
       [-5.  , -4.99, -4.98, ...,  4.97,  4.98,  4.99]])
z = np.sqrt(xs ** 2 + ys ** 2)
z
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,  7.05692568]])

我们使用matplotlib来生成这个二维数组的可视化:

import matplotlib.pyplot as plt
plt.imshow(z, cmap=plt.cm.gray);plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x7fbbfe751b00>
plt.title('image plot of $\sqrt{x^2 + y^2}$ for a grid of values')
Text(0.5, 1.0, 'image plot of $\\sqrt{x^2 + y^2}$ for a grid of values')
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jPWTHhic-1579836299553)(output_59_0.png)]

四、将条件逻辑作为数组操作

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

xarr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
yarr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
cond = np.array([True, False, True, True, False])
result = [(x if c else y) for x, y, c in zip(xarr, yarr, cond)]
result
[1.1000000000000001, 2.2000000000000002, 1.3, 1.3999999999999999, 2.5]

这样会产生很多问题。首先,如果数组很大的话,速度会很慢。其次,当数组是多维时,就无法奏效了。而使用np.where时,就可以非常简单地完成:

result = np.where(cond, xarr, yarr)
result
array([ 1.1,  2.2,  1.3,  1.4,  2.5])

np.where第二个和第三个参数并不需要是数组,它们可以是标量:

arr = np.random.randn(4, 4)
arr
array([[ 0.0462423 ,  1.39587524,  0.7302261 ,  0.21081567],
       [-0.18468851,  0.94854582,  0.70048342,  1.17255176],
       [ 0.72976014,  0.16594239, -1.32911281,  1.61769938],
       [ 0.98796864, -0.76306741,  0.79224391, -1.05967434]])
arr > 0
array([[ True,  True,  True,  True],
       [False,  True,  True,  True],
       [ True,  True, False,  True],
       [ True, False,  True, False]], dtype=bool)
np.where(arr > 0, 2, -2)
array([[ 2,  2,  2,  2],
       [-2,  2,  2,  2],
       [ 2,  2, -2,  2],
       [ 2, -2,  2, -2]])
np.where(arr > 0, 2, arr)
array([[ 2.        ,  2.        ,  2.        ,  2.        ],
       [-0.18468851,  2.        ,  2.        ,  2.        ],
       [ 2.        ,  2.        , -1.32911281,  2.        ],
       [ 2.        , -0.76306741,  2.        , -1.05967434]])
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值