一.创建ndarray对象
我们习惯以as np的方式导入Numpy函数库。
import numpy as np
ndarray对象表示一个数组,Numpy所有的函数都关于这个对象进行操作的。
下面的代码我是使用交互式IPython运行的,所以没有使用print输出,而是直接输出对象展现的。
方法一:直接赋值法
a = np.array([1,2,3,4]) # 一维数组
b = np.array([[1,2,3],[4,5,6]]) # 二维数组
>
array([1, 2, 3, 4])
array([[1, 2, 3])
[4, 5, 6]])
某个数组的维度可以通过该对象的属性shape查看或修改:
可以手动修改维度,ndarray对象会自动调整。
a.shape
b.shape
> (4,)
> (2,3)
a.shape=(2,2)
a
b.shape=(1,-1) # -1的目的是让该对象自动调整,但是不能两个都是-1,至少有一个维度是已知。
b
> array([[1, 2],
[3, 4]])
> array([[1, 2, 3, 4, 5, 6]])
方法二修改shape属性改变的是某个数组对象本身的维度,**reshape()**方法函数可以根据参数数组,得到一个维度的数组对象。
该对象与参数数组共享数据存储空间。
类似的,直接赋值"="得到的
共享相同数据存储空间我就不赘述了,懂得都懂。
c = b.reshape(3,2) # b数组不会改变
x = b # b, c, x共享数据存储空间,没有真正意义上copy,只是浅层次的复制。
c
> array([[1, 2],
[3, 4],
[5, 6]])
方法三使用函数np.linspce()这种方法创建有规律的数组,具体见下文自动生成数组。
元素类型
数组对象的元素类型可以通过dtype得到。默认创建的数组都是整型,并且是32位,因为我的python是32位的。
c.dtype
> dtype('int32')
numpy里面有自己的numpy.int32,这里不多赘述了。
自动生成数组
np.arange() 类似于内置函数range()
np.arange(0,1,0.1)
> array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
np.linspace(0,1,10) # 等差数列
> array([0. , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
0.55555556, 0.66666667, 0.77777778, 0.88888889, 1. ]) # 默认包括终点
np.linspace(0,1,10,endpoint=False)
> array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]) # endpoint为布尔,控制终点是否包括
np.logspace(0,2,5,base=10) # 等比数列,base默认为10,10**0到10**2 分为5部分
> array([0. , 0.11111111, 0.22222222, 0.33333333, 0.44444444,
0.55555556, 0.66666667, 0.77777778, 0.88888889, 1. ])
还有几个创建指定形状和类型的数组的函数:
np.zeros() 用于创建某种形状且每个元素为0的数组或矩阵
np.ones() 用于创建某种形状且每个元素为1的数组或矩阵
np.empty() 用于创建某种形状但不定义的数组或矩阵
np.full 用于创建某种形状且每个元素为特定参数的数组或矩阵
np.zeros((2,4),int)
np.ones((2,4),float)
np.empty((2,4),float) #只开辟存储空间,不赋值
np.full((2,4),7) # 7为人为设置的
> array([[0, 0, 0, 0],
[0, 0, 0, 0]])
> array([[1., 1., 1., 1.],
[1., 1., 1., 1.]])
> array([[1., 1., 1., 1.],
[1., 1., 1., 1.]])
> array([[7, 7, 7, 7],
[7, 7, 7, 7]])
还有zeros_like()、ones_like()、empty_like()、full_like()等函数用于创建于参数数组相同性质与元素类型的数组。不一一介绍了。
存取元素(子集)
ndarray对象有很简洁实用的存取方式:
第一种与列表类似 因为我比较懒,就不多赘述了。无非是[起始点:终点:步长],正序从零开始,负数倒序是-1开始。终点不包括,也就是左闭右开区间。
*需要注意的是 ndarray数组对象与list列表不同,列表通过索引可以达到deep copy,也就是开辟新的存储空间;而ndarray通过列表类似的直接索引只能获得共享空间。
但是这里有一个疑问
a = np.linspace(1,10,10)
a
> array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.])
b = a
b
> array([ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.])
c = a[0:6]
c
> array([1., 2., 3., 4., 5., 6.])
a is b # a == b 返回True就不多说了
> True
#问题是下面
a[0:6] == c
> array([ True, True, True, True, True, True]) #返回一个布尔数组
a[0:6] is c #我想的是a这一块的内存与c共享,但是输出出来是False
> False
#然后我试了一下用list
d = [i for i in range(6)]
e = d[0:3]
e is d[0;3]
> False
e == d[0:3]
> True #可能这是由列表索引[]内部构造决定的,我也没深入研究list数据结构是什么样的,感兴趣的可以去探索一下。
Numpy给我们提供了整数列表、整数数组、布尔数组等几种高级下标存取方法。
整数列表、整数数组的下标的方法获取的数组,是deep copy,开辟新空间的。
a = np.linspace(1,12,12)
b = np.array([[1,2,3], # 二维数组
[4,5,6],
[7,8,9],
[10,11,12]])
# 采取整数列表的方法
a[[0,1,3]]
> array([1., 2., 4.])
b[[0,1,3]]
> array([[ 1, 2, 3],
[ 4, 5, 6],
[10, 11, 12]])
# 采取整数数组的方法
a[np.array([-1,2,3,3])]
> array([12., 3., 4., 4.]) # 其实可以更多样化比如下面
a[np.array([[-1,2],[3,2]]) # 创建的数组的每个元素,是根据索引数组中的元素作为下标获取a数组元素的。
#索引数组中每个元素的位置与元素本身分别决定了创建的新数组中的位置与元素#(这个元素是根据元素从被索引数组中来的)对于简而言之,自己感悟。
> array([[12., 3.],
[ 4., 3.]])
b[np.array([-1,2,3,3])]
> array([[10, 11, 12],
[ 7, 8, 9],
[10, 11, 12],
[10, 11, 12]])
c=b[np.array([[-1,2],[3,2]])]
c
> array([[[10, 11, 12], #可以看出数组维度可以突破二维
[ 7, 8, 9]],
[[10, 11, 12],
[ 7, 8, 9]]])
c.shape
> (2, 2, 3)
布尔数组比较特殊,所以单独写一下。多维数组类似于一维数组。
首先我们知道这样可以得到布尔数组
其实还有布尔列表,但是Numpy1.10之后的版本布尔列表和布尔数组是等效的。
# 仍然使用上例的a数组
a>7 # 返回相同形状的数组,满足条件返回True,反之亦然。
> array([False, False, False, False, False, False, False, True, True,
True, True, True])
# 有灵性的朋友就知道我要写什么了
a[a>7]
> array([ 8., 9., 10., 11., 12.])
a[a%2==0]
> array([ 2., 4., 6., 8., 10., 12.])
#如果作为下标的布尔数组长度小于被索引数组,超过的部分自动默认False,也就是不返回超过的部分。
剩下的多维数组有很多巧妙的用法,下次编辑,我想睡觉了。