07 -Python入门- Lesson7 NumPy

07 Python入门 Lesson7 NumPy

本节好多内容参考了 Alien大大 的新版笔记,衷心感谢。

2.NumPy简介

NumPy 是 Numerical Python 的简称,它是 Python 中的科学计算基本软件包。NumPy 为 Python 提供了大量数学库,使我们能够高效地进行数字计算。这些课程将简要讲解 NumPy 基本概念,并介绍一些最重要的 NumPy 功能。

NumPy 手册
NumPy 用户指南
NumPy 参考资料
Scipy 讲座

3.为何要使用NumPy

因为快啊!底层用的C语言,而且做了优化,在例子中的速度是Python的100倍!

4.创建和保存 ndarray

重点提示

这一节的课后说明十分详细,重点如下:

  • NumPy 的核心是 ndarray,其中 nd 表示 n维。ndarray 是一个多维数组,其中的所有元素类型都一样。换句话说,ndarray 是一个形状可以多样,并且可以存储数字或字符串的网格。(务必注意,这个维和三维空间的维并不完全相同,将在7节之后的Plus讲解。
  • NumPy 的维数对应的是序,在数组中每一行对应一维。使用.shape观察,比如这段代码:
# We create a rank 2 ndarray that only contains integers
Y = np.array([[1,2,3],[4,5,6],[7,8,9], [10,11,12]])

# We print Y
print()
print('Y = \n', Y)
print()

# We print information about Y
print('Y has dimensions:', Y.shape)
print('Y has a total of', Y.size, 'elements')
print('Y is an object of type:', type(Y))
print('The elements in Y are of type:', Y.dtype)

>>> 输出如下:
Y =
[[ 1 2 3]
 [ 4 5 6]
 [ 7 8 9]
 [10 11 12]]

Y has dimensions: (4, 3)
Y has a total of 12 elements
Y is an object of type: class 'numpy.ndarray'
The elements in Y are of type: int64
  • NumPy 数组在创建时有固定的大小,不同于Python列表(可以动态增长)。更改ndarray的大小将创建一个新的数组并删除原始数据。
  • NumPy 数组中的元素都需要具有相同的数据类型,如果混搭,会按照最通用的元素进行转换,比如有字符也有数字时,会都存储字符;有整数也有小数时,会都存成小数(浮点型)。

创建ndarray

方法1:使用np.array从python list转换:
(注意可以通过slice的方式选中其中的元素,最后一个例子)

a = np.array([1, 2, 3]) 
# 1维数组 

print(type(a), a.shape, a[0], a[1], a[2]) 
# out: <class 'numpy.ndarray'> (3,) 1 2 3 

a[0] = 5 
# 重新赋值 print(a) 
>>> 输出如下:
[5 2 3] 

b = np.array([[1,2,3],[4,5,6]]) 
# 2维数组 print(b) 
>>> 输出如下:
out: [[1 2 3]
      [4 5 6]] 

print(b[0, 0], b[0, 1], b[1, 0]) 
>>> 输出如下:
out: 1 2 4

方法2:直接使用np.array(本是下一节内容,放在一起对比):

a = np.zeros((2,2))
# 创建2x2的全0数组
print(a)
>>> 输出如下:
[[ 0.  0.]
 [ 0.  0.]]

b = np.ones((1,2))   
# 创建1x2的全1数组
print(b)
>>> 输出如下:
[[ 1.  1.]]

c = np.full((2,2), 7) 
# 创建2x2定值为7的数组
print(c)
>>> 输出如下:
[[7 7]
 [7 7]]

d = np.eye(2)        
# 创建2x2的单位矩阵(对角元素为1)
print(d)
>>> 输出如下:
[[ 1.  0.]
 [ 0.  1.]]

d_1 = np.diag([10,20,30,50]) 
#创建一个对角线为10,20,30,50的对角矩阵
print(d_1)
>>> 输出如下:
[[10 0 0 0]
 [ 0 20 0 0]
 [ 0 0 30 0]
 [ 0 0 0 50]]

e = np.arange(15)   
#创建一个一维的0-14的数组
print(e)
>>> 输出如下:
[ 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14]

e_1 = np.arange(4,10)  
#创建一个一维的4-9的数组
print(e_1)
>>> 输出如下:
[4 5 6 7 8 9]

e_2 = np.arange(1,14,3)  
#创建一个一维的1-13且以间隔为3的数组
print(e_2)
>>> 输出如下:
[ 1 4 7 10 13]

f = np.linspace(0,10,6)  
#创建一个一维的范围在0-10,长度为6的数组
print(f)
>>> 输出如下:
[ 0.,  2.,  4.,  6.,  8., 10.]  
#各个元素的间隔相等,为(10-0)/(6-1) = 2,若不想包含末尾的10,可以添加参数endpoint = False

g = np.arange(12).reshape(3,4)  
#把arange创建的一维数组转换为3行4列的二维数组
print(g)                        
#同样方法也适用于linspace等
#注意:使用reshape转换前后的数据量应该相同,12 = 3x4
>>> 输出如下:
[[ 0,  1,  2,  3],              
 [ 4,  5,  6,  7],
 [ 8,  9, 10, 11]]              

h = np.random.random((2,2)) 
# 2x2的随机数组(矩阵),取值范围在[0.0,1.0)(包含0,不包含1)
print(e)
>>> 输出如下:
[[ 0.72776966  0.94164821]
 [ 0.04652655  0.2316599 ]]

i = np.random.randint(4,15,size = (2,2))  
#创建一个取值范围在[4,15),2行2列的随机整数矩阵
print(i)
>>> 输出如下:
[[6, 5],
 [5, 9]]

j = np.random.normal(0,0.1,size = (3,3))  
#创建一个从均值为0,标准差为0.1的正态分布中随机抽样的3x3矩阵
print(j)
>>> 输出如下:
[[-0.20783767, -0.12406401, -0.11775284],
 [ 0.02037018,  0.02898423, -0.02548213],
 [-0.0149878 ,  0.05277648,  0.08332239]]

存储和读取

# We create a rank 1 ndarray 
x = np.array([1, 2, 3, 4, 5]) 
# We save x into the current directory as 
np.save('my_array', x)
# We load the saved array from our current directory into variable y
y = np.load('my_array.npy')

# We print y
print()
print('y = ', y)
print()

# We print information about the ndarray we loaded
print('y is an object of type:', type(y))
print('The elements in y are of type:', y.dtype)

7.访问和删除 ndarray 中的元素及向其中插入元素

这里主要是提供了一些访问、更改或增加ndarray中某一元素的基础方法。

访问&更改

类似于访问python list中元素的方式,按照元素的index进行访问或更改。

访问某一元素:

print(np.arange(6)[3]) 
# 访问一维数组的某一元素,中括号内填写index
>>>
3

print(np.arange(6).reshape(3,2)[1,1]) 
# 访问二维数组的某一元素,中括号内填写[行,列]
>>>
3

print(np.arange(12).reshape(2,3,2)[0,1,1]) #访问三位数组中的某一元素,中括号内[组,行,列]
>>>
3

更改某一元素

用 = 进行赋值和替换即可。

a = np.arange(6)
a[3] = 7      
#先访问,再重新赋值
print(a)
[0 1 2 7 4 5]

删除

可使用np.delete(ndarray, elements, axis)函数进行删除操作。这里需要注意的是axis这个参数,课程中只讲到了2维数据中,axis = 0表示选择行,axis = 1表示选择列,但不能机械的认为0就表示行,1就表示列。在三维数据中,axis = 0表示组,1表示行,2表示列。这是为什么呢?提示一下,三位数组的shape中组、行和列是怎样排序的?

也就是说:axis的赋值一定要考虑数组的shape(将在后面小节扩展)。

a = np.arange(12).reshape(2,2,3)
print(a)
>>>
[[[ 0  1  2]
  [ 3  4  5]]

 [[ 6  7  8]
  [ 9 10 11]]]

print(np.delete(a,[0],axis = 0))
# 思考下,这里删除axis = 0下的第0个,会是什么结果呢?
# 再有一点需要注意的是,如果你想让原数据保留删除后的结果,需要重新替换一下才可以。
# 结果如下,是将第一个维度的,第一个元素删除了:
>>>
[[[ 6  7  8]
  [ 9 10 11]]]

a = np.arange(6).reshape(2,3)
print(a)
>>>
[[0 1 2]
 [3 4 5]]

print(np.delete(a,[0],axis = 0))
>>>
[[3 4 5]]

array([[0, 1, 2],
       [3, 4, 5]])  
       
# 但是这里a其实是没有更改的
# 需要以下重新赋值的过程才能更新到a中
a = np.delete(a,[0],axis = 0)  
#重新替换
print(a)
>>>
array([[3, 4, 5]])   
#原数据已更改

增加

往ndarray中增加元素的办法跟python list也很类似,常用的有两种:

  • 一种是添加(append),就是将新增的元素添加到ndarray的尾部
    语法为:np.append(ndarray, elements, axis) 参数和delete函数一致,用法也一致,这里不再赘述
  • 一种是插入(insert),可以让新增元素插入到指定位置
    语法为:np.insert(ndarray, index, elements, axis) 参数中就多了一个index,指示的是插入新元素的位置。
  • 这里值得注意的是,不论是append还是insert,在往多维数组中插入元素时,一定要注意对应axis上的shape要一致。再一个就是,和delete一样,如果你想要更改原数据,需要用 a = np.append(a,elements,axis) 将变化以后的内容写回到变量 a 中。

Plus.秩与轴

对于维度来讲,我们比较熟悉的是3维空间,如果定义了一个坐标原点,我们可以把三维空间中的任意一点,用 (x,y,z) 来表示。

那么对于这3个坐标我们来看下:

b = np.arange(3).reshape(3,1)
print(b,b.shape)
>>>
[[0]
 [1]
 [2]] (3, 1)

shape的输出 (3, 1) 说明数据是个2维数组,第一个维度是行数,对应了3个数据分别是x,y,z轴。第二个维度是值,分别对应的0,1,2值。但是我们也可以用以下的方式记录坐标:

a = np.arange(3)
print(a,a.shape)
>>>
[0 1 2] (3,)

这个数组就是一维的了,因为把x,y,z三个坐标的值同时写到一个列表里了。那么这么写有什么好处呢?我们假设这是一个球轨迹点,我们们可以通过增加第二个时间维度,来记录球的运动轨迹:

[[0 1 2]
 [3 4 5]
 [6 7 8]] (3, 3)

于是我们就得到了一个记录了小球运动轨迹的矩阵。其中标记了3个点(1,2,3秒的位置),分别是 [0 1 2], [3 4 5], [6 7 8]

那么再扩展,三维数据的 ndarray 是什么样的呢(和现实有些不同了,需要抽象理解):

[[[ 0  1]
  [ 2  3]
  [ 4  5]]

 [[ 6  7]
  [ 8  9]
  [10 11]]

 [[12 13]
  [14 15]
  [16 17]]] (3, 3, 2)

在 ndarray 中这个数据维度称为 轴,就是 shape 输出的结果的元素数量,定义如下:

NumPy’s main object is the homogeneous multidimensional array. It is a table of elements (usually numbers), all of the same type, indexed by a tuple of positive integers. In NumPy dimensions are called axes. The number of axes is rank.

For example, the coordinates of a point in 3D space [1, 2, 1] is an array of rank 1, because it has one axis. That axis has a length of 3. In the example pictured below, the array has rank 2 (it is 2-dimensional). The first dimension (axis) has a length of 2, the second dimension has a length of 3.

  • 也可以函数直接得出:
    • 使用 print(d.ndim) 来输出轴数。
    • 使用 print(np.linalg.matrix_rank(d)) 来输出轴数(与上面不同,还会显示下层的轴数,请自行对比)
  • 这个轴,和线性代数中的 秩 是一样的。对于 秩 的定义是:
    • 定义2.1 在矩阵A中,任取k行与k列(k≤m,k≤n),位于这些行列交叉处的k2个元素,不改变它们在矩阵中所处的位置次序而得的k阶行列式,称为矩阵A的k阶子式。
    • 定义2.1 设在矩阵A中有一个不等于0的r阶子式D,且所有r+1阶子式(如果存在的话)全等于0,那末D称为矩阵A的最高阶非零子式,数r称为矩阵A的秩,记作R(A)。
  • 扩展资源1
  • 扩展资源2

8.ndarray 切片

ndarray切片

前面学了选择ndarray中的某个元素的方法,这里我们学习选择ndarray子集的方法——切片。对于切片大家并不陌生,在list里面我们也接触过切片,一维的ndarray切片与list无异。需要注意的是,就是理解2维及多维ndarray切片。

2维矩阵切片:

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

这里可以看出,我们筛选了a矩阵中前三列的所有行,这是如何实现的呢?切片的第一个元素:表示的是选择所有行,第二个元素:-1表示的是从第0列至最后一列(不包含),所以结果如上所示。

再看一个例子,筛选的是第2-3行的所有列:

a[1:3,:] 
>>>
array([[ 4, 5, 6, 7], [ 8, 9, 10, 11]]) 

以列的形式获取最后一列数据:

a[:,3:] 
>>>
array([[ 3], [ 7], [11], [15]]) 

以一维数组的形式获取最后一列数据:

a[:,-1] 
>>>
array([ 3, 7, 11, 15]) 

上面两种方法经常会用到,前者的shape为(4,1),后者为(4,)。

ndarray筛选

选择ndarray的对角线:

所用函数为np.diag(ndarray, k=N),其中参数k的取值决定了按照哪一条对角线选择数据。

默认k = 0,取主对角线;
k = 1时,取主对角线上面1行的元素;
k = -1时,取主对角线下面1行的元素。

思考:这个函数只能选择主对角线上的元素,那如果想要获取副对角线上的元素呢?

尝试自己搜索一下关键词numpy opposite diagonal寻找答案。不建议你直接点/getting the opposite diagonal of a numpy array/

提取ndarray中的唯一值:

所用函数为np.unique(ndarray),注意unique也可以添加参数axis来控制评判唯一值的轴方向,不好理解可以看示例:

a = [[0,1,2], [3,4,5], [0,1,2]] print(np.unique(a)) 
#查看二维数组a中的唯一值 array([0, 1, 2, 3, 4, 5]) 
print(np.unique(a,axis = 0)) 
#查看a中的唯一行(也就是没有重复的行) 
array([[0, 1, 2], [3, 4, 5]]) print(np.unique(a,axis = 1)) 
#查看a中的唯一列 array([[0, 1, 2], [3, 4, 5], [0, 1, 2]]) 
print(np.unique(a[0])) 
#查看a中第一行的唯一值 
array([0, 1, 2]) 

通过布尔运算筛选:

这里在中括号中添加筛选条件,当该条件的结果为True时(即满足条件时),返回该值。

X[X > 10] #筛选数组X中大于10的数据 

这里需要注意的是,当输入多个筛选条件时,&表示与,|表示或,~表示非。

9.布尔型索引、集合运算和排序

ndarray运算

  • 集合运算
np.intersect1d(x,y) 
#取x与y的交集 np.setdiff1d(x,y) 
#取x与y的差集,返回的是在x中且没在y中的元素 np.union1d(x,y) 
#取x与y的并集 
  • 算术运算

我们可以通过+-*/np.addnp.substractnp.multiplynp.divide来对两个矩阵进行元素级的加减乘除运算,因为是元素级的运算,所以两个矩阵的shape必须要严格一致。

上面涉及到的乘法是元素对应相乘,也就是点乘,那矩阵的叉乘呢?可以了解下/numpy.matmul/函数。

ndarray排序

我们使用np.sort()ndarray.sort()来对ndarray进行排序。

  • 相同的是:二者都可以使用参数axis来决定依照哪个轴进行排序,axis = 0时按照列排序,axis = 1时按照行排序;
  • 不同的是:np.sort()不会更改原数组;ndarray.sort()会更改原数组。
  • 当 np.sort() 当做函数使用时,它不会对ndarray进行就地排序,即不更改被排序的原始 ndarray。但是,如果将 sort 当做方法,ndarray.sort() 会就地排序 ndarray,即原始数组会变成排序后的数组。

14.迷你项目:均值标准化和数据分离

这里涉及到一个概念,叫做数据标准化。数据的标准化(normalization)是将数据按比例缩放,使之落入一个小的特定区间。在某些比较和评价的指标处理中经常会用到,去除数据的单位限制,将其转化为无量纲的纯数值,便于不同单位或量级的指标能够进行比较和加权。

有很多种对数据进行标准化处理的方法,我们课程中选择的是利用数据均值和标准差进行标准化:
在这里插入图片描述

对某一列中某一值进行标准化就是将该值减去该列的平均值,然后除以该列的标准差。标准化后的序列,均值为0,标准差为1,且无量纲。标准化后的数据,没有量纲,方便计算和比较,在机器学习中的很多算法都需要将数据进行标准化。

但是基于本章的要求,我们主要是学习numpy的基本操作即可,具体的数据标准化还有算法可以之后在机器学习课程中学习。

这里需要注意的是:

  • np.random.permutation() :

np.random.permutation(N) 函数会创建一个从 0 到 N - 1的随机排列的整数集。这个整数集也是ndarray类型。

np.random.permutation(5) 
>>>
array([3, 1, 2, 4, 0]) 
  • 将数据集切分为训练集、测试集和交叉集。

这里的切分有两点隐形要求:

  1. 随机性,三个数据集中的数据必须是随机分配的;
  2. 三个数据集的合集必须为数据集。

考虑到上面学到的np.random.permutation() 函数,所以我们的思路可以是这样的:

  1. 使用permutation()函数,将数据集的行数当作N,这样就可以得到一个随机排列的行索引序列;
  2. 使用切片,将刚才的随机行索引序列,按照训练集、测试集和交叉集的比例6:2:2进行切分;
  3. 使用索引访问,获取切分后的数据,即ndarray[index]的方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值