6.17学习:

np.array()

  Numpy中核心的就是array,numpy先天就把数组看作多维矩阵,进而进行矩阵的操作。

import numpy
numpy.__version__

  另外,因为要很经常的使用numpy,所以常常使用以下代码采用np来代替numpy。

import numpy as np

  python中list也可以表达数组,但是List没有对元素做类型的限制,一个List里可以有很多种数据类型,虽然灵活,但这导致List效率低下。

L = [i for i in range(10)]
L

  输出:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]。

L[5] = 100
L

  输出:[0, 1, 2, 3, 4, 100, 6, 7, 8, 9]。

L[5] = "Machine Learning"
L

  输出:[0, 1, 2, 3, 4, ‘Machine Learning’, 6, 7, 8, 9]。

  当然,python中也有限定了只能存储一种数据类型的数组,来自array包的.array方法。

import array
arr = array.array('i',[i for i in range(10)])
# array中有.array方法,
# 第一个参数表示数据类型,i表示int型;
# 第二个参数可以放一个list来表示array中相对应的元素,这里用生成式的方式来描述了一个0-9的list
arr

  输出:array(‘i’, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])。

  Array中对元素的操作和List类似。

arr[5]
arr[5] = 100
arr

  输出:5、array(‘i’, [0, 1, 2, 3, 4, 100, 6, 7, 8, 9])。

arr[5] = 'Machine Learning'

  输出:TypeError: an integer is required (got type str),因为array中限定只能存储一种类型,这样虽然不灵活但效率高。

  Array只是把存储在其中的数据当成一个数组来看,或者当成二维数组,而不是向量或矩阵,相对应的也就没有配备矩阵相关的运算,不适合机器学习。

  所以我们使用numpy中的array来表示矩阵。

nparr = np.array([i for i in range(10)])

  输出:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])。

nparr[5]
nparr[5] = 100
nparr  输出:5、array([ 0, 1, 2, 3, 4, 100, 6, 7, 8, 9])。
nparr[5] = 'Machine Learning'
nparr

  输出:ValueError: invalid literal for int() with base 10: ‘Machine Learning’。由此可见,和List和array中的操作方法基本类似,但是numpy也封装了一些特殊的对array操作的方法。

# 查看numpy中array存储的数据类型
nparr.dtype
nparr[5] = 5.20
nparr

  没有报错,这是因为numpy在这里给5.20做了一次隐式类型转换。

nparr2 = np.array([1,2,3.0])
nparr2.dtype

  Numpy有隐形类型转换机制,输出:dtype(‘float64’)。

np.zeros()、np.ones()、np.full()

  Numpy预置了很多创建数组的方法。

np.zeros(10)
# 创建一个全为0的矩阵(向量)

  输出:array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])。

np.zeros(10).dtype
# 如果不指定dtype,zeros默认为flout型,注意到每一位都是0.
# np.zeros(10,dtype=int)

  输出:dtype(‘float64’)。

np.zeros((3,5))
# np,zeros(shape=(3,5),dtype=int)

  输出:array([[0., 0., 0., 0., 0.],
      [0., 0., 0., 0., 0.],
      [0., 0., 0., 0., 0.]])

np.ones(10)

  输出:array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])。

np.ones((3,5))

  输出:array([[1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.],
       [1., 1., 1., 1., 1.]])。

np.full((3,5),666)
# np.full(shape=(3,5),fill_value=666)
# full方法不指定,666的数据类型默认为整型

  输出:array([[666, 666, 666, 666, 666],
       [666, 666, 666, 666, 666],
       [666, 666, 666, 666, 666]])。

np.full(fill_value=666.0,shape=(3,5))
# 写变量名的话就可以不用按照顺序了

np.arange()

# python中有range方法
[i for i in range(0,20,2)]
# 0是起点,20是终点,步长为2,前闭后开
# python中range不能传入浮点数

  输出:[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]。

# numpy中有arange方法
np.arange(0,20,2)
# numpy中arange可以传入浮点数

  输出:array([ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18])。

np.arange(0,10)
# 不填写步长,默认为1

  输出:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])。

np.arange(10)
# 不填写起点,默认起点为0

np.linspace()

np.linspace(0,20,10)
# 在0-20的区间里等长的截出10个点,这10个点包括0和20

  输出:array([ 0. , 2.22222222, 4.44444444, 6.66666667, 8.88888889,
       11.11111111, 13.33333333, 15.55555556, 17.77777778, 20. ])。

np.linspace(0,20,11)

  输出:array([ 0., 2., 4., 6., 8., 10., 12., 14., 16., 18., 20.])。

np.random()

np.random.randint(0,10)
# 生成0-10之间的随机数
np.random.randint(0,10,10)
# 生成10个0-10之间的随机数,永远取不到10

  输出:array([5, 9, 5, 6, 5, 4, 0, 8, 0, 8])。

np.random.randint(4,8,size=10)

  输出:array([6, 4, 7, 5, 7, 5, 6, 4, 5, 4])。

np.random.randint(4,8,size=(3,5))

  输出:array([[4, 4, 6, 4, 6],
      [4, 7, 5, 6, 7],
       [6, 6, 7, 7, 6]])

  计算机中的随机数都是伪随机,可以指定随机数种子,来让每一次生成的随机数都一样,方便我们调试。

np.random.seed(666)
np.random.randint(4,8,size=(3,5))
np.random.randint(4,8,size=(3,5))

  可见,前两次生成的随机数是一样的。

np.random.random()
# 生成的随机数默认都是浮点数,但是每一个浮点数都在0-1之间
np.random.random(10)
# 生成包含10个数的随机数,每一个数都在0-1之间
np.random.random((3,5))

  输出:array([[0.46284169, 0.23340091, 0.76706421, 0.81995656, 0.39747625],
      [0.31644109, 0.15551206, 0.73460987, 0.73159555, 0.8578588 ],
       [0.76741234, 0.95323137, 0.29097383, 0.84778197, 0.3497619 ]])

  这时生成的随机数是在0-1之间随机分布的随机数,如果想生成符合正态分布的随机数,采用numpy.random.normal()方法。

np.random.normal()
# 生成一个符合均值为0,方差为1的正态分布的随机数
np.random.normal(10,100)
# 生成一个符合均值为10,方差为100的正态分布的随机数
np.random.normal(0,1,(3,5))
# 生成一个3*5元组的符合标准正态分布的随机数

  输出:array([[-0.21326813, 0.44076692, 0.69339587, 0.03820097, -0.18592982],
       [-0.35371521, -1.95332994, -0.34376486, -1.47693162, -0.70022971],
       [ 0.77605168, 1.18063598, 0.06102404, 1.07856138, -0.79783572]])

np.array()的基本操作

  前置代码。

import numpy as np
x = np.arange(10)
x

  输出:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])。

X = np.arange(15).reshape(3,5)
X

  输出:。array([[ 0, 1, 2, 3, 4],
       [ 5, 6, 7, 8, 9],
        [10, 11, 12, 13, 14]])

基本属性

x.ndim  # 输出 1
X.ndim # 输出 2
# 查看是几维数组
x.shape  # 输出 (10,)
X.shape # 输出 (3, 5)
# shape返回一个元组,每一位表示一个维度
x.size  # 输出 10
X.size # 输出 15
# 返回数组中元素的个数

np.array的数据访问

x[0]  # 输出 0 
# 采用此法访问数组元素
x[-1]  # 输出 9
# 这样表示倒着走
X[(0,0)]  # 输出 0
# numpy中访问数组中特定位置的元素
# 也可以写 X[0,0]
x[0:5]
# 使用切片访问

  输出:array([0, 1, 2, 3, 4])。

x[:5]
# 从头开始访问到第5位
x[5:]
# 从第5位开始访问到结尾

  输出:array([5, 6, 7, 8, 9])。

x[::2]
# 从头访问到尾,步长为2

  输出:array([0, 2, 4, 6, 8])。

x[::-1]
# 倒着访问

  输出:array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])。

X[:2,:3]  # 注意是大X
# 访问前2行,前3列

  输出:array([[0, 1, 2],
      [5, 6, 7]])

X[:2][:3]
# 先截取前2列,在此基础上,截取前3列(无意义的错误写法)

  输出:array([[0, 1, 2, 3, 4],
      [5, 6, 7, 8, 9]])

X[:2,::2]
# 访问前2行,但每一行都按照步长为2访问

  输出:array([[0, 2, 4],
      [5, 7, 9]])

X[::-1,::-1]
# 倒着访问

  输出:array([[14, 13, 12, 11, 10],
      [ 9, 8, 7, 6, 5],
      [ 4, 3, 2, 1, 0]])

X[0]
# 只取第一行(X[][],第一个元素表示行)
X[0,:]
# 两者等价

  输出:array([0, 1, 2, 3, 4])。

subX = X[:2,:3]
subX

  输出:array([[0, 1, 2],
      [5, 6, 7]])

subX[0,0] = 100
subX

  输出:array([[100, 1, 2],
      [ 5, 6, 7]])

X

  输出:array([[100, 1, 2, 3, 4],
       [ 5, 6, 7, 8, 9],
       [ 10, 11, 12, 13, 14]])

  在python中,对原矩阵切片的话是创建了一个新的矩阵,不会影响。但在numpy中,会影响被切片的矩阵。

X[0,0] = 0
X  
subX

  输出:X和subX的第一位都别修改了。

  如果想不相连,可以调用numpy中的copy()方法。

subX = X[:2,:3].copy()
subX

  输出:array([[0, 1, 2],
      [5, 6, 7]])

subX[0,0] = 100
subX

  输出:array([[100, 1, 2],
      [ 5, 6, 7]])

X  # X此时不受影响

  输出:array([[ 0, 1, 2, 3, 4],
       [ 5, 6, 7, 8, 9],
       [10, 11, 12, 13, 14]])

np.reshape()

x.shape  # 输出 (10,)
x.ndim # 输出 1
x.reshape(2,5)

  输出:array([[0, 1, 2, 3, 4],
      [5, 6, 7, 8, 9]])

x
# 调用reshape方法没有改名小x自身

  输出:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])。

A = x.reshape(2,5)
A

  输出:array([[0, 1, 2, 3, 4],
      [5, 6, 7, 8, 9]])。

  此时x是一维向量,注意向量永远是一列,和二维矩阵的维度是不同的(尽管1*10的二维矩阵看起来和10个元素的向量一样),可以用reshape方法把向量变成二维矩阵。

B = x.reshape(1,10)
B

  输出:array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])。

B.ndim  # 输出 2
B.shape  # 输出 (1,10)
x.shape # 输出 (10,)

  reshape还可以很智能的调配每一行的元素个数。

x.reshape(10,-1)
# 把x变成10行,每一行自动均匀填充

  输出:array([[0],
       [1],
       [2],
       [3],
       [4],
       [5],
       [6],
       [7],
       [8],
       [9]])

x.reshape(-1,2)
# 把x变成2列,每一列自动填充
# 不能整除的不能写

  输出:array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7],
       [8, 9]])

合并操作

x = np.array([1,2,3])
y = np.array([3,2,1])
np.concatenate([x,y])
# 合并两个数组

  输出:array([1, 2, 3, 3, 2, 1])。

z = np.array([666,666,666])
np.concatenate([x,y,z])
# concatenate不局限于两个数组的合并

  输出:array([ 1, 2, 3, 3, 2, 1, 666, 666, 666])。

A = np.array([[1,2,3],[4,5,6]])
np.concatenate([A,A])

  输出:array([[1, 2, 3],
       [4, 5, 6],
       [1, 2, 3],
       [4, 5, 6]])。

np.concatenate([A,A],axis=1)
# 之前沿着纵向拼接矩阵,axis默认是0,当指定为1时,沿着横向拼接

  输出:array([[1, 2, 3, 1, 2, 3],
      [4, 5, 6, 4, 5, 6]])。

np.concatenate([A,z])
# 维数不一样不能拼接

  输出:ValueError: all the input arrays must have same number of dimensions, but the array at index 0 has 2 dimension(s) and the array at index 1 has 1 dimension(s)。

np.concatenate([A,z.reshape(1,-1)])
# 利用reshape将z转换成1行3列(自动分配)的二维矩阵即可拼接

  输出:array([[ 1, 2, 3],
       [ 4, 5, 6],
       [666, 666, 666]])。

A
# 拼接结果是一个新的矩阵,此时A没有被改变

  输出:array([[1, 2, 3],
      [4, 5, 6]])。

A2 = np.concatenate([A,z.reshape(1,-1)])
# 最好令一个变量来保存
np.vstack([A,z])
# vstack更加智能,可以自动拼接【垂直方向】,横着摞

  输出:array([[ 1, 2, 3],
       [ 4, 5, 6],
       [666, 666, 666]])。

B = np.full((2,2),100)
B
np.hstack([A,B])
# 采用hstack自动拼接【水平方向】

  输出:array([[ 1, 2, 3, 100, 100],
       [ 4, 5, 6, 100, 100]])。

np.hstack([A,z])
# 当维度非法的时候,不论vstack还是hstack都会报错

  输出:ValueError。

分割操作

x = np.arange(10)
x # 输出 array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x1, x2, x3 = np.split(x,[3,7])
# splict(,[])函数将数组x按照第3位、第7位分割成三段,用x1、x2、x3接收
x1  # 输出 array([0, 1, 2])
x2 # 输出 array([3, 4, 5, 6])
x3 # 输出 array([7, 8, 9])
np.split(x,[5])
# 按照第5位切割成两段
A = np.arange(16).reshape((4,4))
A

  输出:array([[ 0, 1, 2, 3],
       [ 4, 5, 6, 7],
       [ 8, 9, 10, 11],
       [12, 13, 14, 15]])。

A1, A2 = np.split(A,[2])
# 在默认情况下【横向分割】
A1

  输出:array([[0, 1, 2, 3],
       [4, 5, 6, 7]])。

A2

  输出:array([[ 8, 9, 10, 11],
       [12, 13, 14, 15]])。

A1, A2 = np.split(A,[2],axis = 1)
# 这样就可以【纵向分割】
upper, lower = np.vsplit(A,[2])
# split和stack同理
upper

  输出:array([[0, 1, 2, 3],
       [4, 5, 6, 7]])。

left, right = np.hsplit(A,[2])
left

  输出:array([[ 0, 1],
       [ 4, 5],
       [ 8, 9],
       [12, 13]])

  数据的分割有什么意义呢?可以吧特征和label分开。

data = np.arange(16).reshape((4,4))
x, y = np.hsplit(data,[-1])
x

  输出:array([[ 0, 1, 2],
      [ 4, 5, 6],
       [ 8, 9, 10],
       [12, 13, 14]])。

y

  输出:array([[ 3],
       [ 7],
       [11],
       [15]])。

  有时我们希望抽出的label是列向量而不是二维数组,这个时候用切片的办法。

y[:,0]
# y[行,列] 行从头到尾都要,列只要第1列

  输出:array([ 3, 7, 11, 15])。