您的位置:首页 > 编程语言 > Python开发

numpy基础学习笔记

2018-08-17 22:04 260 查看

numpy是什么?

按官方文档的解释来看,NumPy是使用Python进行科学计算的基础包。它的内容包括:一个强大的N维数组对象、复杂的(广播)功能、用于集成C / C ++和Fortran代码的工具、有用的线性代数,傅里叶变换和随机数功能。它提供了许多高级的数值编程工具,如:矩阵数据类型、矢量处理,以及精密的运算库;主要可以用来存储和处理大型矩阵,在数据分析、机器学习等方向用到;

numpy的基本功能

数组的构造

数组的取值与赋值

数组简单运算

广播规则(broadcasting rules)

其他一些数组处理方法

numpy的文件输入输出

数组的构造

Numpy库中的矩阵模块为ndarray对象,和python中的list并不完全一样,但很多都有类似的地方

可以使用

array
函数从常规Python列表或元组创建数组,例如:

[code]>>> import numpy as np
>>> a = np.array([1,2,3])
>>> print(a)
[1 2 3]

#可以在创建时显式指定数组的类型
>>> b = np.array([4,5,6],dtype=np.float64)
>>> print(b,b.dtype)
[4. 5. 6.] float64

#可以使用shape查看数组大小,比如
>>> c = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> print(c.shape)
(3, 3)

#可以使用astype复制数组并转换数据类型
>>> int_arr = np.array([1,2,3,4,5])
>>> print(int_arr, int_arr.dtype)
[1 2 3 4 5] int32
>>> float_arr = int_arr.astype(np.float64)
>>> print(float_arr.dtype, float_arr)
float64 [1. 2. 3. 4. 5.]
#这种数据类型的转换和普通编程语言的转换是类似的,所以要注意转换条件,失败会抛出异常

numpy提供了几个函数创建具有初始占位符内容的数组。

[code]#zeros函数创建一个元素全为0的数组
>>> a = np.zeros((2,3))
>>> a
array([[0., 0., 0.],
[0., 0., 0.]])

#ones函数创建一个元素全为1的数组
>>> b = np.ones((1,2))
>>> b
array([[1., 1.]])

#empty函数创建一个初始元素是随机的数组,其内容取决于内存的状态
>>> np.empty((3,4))
array([[6.23042070e-307, 4.67296746e-307, 1.69121096e-306,
2.22521103e-306],
[1.29061278e-306, 1.89146896e-307, 7.56571288e-307,
3.11525958e-307],
[1.24610723e-306, 1.37962320e-306, 1.29060871e-306,
5.68175493e-322]])

#arange函数和range类似
>>> np.arange(8)
array([0, 1, 2, 3, 4, 5, 6, 7])

#full函数创建一个所有元素都是指定的元素
>>> np.full((2,2), 8)
array([[8, 8],
[8, 8]])

#eye函数创建一个对角矩阵
>>> np.eye(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])

更多的函数可以看看:

array
zeros
zeros_like
ones
ones_like
empty
empty_like
arange
linspace
numpy.random.rand
, 
numpy.random.randn
fromfunction
, 
fromfile

数组的取值与赋值

可以像list一样切片,但是对切片得到的数组的修改同时也会修改到原数组,可以使用copy避免;

[code]>>> a = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]])
>>> a
array([[ 1,  2,  3,  4],
       [ 5,  6,  7,  8],
       [ 9, 10, 11, 12]])
#表示取a中的0,1行,2到3列的元素
>>> b = a[0:2,2:4]
>>> b
array([[3, 4],
       [7, 8]])
#对b的修改也会修改到a
>>> b[0,0] = 123
>>> b
array([[123,   4],
[  7,   8]])
>>> a
array([[  1,   2, 123,   4],
[  5,   6,   7,   8],
[  9,  10,  11,  12]])

#可以使用copy函数避免
>>> b = a[0:2,2:4].copy()
>>> b[0,0] = 456
>>> b
array([[456,   4],
[  7,   8]])
>>> a
array([[ 1,  2,  3,  4],
[ 5,  6,  7,  8],
[ 9, 10, 11, 12]])

但是切片的结果也要注意,比如下面两个切片的结果是不一样的

[code]>>> row_r1 = a[1,:]
>>> print(row_r1, row_r1.shape)
[5 6 7 8] (4,)
>>> row_r2 = a[1:2, :]
>>> print(row_r2, row_r2.shape)
[[5 6 7 8]] (1, 4)

还有一种取值方法

[code]>>> a = np.array([[1,2], [3, 4], [5, 6]])
>>> print(a)
[[1 2]
[3 4]
[5 6]]
>>> print(a[[0,1,2], [0,1,0]])
[1 4 5]
#这相当于取a[0,0], a[1,1], a[2,0]并生成一个新数组

#一个新的例子,但是也比较容易懂的
>>> a = np.array([[1,2,3],[4,5,6],[7,8,9],[10,11,12]])
>>> b = np.array([0,2,0,1])
>>> print(a[np.arange(4),b])
[ 1  6  7 11]

还可以是用条件判断取值

[code]>>> a = np.array([[1,2], [3, 4], [5, 6]])
>>> bool_index = (a > 2)
>>> a
array([[1, 2],
[3, 4],
[5, 6]])
>>> bool_index
array([[False, False],
[ True,  True],
[ True,  True]])
#之后再用刚才的布尔型数组作为下标就可以去除符合条件的元素啦
>>> print(a[bool_index])
[3 4 5 6]

#其实一句就可以替代
>>> print(a[a>2])
[3 4 5 6]

数组简单运算

数组也可以使用简单的加减乘除和求和、转置、对每个元素求平方根

[code]>>> x = np.array([[1,2],[3,4]], dtype=np.float64)
>>> y = np.array([[5,6],[7,8]], dtype=np.float64)

#加法
>>> x+y
array([[ 6.,  8.],
[10., 12.]])
>>> np.add(x,y)
array([[ 6.,  8.],
[10., 12.]])

#减法
>>> x-y
array([[-4., -4.],
[-4., -4.]])
>>> np.subtract(x,y)
array([[-4., -4.],
[-4., -4.]])

#乘法
>>> x*y
array([[ 5., 12.],
[21., 32.]])
>>> np.multiply(x,y)
array([[ 5., 12.],
[21., 32.]])

#除法
>>> x/y
array([[0.2       , 0.33333333],
[0.42857143, 0.5       ]])
>>> np.divide(x, y)
array([[0.2       , 0.33333333],
[0.42857143, 0.5       ]])

#求平方根
>>> np.sqrt(x)
array([[1.        , 1.41421356],
[1.73205081, 2.        ]])

#矩阵的乘法运算
>>> x.dot(y)
array([[19., 22.],
[43., 50.]])
>>> np.dot(x,y)
array([[19., 22.],
[43., 50.]])

#数组的转置
>>> x.T
array([[1., 3.],
[2., 4.]])
#一维数组的转置还是自己,二维数组转置不一样,高维数组也可以做转置,但是理解起来不是那么容易
>>> a = np.arange(16).reshape(2,2,4)
>>> print(a,a.shape)
[[[ 0  1  2  3]
[ 4  5  6  7]]

[[ 8  9 10 11]
[12 13 14 15]]] (2, 2, 4)
>>> print(a.transpose((1,0,2)))
[[[ 0  1  2  3]
[ 8  9 10 11]]

[[ 4  5  6  7]
[12 13 14 15]]]
>>> print(a.transpose((0,2,1)))
[[[ 0  4]
[ 1  5]
[ 2  6]
[ 3  7]]

[[ 8 12]
[ 9 13]
[10 14]
[11 15]]]
>>> print(a.transpose((2,1,0)))
[[[ 0  8]
[ 4 12]]

[[ 1  9]
[ 5 13]]

[[ 2 10]
[ 6 14]]

[[ 3 11]
[ 7 15]]]

#还有一些逻辑运算
#这个相当于一个三元运算符的操作
>>> x_arr = np.array([1.1, 1.2, 1.3, 1.4, 1.5])
>>> y_arr = np.array([2.1, 2.2, 2.3, 2.4, 2.5])
>>> cond = np.array([True, False, True, True, False])
>>> print(np.where(cond, x_arr, y_arr))
[1.1 2.2 1.3 1.4 2.5]
#类似的操作
>>> a = np.random.randn(4,4)
>>> a
array([[ 1.68151343, -1.97903917, -0.35478388,  1.22193956],
[-0.16067959,  0.47544782,  2.2814349 ,  0.21892784],
[ 1.3607337 , -0.50646187, -0.85782202, -0.54991086],
[ 1.00247206, -0.05980489, -0.03853833,  0.91525938]])
>>> print(np.where(a > 0, 1,-1))
[[ 1 -1 -1  1]
[-1  1  1  1]
[ 1 -1 -1 -1]
[ 1 -1 -1  1]]

科学计算最常用到的矩阵内元素的运算应该是求和吧,用sum完成

[code]>>> x= np.array([[1,2], [3,4]])
>>> np.sum(x)
10
#每列的总和
>>> print(np.sum(x, axis=0))
[4 6]
#每行的总和
>>> print(np.sum(x, axis=1))
[3 7]

#所有元素的算术平均
>>> print(np.mean(x))
2.5
#每列的算术平均
>>> print(np.mean(x, axis=0))
[2. 3.]
#每行的算术平均
>>> print(np.mean(x, axis=1))
[1.5 3.5]

更多的函数也可以看看:

all
any
apply_along_axis
argmax
argmin
argsort
average
bincount
ceil
clip
conj
corrcoef
cov
cross
cumprod
cumsum
diff
dot
floor
inner
lexsort
max
maximum
mean
median
min
minimum
, 
nonzero
outer
prod
re
round
sort
std
sum
trace
transpose
var
vdot
vectorize
where

当然还有更多的运算可以看一看
文档

广播规则(broadcasting rules)

广播描述了numpy如何在算术运算期间处理具有不同形状的数组,它提供了一种矢量化数组操作的方法,以便在C而不是Python中进行循环。它可以在不制作不必要的数据副本的情况下实现这一点,并且通常可以实现高效;然而,有些情况下广播是一个坏主意,因为它会导致内存使用效率低下,从而减慢计算速度。

numpy操作通常在逐个元素的基础上在数组对上完成。在最简单的情况下,两个数组必须具有完全相同的形状,举一些例子可能就很容易懂了:

[code]#逐个元素运算,数组的形状相同
>>> a = np.array([1.0, 2.0, 3.0])
>>> b = np.array([2.0, 2.0, 2.0])
>>> a * b
array([ 2.,  4.,  6.])

#最简单的逐个元素运算而形状不同的例子
>>> a = np.array([1.0, 2.0, 3.0])
>>> b = 2.0
>>> a * b
array([ 2.,  4.,  6.])

#下面是另一个两个形状不同的数组逐元素运算的例子,不用broadcasting和用broadcasting的方法
#不用broadcasting就是将x二维数组看做几个一维数组循环分别与v相加,但是如果数组很大就行不通了
>>> x = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
>>> v = np.array([1, 0, 1])
>>> y = np.empty_like(x)
>>> y
array([[5242959, 5111877, 4980802],
[5439553, 4325471, 5177420],
[4915267, 4587615, 4390977],
[5177428,      82,       0]])
>>> for i in range(4):
y[i,:] = x[i,:] + v
>>> print(y)
[[ 2  2  4]
[ 5  5  7]
[ 8  8 10]
[11 11 13]]

#用broadcasting可以直接相加
>>> print(x.shape, v.shape)
(4, 3) (3,)
>>> x+v
array([[ 2,  2,  4],
[ 5,  5,  7],
[ 8,  8, 10],
[11, 11, 13]])

当操作两个array时,numpy会逐个比较它们的形状,在下述情况下,两arrays会兼容和输出broadcasting结果:

  1. 相等
  2. 其中一个为1

数组不需要具有相同数量的维度。例如,如果您有一个

256x256x3
RGB值数组,并且希望将图像中的每种颜色缩放不同的值,则可以将图像乘以具有3个值的一维数组。根据广播规则排列这些数组的尾轴的大小,表明它们是兼容的:

图像  (3 d  阵列): 256  x  256  x  3
比例  (1 d  阵列):             3
结果 (3 d  阵列): 256  x  256  x  3

当比较的任何一个尺寸为1时,使用另一个尺寸。换句话说,尺寸为1的尺寸被拉伸或“复制”以匹配另一个尺寸。以下是一些例子:

A       (4 d  阵列):  8  x  1  x  6  x  1
B       (3 d  阵列):      7  x  1  x  5
结果 (4 d  阵列):  8  x  7  x  6  x  5
A       (2 d  阵列):  5  x  4
B       (1 d  阵列):      1
结果 (2 d  阵列):  5  x  4

A       (2 d  阵列):  5  x  4
B       (1 d  阵列):      4
结果 (2 d  阵列):  5  x  4

A       (3 d  阵列):  15  x  3  x  5
B       (3 d  阵列):  15  x  1  x  5
结果 (3 d  阵列):  15  x  3  x  5

A       (3 d  阵列):  15  x  3  x  5
B       (2 d  阵列):       3  x  5
结果 (3 d  阵列):  15  x  3  x  5

A       (3 d  阵列):  15  x  3  x  5
B       (2 d  阵列):       3  x  1
结果 (3 d  阵列):  15  x  3  x  5

如果不满足这些条件, 则抛出异常,指示数组具有不兼容的形状。

其他一些数组处理方法

使用reshape修改数组的形状

[code]>>> arr = np.arange(8)
>>> print(arr.shape)
(8,)
>>> arr.reshape(2,4)
array([[0, 1, 2, 3],
[4, 5, 6, 7]])
>>> arr.reshape(2,2,2)
array([[[0, 1],
[2, 3]],
[[4, 5],
[6, 7]]])
>>> print(arr.reshape(4,-1).shape)
(4, 2)
#如果在某一个维度上写上-1,numpy会帮我们自动推导出正确的维度

高维数组可以用ravel来拉平

[code]>>> a = np.arange(15).reshape(5,3)
>>> a
array([[ 0,  1,  2],
[ 3,  4,  5],
[ 6,  7,  8],
[ 9, 10, 11],
[12, 13, 14]])
>>> a.ravel()
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14])

堆叠数组

[code]>>> arr1 = np.array([[1, 2, 3], [4, 5, 6]])
>>> arr2 = np.array([[7, 8, 9], [10, 11, 12]])
#竖着堆叠
>>> np.concatenate([arr1, arr2], axis=0)
array([[ 1,  2,  3],
[ 4,  5,  6],
[ 7,  8,  9],
[10, 11, 12]])
#另一种竖着堆叠的描述  vertical
>>> np.vstack((arr1, arr2))
array([[ 1,  2,  3],
[ 4,  5,  6],
[ 7,  8,  9],
[10, 11, 12]])
#横着堆叠
>>> np.concatenate([arr1, arr2], axis=1)
array([[ 1,  2,  3,  7,  8,  9],
[ 4,  5,  6, 10, 11, 12]])
#另一种横着堆叠的描述 horizontal
>>> np.hstack((arr1, arr2))
array([[ 1,  2,  3,  7,  8,  9],
[ 4,  5,  6, 10, 11, 12]])

#辅助堆叠
#r_用于按行堆叠
>>> print(np.r_[arr1, arr2])
[[ 1  2  3]
[ 4  5  6]
[ 7  8  9]
[10 11 12]]
#c_用于按列堆叠
>>> print(np.c_[arr1, arr2])
[[ 1  2  3  7  8  9]
[ 4  5  6 10 11 12]]

使用repeat来按元素重复,用tile整体重复numpy tile

[code]#按元素重复
>>> print(arr.repeat(3))
[0 0 0 1 1 1 2 2 2]
>>> print(arr.repeat([2,3,5])) #第一个数字重复2次,第二个数字重复3次,第三个数字重复5次
[0 0 1 1 1 2 2 2 2 2]

>>> arr = np.random.rand(2,2)
>>> arr
array([[0.96493445, 0.85625599],
[0.97530159, 0.68898469]])
#在竖直方向重复
>>> print(arr.repeat(2, axis=0))
[[0.96493445 0.85625599]
[0.96493445 0.85625599]
[0.97530159 0.68898469]
[0.97530159 0.68898469]]
#在水平方向上重复
>>> print(arr.repeat(2, axis=1))
[[0.96493445 0.96493445 0.85625599 0.85625599]
[0.97530159 0.97530159 0.68898469 0.68898469]]

#按整体重复,贴瓷砖
>>> arr
array([[0.96493445, 0.85625599],
[0.97530159, 0.68898469]])
#在水平方向上整体重复两次
>>> print(np.tile(arr, 2))
[[0.96493445 0.85625599 0.96493445 0.85625599]
[0.97530159 0.68898469 0.97530159 0.68898469]]
#在水平方向上重复三次,在数值方向上重复两次
>>> print(np.tile(arr, (2,3)))
[[0.96493445 0.85625599 0.96493445 0.85625599 0.96493445 0.85625599]
[0.97530159 0.68898469 0.97530159 0.68898469 0.97530159 0.68898469]
[0.96493445 0.85625599 0.96493445 0.85625599 0.96493445 0.85625599]
[0.97530159 0.68898469 0.97530159 0.68898469 0.97530159 0.68898469]]

拆分数组

[code]>>> arr = np.random.rand(5,5)
>>> arr
array([[0.31256936, 0.52722231, 0.36990346, 0.70670806, 0.98177183],
[0.01544823, 0.20618592, 0.00296101, 0.94197733, 0.39296215],
[0.48011556, 0.27388136, 0.52788325, 0.20491882, 0.73750904],
[0.69087288, 0.1509966 , 0.77664778, 0.99087707, 0.48756347],
[0.78309695, 0.2797002 , 0.38278039, 0.1923765 , 0.49780384]])

#在竖直方向上拆分,分别在第2排和第4排的地方拆分
>>> first, second, third = np.split(arr, [1,3], axis=0)
>>> print(first, '\n\n', second, '\n\n', third)

[[0.31256936 0.52722231 0.36990346 0.70670806 0.98177183]]

[[0.01544823 0.20618592 0.00296101 0.94197733 0.39296215]
[0.48011556 0.27388136 0.52788325 0.20491882 0.73750904]]

[[0.69087288 0.1509966  0.77664778 0.99087707 0.48756347]
[0.78309695 0.2797002  0.38278039 0.1923765  0.49780384]]

#在水平方向上拆分同理,把axis改为1

numpy的文件输入输出

[code]#从文件中读取数据存在数组中,文件中的分隔符为“,”
>>>arr = np.loadtxt('array_ex.txt', delimiter=',')

#将数组存入文件
>>>arr = np.arange(50).reshape(2,5,5)
>>>np.save('some_array', arr)

#多个数组也可以同时存入文件
>>>np.savez("array_archive.npz", arr=arr, b=arr2, c=arr3)

 

以上是numpy的一些基本功能,这些都是我在七月在线上学习后再自己看了一段时间官方文档整理的,但是很多其实还是不够完善的,比如切片也有很多需要学习的地方;网上很多人写的numpy全是一些函数功能,不用的话根本记不住,这篇文章中大部分还是用的七月在线老师的例子,老师讲得也挺好的,大家可以去看一看,更重要的还是自己要去看官方文档NumPy

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: