目录
(2)np.zeros() 、ones() 、empty()
python库之numpy(下):https://blog.csdn.net/sandalphon4869/article/details/88745924
一、numpy库介绍
1.简介
NumPy(Numerical Python的简称)是Python数值计算最重要的基础包。大多数提供科学计算的包都是用NumPy的数组作为构建基础。
NumPy的部分功能如下:
- ndarray,一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组。
- 用于对整组数据进行快速运算的标准数学函数(无需编写循环)。
- 用于读写磁盘数据的工具以及用于操作内存映射文件的工具。
- 线性代数、随机数生成以及傅里叶变换功能。
- 用于集成由C、C++、Fortran等语言编写的代码的A C API。
NumPy本身并没有提供多么高级的数据分析功能,理解NumPy数组以及面向数组的计算将有助于你更加高效地使用诸如pandas之类的工具。
对于大部分数据分析应用而言,我最关注的功能主要集中在:
- 用于数据整理和清理、子集构造和过滤、转换等快速的矢量化数组运算。
- 常用的数组算法,如排序、唯一化、集合运算等。
- 高效的描述统计和数据聚合/摘要运算。
- 用于异构数据集的合并/连接运算的数据对齐和关系型数据运算。
- 将条件逻辑表述为数组表达式(而不是带有if-elif-else分支的循环)。
- 数据的分组运算(聚合、转换、函数应用等)。
NumPy之于数值计算特别重要的原因之一,是因为它可以高效处理大数组的数据。
基于NumPy的算法要比纯Python快10到100倍(甚至更快),并且使用的内存更少。
2.安装和使用
numpy库是第三方库
pip install numpy
一般记作np
import numpy as np
二、 ndarray
0.性质
arr = np.array([[1., 2., 3.], [4., 5., 6.]])
#创建ndarray
print(arr.dtype)
#float64
print(arr.ndim)
#2 二维数组
print(arr.shape)
#(2, 3) 两行三列
shape
arr1=np.array(1)
print(arr1)
#1
print(arr1.shape)
#()
arr2=np.array([1,2,3])
print(arr2)
#[1 2 3]
print(arr2.shape)
#(3,)
arr3=np.array([[1,2,3]])
print(arr3)
#[[1 2 3]]
print(arr3.shape)
#(1,3)
arr4=np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
print(arr4)
'''
[[[ 1 2 3]
[ 4 5 6]]
[[ 7 8 9]
[10 11 12]]]
'''
print(arr4.shape)
#(2,2,3)
1.创建ndarray
(1)np.array()
import numpy as np
#一维
a={1,2,3}
data1 = np.array(a)
print(data1)
#{1, 2, 3}
#没什么区别
b=[4,5,6]
data2 = np.array(b)
print(data2)
#[4 5 6]
#列表类型去掉了逗号
#多维
c=[[1,2,3],[4,5,6]]
data3 = np.array(c)
print(data3)
'''
[[1 2 3]
[4 5 6]]
'''
d={{1,2,3},{4,5,6}}
data4 = np.array(d)
print(data4)
#error
#所以array()中的数据最好写成列表类型
(2)np.zeros() 、ones() 、empty()
zeros和ones分别可以创建指定长度或形状的全0或全1数组,empty可以创建一个没有任何具体值的数组。
函数原型:
np.zeros(shape,dtype=float,order='C')
np.ones(shape,dtype=float,order='C')
np.empty(shape,dtype=float,order='C')
要用这些方法创建多维数组,只需传入一个表示形状的元组类型即可:
print(np.zeros(4))
'''
[ 0. 0. 0. 0.]
'''
print(np.zeros((3,4)))
#注意是元组类型,(3,4)是传给shape的
'''
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
'''
print(np.zeros((2,3,4)))
#从高维到低维
'''
[[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]]
'''
注意:认为np.empty会返回全0数组的想法是不安全的。只分配内存空间,不进行初始化,它返回的都是一些未初始化的垃圾值。
print(np.empty((2,3)))
'''
[[ 2.1096553 -0.09990896 1.04218815]
[-0.13491275 -0.29338706 -0.90817572]]
'''
(3)np.arange()
arange是Python内置函数range的数组版,产生从0~N-1的整数ndarray。注意:不到N
一个参数的arange()
print(np.arange(8))
#[0 1 2 3 4 5 6 7]
两个参数的arange()
arr=np.arange(1,10)
print(arr)
#[1 2 3 4 5 6 7 8 9]
三个参数的arange()
arr=np.arange(1,2,0.1)
print(arr)
#[ 1. 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9]
产生特定shape的ndarry数组
arr=np.arange(28).reshape((3,2,4))
#reshape()里传入一个元组类型
2.ndarray的数据类型
通常只需要知道你所处理的数据的大致类型是浮点数、复数、整数、布尔值、字符串,还是普通的Python对象即可
(1)指定类型:
arr1=np.array([1,2,3])
print(arr1.dtype)
#int32
#自动选择合适的类型
arr2=np.array([4,5,6],dtype=np.int64)
print(arr2.dtype)
#int64
#简洁形式
empty_uint32 = np.empty(8, dtype='u4')
(2) 转化类型:
astype()
arr = np.array([3.7, -1.2, -2.6, 0.5, 12.9, 10.1])
print(arr)
print(arr.astype(np.int32))
'''
[ 3.7 -1.2 -2.6 0.5 12.9 10.1]
[ 3 -1 -2 0 12 10]
'''
#整数被转换成了浮点数。如果将浮点数转换成整数,则小数部分将会被截取删除:
如果某字符串数组表示的全是数字,也可以用astype将其转换为数值形式。
注意:使用numpy.string_类型时,一定要小心,因为NumPy的字符串数据是大小固定的,发生截取时,不会发出警告。
arr= np.array(['1.25', '-9.6', '42.00000002344'], dtype=np.string_)
print(arr.astype(np.float))
#[ 1.25 -9.6 42.00000002]
3.ndarray数组的运算
数组与标量的算术运算会将标量值传播到各个元素:
arr = np.array([[1., 2., 3.], [4., 5., 6.]])
print(arr+1)
print(arr*2)
print(1/arr)
print(arr**2)
'''
[[ 2. 3. 4.]
[ 5. 6. 7.]]
[[ 2. 4. 6.]
[ 8. 10. 12.]]
[[ 1. 0.5 0.33333333]
[ 0.25 0.2 0.16666667]]
[[ 1. 4. 9.]
[ 16. 25. 36.]]
'''
数组与数组之间的算术运算
arr1 = np.array([[1., 2., 3.], [4., 5., 6.]])
arr2 = np.array([[2., 3., 4.], [5., 6., 7.]])
print(arr2 - arr1)
print(arr1 * arr2)
'''
[[ 1. 1. 1.]
[ 1. 1. 1.]]
[[ 2. 6. 12.]
[ 20. 30. 42.]]
'''
#arr*arr并非是矩阵乘法,而是对应元素之间的数字相乘
数组之间的比较会生成布尔值数组:
arr1 = np.array([[1., 2., 3.], [4., 5., 6.]])
arr2 = np.array([[2., 3., 4.], [5., 6., 7.]])
print(arr2 > arr1)
print(arr2 == arr1)
'''
[[ True True True]
[ True True True]]
[[False False False]
[False False False]]
'''
#>、<、==、>=、<=.注意==
4.数组的广播(不同shape的数组兼容处理)
如果两个数组的维数不相同,则元素到元素的操作是不可能的。 然而,在 NumPy 中仍然可以对形状不相似的数组进行操作,因为它拥有广播功能。 较小的数组会广播到较大数组的大小,以便使它们的形状可兼容。
如果满足以下规则,可以进行广播:
ndim较小的数组会在前面追加一个长度为 1 的维度。 输出数组的每个维度的大小是输入数组该维度大小的最大值。
- ndim较小的数组会在前面追加一个长度为 1 的维度。
- 输出数组的每个维度的大小是输入数组该维度大小的最大值。
- 如果输入在每个维度中的大小与输出大小匹配,或其值正好为 1,则可以在计算中使用该输入。
- 如果输入的某个维度大小为 1,则该维度中的第一个数据元素将用于该维度的所有计算。
如果上述规则产生有效结果,并且满足以下条件之一,那么数组被称为可广播的。
- 数组拥有相同形状。
- 数组拥有相同的维数,每个维度拥有相同长度,或者长度为 1。
- 数组拥有极少的维度,可以在其前面追加长度为 1 的维度,使上述条件成立
- 如果输入在每个维度中的大小与输出大小匹配,或其值正好为 1,则可以在计算中使用该输入。
- 如果输入的某个维度大小为 1,则该维度中的第一个数据元素将用于该维度的所有计算。
#二维与一维 a = np.array([[0.0,0.0,0.0],[10.0,10.0,10.0],[20.0,20.0,20.0],[30.0,30.0,30.0]]) b = np.array([1.0,2.0,3.0]) print ('第一个数组:') print (a) print ('\n第二个数组:') print (b) print ('\n第一个数组加第二个数组:') print (a + b) ''' 第一个数组: [[ 0. 0. 0.] [ 10. 10. 10.] [ 20. 20. 20.] [ 30. 30. 30.]] 第二个数组: [ 1. 2. 3.] 第一个数组加第二个数组: [[ 1. 2. 3.] [ 11. 12. 13.] [ 21. 22. 23.] [ 31. 32. 33.]] '''
b广播后应用规则1,数组变为[[0,1,2]],shape变为(1,3),满足条件5,第一个元素[0,1,2]用于该维度的所有计算:[0,0,0]+[0,1,2],[10,10,10]+[0,1,2]...
#error的示例 a = np.array([[0.0,0.0,0.0],[10.0,10.0,10.0],[20.0,20.0,20.0],[30.0,30.0,30.0]]) b = np.array([[1.0,2.0,3.0],[4.0,5.0,6.0]]) print ('第一个数组:') print (a) print ('\n第二个数组:') print (b) print ('\n第一个数组加第二个数组:') print (a + b)
自身既不符合条件,也不能增加维度符合条件
#一维与零维就是数组与标量的运算 a = np.array([0.0,0.0,0.0]) b = np.array(1.0) print ('第一个数组:') print (a) print ('\n第二个数组:') print (b) print ('\n第一个数组加第二个数组:') print (a + b) ''' 第一个数组: [ 0. 0. 0.] 第二个数组: 1.0 第一个数组加第二个数组: [ 1. 1. 1.] '''
增加维度,第一个元素用于所有计算
5.基本的切片与索引
(1)基本的切片和索引
注意:当你将一个标量值赋值给一个切片时(如arr[5:8]=12),该值会自动传播到整个选区。
import numpy as np
arr = np.arange(10)
print (arr)
#[0 1 2 3 4 5 6 7 8 9]
print (arr[5])
#5
print (arr[0:2])
#[0 1]
arr[0:2] = 12
print (arr)
#[12 12 2 3 4 5 6 7 8 9]
#与内置数组的区别
arr1=[0,1,2,3,4,5]
arr1[0:2]=[6]
print(arr1[0:2])
#[6,2]
print(arr1)
#[6,2,3,4,5]
#ps
print (arr)
#[0 1 2 3 4 5 6 7 8 9]
slice=arr[0:4]
print(slice)
#[0 1 2 3]
slice=666
print(arr)
#[0 1 2 3 4 5 6 7 8 9]
#ps
print (arr)
#[0 1 2 3 4 5 6 7 8 9]
slice=arr[0:4]
print(slice)
#[0 1 2 3]
slice[:]=666
print(arr)
(2)多维数组的索引
在多维数组中,如果省略了后面的索引,则返回对象会是一个维度低一点的ndarray
如:在一个二维数组中,各索引位置上的元素不再是标量而是一维数组:
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr2d[2])
#[7 8 9]
选取单个元素
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
#同C/C++的风格
print(arr2d[0][2])
#3
#自己的风格,列表
print(arr2d[0,2])
#3
axis值
(3)视图还是复制
视图:跟列表最重要的区别在于,数组切片是原始数组的视图。这意味着数据不会被复制,修改切片,变动也会体现在原始数组arr中。
由于NumPy的设计目的是处理大数据,所以你可以想象一下,假如NumPy坚持要将数据复制来复制去的话会产生何等的性能和内存问题。
import numpy as np
arr = np.arange(10)
print (arr)
#[0 1 2 3 4 5 6 7 8 9]
slice=arr[0:4]
print(slice)
#[0 1 2 3]
slice[:]=666
print(arr)
slice[0]=33
print(arr)
#[ 33 666 666 666 4 5 6 7 8 9]
复制:如果你想要得到的是ndarray切片的一份副本而非视图,就需要明确地进行复制操作,copy()方法
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
myarr=arr2d.copy()
myarr[0]=666
print(myarr)
print(arr2d)
'''
[[666 666 666]
[ 4 5 6]
[ 7 8 9]]
[[1 2 3]
[4 5 6]
[7 8 9]]
'''
6.花式切片
arr2d = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
#[:2]一个切片值,表示行切片,从0不到2行
print(arr2d[:2])
'''
[[1 2 3]
[4 5 6]]
'''
#两个切片值,[行切片,列切片]
print(arr2d[:2,1:])
'''
[[2 3]
[5 6]]
'''
#选取第二行的前两列
print(arr2d[1,:2])
#[4 5]
#选区前两行的第二列
print(arr2d[:2,1])
#[2 5]
#选取前两列
print(arr2d[:,:2])
'''
[[1 2]
[4 5]
[7 8]]
'''
7.布尔型索引
通过布尔型索引选取数组中的数据,将总是创建数据的副本,即使返回一模一样的数组也是如此。
对names和字符串"Bob"的比较运算将会产生一个布尔型数组:
names=np.array(['A','B','C','A'])
print(names=='A')
#[ True False False True]
布尔型数组可用于数组索引
注意:布尔型数组的长度必须跟被索引的轴长度一致
arr=np.empty((4,3))
print(arr)
'''
[[ 1.16337425e-311 2.81617418e-322 0.00000000e+000]
[ 0.00000000e+000 1.69119873e-306 8.60952352e-072]
[ 4.46442178e-090 1.05118281e-046 1.55029986e+184]
[ 2.14704562e+184 6.48224659e+170 4.93432906e+257]]
'''
print(arr[names=='A'])
'''
[[ 1.16337425e-311 2.81617418e-322 0.00000000e+000]
[ 2.14704562e+184 6.48224659e+170 4.93432906e+257]]
'''
#相当于arr[0]、arr[3]
布尔型数组跟切片、整数混合使用:
print(arr[names=='A',:2])
'''
[[ 1.16337425e-311 2.81617418e-322]
[ 2.14704562e+184 6.48224659e+170]]
'''
~操作符用来反转布尔条件很好用:
condition=names=='A'
print(arr[~condition])
'''
[[ 0.00000000e+000 1.69119873e-306 8.60952352e-072]
[ 4.46442178e-090 1.05118281e-046 1.55029986e+184]]
'''
组合应用多个布尔条件,使用&(和)、|(或)的布尔算术运算符
注意:组合条件要用括号括起来
注意:Python关键字and和or在布尔型数组中无效。要使用&与|。
print(arr[names=='A'|names=='B'])
#error
print(arr[(names=='A')|(names=='B')])
'''
[[ 1.16337425e-311 2.81617418e-322 0.00000000e+000]
[ 0.00000000e+000 1.69119873e-306 8.60952352e-072]
[ 2.14704562e+184 6.48224659e+170 4.93432906e+257]]
'''
通过布尔型数组设置值
arr=np.array([[-1,-2,-3],[-1,0,1],[1,2,3]])
print(arr)
arr[arr<0]=0
print(arr)
'''
[[-1 -2 -3]
[-1 0 1]
[ 1 2 3]]
[[0 0 0]
[0 0 1]
[1 2 3]]
'''
#第二行中还有'1',说明是设置单个值为0,而不是设置整行整列为0
arr=np.array([[-1,-2,-3],[-1,0,1],[1,2,3]])
print(arr)
tags=np.array([True,True,False])
arr[tags]=0
print(arr)
'''
[[-1 -2 -3]
[-1 0 1]
[ 1 2 3]]
[[0 0 0]
[0 0 0]
[1 2 3]]
'''
#设置整行整列为0
8.花式索引
花式索引跟切片不一样,它总是将数据复制到新数组中。
括号的[]的个数,一个是基本的索引,两个及以上的才是花式索引,并且比其少的括号和其一样,比其多的括号就多。
所以,我们就选用两个括号就行,[[传入的数组]]
arr=np.arange(36).reshape((3,3,4))
print(arr)
'''
[[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]
[[24 25 26 27]
[28 29 30 31]
[32 33 34 35]]]
'''
print(arr[2,0,1])
#25
#只有一个[]的数组是基本的索引
print(arr[[2,0]])
'''
[[[24 25 26 27]
[28 29 30 31]
[32 33 34 35]]
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]]
'''
#花式索引传入的数组用两个以上的[]
print(arr[[[2,0]]])
'''
[[[24 25 26 27]
[28 29 30 31]
[32 33 34 35]]
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]]
'''
print(arr[[[[[[2,0]]]]]])
'''
[[[[[[24 25 26 27]
[28 29 30 31]
[32 33 34 35]]
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]]]]]
'''
使用负数索引将会从末尾开始选取行
print(arr[[-1,-2,-3]])
'''
[[[24 25 26 27]
[28 29 30 31]
[32 33 34 35]]
[[12 13 14 15]
[16 17 18 19]
[20 21 22 23]]
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]]
'''
一次传入多个索引数组会有一点特别。它返回的是一个一维数组,其中的元素对应各个索引元组。
注意:对应,那么就要求传入的数组的shape一样。
arr = np.arange(16).reshape((4, 4))
print(arr)
'''
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
'''
print(arr[[3,1,2,0], [0, 3, 1, 2]])
#[12 7 9 2]
#就是arr[3,0],[1,3],[2,1],[0,2]
print(arr[[3,1,2,0],[2,3]])
#error,不对应
arr=np.arange(36).reshape(3,3,4)
print(arr[[2,1,0],[1,0,2]])
'''
[[28 29 30 31]
[12 13 14 15]
[ 8 9 10 11]]
'''
print(arr[[2,1,0],[1,0,2],[3,2,0]])
#[31 14 8]
花式索引加切片索引等:
就是在花式索引arr[[传入数组]]后面加其他的操作,如切片索引[: , :3]。就是arr[[ ]] [: , :3]。之间的空格是为了看起来方便,没有也行
arr = np.arange(16).reshape((4, 4))
print(arr)
'''
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]]
'''
print(arr[[2,1,0,3]] [:,:3])
'''
[[ 8 9 10]
[ 4 5 6]
[ 0 1 2]
[12 13 14]]
'''
9.数组转置
转置是重塑的一种特殊形式,它返回的是源数据的视图(不会进行任何复制操作)
转置方法有.T()、.transpose()和.swapaxes().
transpose()与T和swapaxes()的关系:在transpose()的基础上分化出T()和swapaxes()。
ps:transpose是转置的意思,pose是姿势的意思。swap是交换,axes通axis,axis是轴的意思。
transpose(1,0,2):表示将([0], [1], [2])转换为([1], [0], [2])。简单理解就是,将不同位置元素替换掉。
比如:arr[0, 0, 0],第一位和第二位转换后,仍是arr[0, 0, 0]。arr[0 , 1, 0] = 4, 转换后为 arr[1, 0, 0] = 8。同理arr[1, 0 , 0]转换为 arr[0, 1, 0]。此次类推。
arr = np.arange(16).reshape((2, 2, 4))
print(arr)
'''
[[[ 0 1 2 3]
[ 4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]]
'''
print(arr.transpose(1,0,2))
'''
[[[ 0 1 2 3]
[ 8 9 10 11]]
[[ 4 5 6 7]
[12 13 14 15]]]
'''
T转置:表示整个顺序颠倒,([0], [1], [2])转换为([2], [1], [0])。就是内容替换。
arr = np.arange(16).reshape((2, 2, 4))
print(arr.T)
'''
[[[ 0 8]
[ 4 12]]
[[ 1 9]
[ 5 13]]
[[ 2 10]
[ 6 14]]
[[ 3 11]
[ 7 15]]]
'''
print(arr.transpose(2,1,0))
'''
[[[ 0 8]
[ 4 12]]
[[ 1 9]
[ 5 13]]
[[ 2 10]
[ 6 14]]
[[ 3 11]
[ 7 15]]]
'''
T转置适用于一维、二维数组
onearr=np.array([[1,2]])
print(onearr.T)
'''
[[1]
[2]]
'''
arr = np.arange(12).reshape((3, 4))
print(arr)
'''
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
'''
print(arr.T)
'''
[[ 0 4 8]
[ 1 5 9]
[ 2 6 10]
[ 3 7 11]]
'''
swapaxes方法:表示,将其中两个轴互换
arr = np.arange(16).reshape((2, 2, 4))
print(arr.swapaxes(1,2))
'''
[[[ 0 4]
[ 1 5]
[ 2 6]
[ 3 7]]
[[ 8 12]
[ 9 13]
[10 14]
[11 15]]]
'''
print(arr.transpose(0,2,1))
'''
[[[ 0 4]
[ 1 5]
[ 2 6]
[ 3 7]]
[[ 8 12]
[ 9 13]
[10 14]
[11 15]]]
'''
参考:
https://tianchi.aliyun.com/notebook-ai/detail?spm=5176.12282042.0.0.60cb290abNYT8n&postId=5977