大家好呀,今天我们学习 Python 的一个科学计算库 NumPy,它是用 Python 做数据分析所必不可少的一个第三方库。
本节课的主要内容有:
- NumPy认知
(1)NumPy介绍
(2)为什么要学NumPy
(3)NumPy的优势
(4)ndarray与Python原生list运算效率对比 - NumPy 的Ndarray 对象
(1)创建一维数组
(2)创建二维数组
(3)常用属性
(4)调整数组的形状
(5) 将数组转成list
(6)NumPy的数据类型
(7)数组的索引和切片
(8)数组中的数值修改 - 数组中的轴
- 数组的计算
(1)数组和数的计算
(2)数组与数组之间的操作
(3)NumPy的计算方法 - 数组操作
(1)数组添加、删除和去重
(2)数组的拼接
(3)数组的分割 - 数组中
nan
和inf
- 二维数组的转置
课前准备
安装 Numpy
pip install -U numpy -i https://pypi.douban.com/simple
一、NumPy 认知
1、NumPy 介绍
numpyNumPy(Numerical Python)是一个开源的 Python 科学计算库,用于快速处理任意维度的数组。
NumPy 支持常见的数组和矩阵操作,它使用 ndarray 对象来处理多维数组,该对象是一个快速而灵活的大数据容器。
2、为什么要学 NumPy
- 快速
- 方便
- 科学计算的基础库
3、NumPy 的优势
- 对于同样的数值计算任务,使用 NumPy 要比直接编写 Python 代码便捷得多;
- NumPy 中的数组的存储效率和输入输出性能均远远优于 Python 中等价的基本数据结构,且其能够提升的性能是与数组中的元素成比例的;
- NumPy 的大部分代码都是用 C 语言写的,其底层算法在设计时就有着优异的性能,这使得 NumPy 比纯 Python 代码高效得多;
4、ndarray 与 Python 原生 list 运算效率对比
import random
import time
import numpy as np
a = []
for i in range(100000000):
a.append(random.random())
t1 = time.time()
sum1=sum(a)
t2=time.time()
b=np.array(a)
t4=time.time()
sum3=np.sum(b)
t5=time.time()
print(t2-t1, t5-t4)
t2-t1 为使用 python 自带的求和函数消耗的时间,t5-t4 为使用
numpy
求和消耗的时间,结果为:
从中我们看到 ndarray 的计算速度要快很多,节约了时间。
二、NumPy 的 Ndarray 对象
NumPy 最重要的一个特点是其 N 维数组对象 ndarray
,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。ndarray 对象是用于存放同类型元素的多维数组。
1、创建一维数组
import numpy as np
list1 = [1,2,3,4]
oneArray = np.array(list1)
print(type(oneArray))
print(oneArray)
# 创建数组的多种形式
# 1. 直接传入列表的方式
t1 = np.array([1,2,3])
print(t1)
print(type(t1))
'''
[1 2 3]
<class 'numpy.ndarray'>
'''
# 2. 传入range生成序列
t2 = np.array(range(10))
print(t2)
print(type(t2))
'''
[0 1 2 3 4 5 6 7 8 9]
<class 'numpy.ndarray'>
'''
# 3. 使用 numpy 自带的 np.arange() 生成数组
t3 = np.arange(0,10,2)
print(t3)
print(type(t3))
'''
[0 2 4 6 8]
<class 'numpy.ndarray'> '''
2、创建二维数组
import numpy as np
list2 = [[1,2],[3,4],[5,6]]
twoArray = np.array(list2)
print(twoArray)
'''
[[1 2]
[3 4]
[5 6]]
'''
3、常用属性
list2 = [[1,2],[3,4],[5,6]]
twoArray = np.array(list2)
# 获取数组的维度( 注意: 与函数的参数很像)
print(twoArray.ndim)
'''2'''
# 形状(行,列)
print(twoArray.shape)
'''(3, 2)'''
# 有多少个元素
print(twoArray.size)
'''6'''
4、调整数组的形状
four = np.array([[1,2,3],[4,5,6]])
# 修改的是原有的
four.shape = (3,2)
print(four)
# 返回一个新的数组
four_other = np.array([[1,2,3],[4,5,6]])
four_other_new = four.reshape(3,2)
print(four_other) print(four_other_new)
# 将多维变成一维数组
five = four.reshape((6,),order='F')
# 默认情况下‘C’以行为主的顺序展开,‘F’(Fortran风格)意味着以列的顺序展开
six = four.flatten(order='C')
print(five)
print(six)
# 拓展:数组的形状
t = np.arange(24)
print(t)
print(t.shape)
# 转换成二维
t1 = t.reshape((4,6))
print(t1)
print(t1.shape)
# 转成三维
t2 = t.reshape((2,3,4))
print(t2)
print(t2.shape)
5、将数组转成list
# 将数组转成list
a= np.array([9, 12, 88, 14, 25])
list_a = a.tolist()
print(list_a)
print(type(list_a))
6、NumPy 的数据类型
f = np.array([1,2,3,4,5], dtype = np.int16)
# 返回数组中每个元素的字节单位长度
print(f.itemsize)
# 获取数据类型
print(f.dtype)
# 调整数据类型
f1 = f.astype(np.int64)
print(f1.dtype)
# 拓展随机生成小数
# 使用python语法,保留两位
print(round(random.random(),2))
arr = np.array([random.random() for i in range(10)])
# 取小数点后两位
print(np.round(arr,2))
** dtype
是 numpy.dtype
类型,先看看对于数组来说都有哪些类型:**
名称 | 描述 | 简写 |
---|---|---|
np.bool | 用一个字节存储的布尔类型(True或False) | 'b' |
np.int8 | 一个字节大小,-128 至 127 (一个字节) | 'i' |
np.int16 | 整数,-32768 至 32767 (2个字节) | 'i2' |
np.int32 | 整数,-2 31 至 2 32 -1 (4个字节) | 'i4' |
np.int64 | 整数,-2 63 至 2 63 - 1 (8个字节) | 'i8' |
np.uint8 | 无符号整数,0 至 255 | 'u' |
np.uint16 | 无符号整数,0 至 65535 | 'u2' |
np.uint32 | 无符号整数,0 至 2 ** 32 - 1 | 'u4' |
np.uint64 | 无符号整数,0 至 2 ** 64 - 1 | 'u8' |
np.float16 | 半精度浮点数:16位,正负号1位,指数5位,精度10位 | 'f2' |
np.float32 | 单精度浮点数:32位,正负号1位,指数8位,精度23位 | 'f4' |
np.float64 | 双精度浮点数:64位,正负号1位,指数11位,精度52位 | 'f8' |
np.complex64 | 复数,分别用两个32位浮点数表示实部和虚部 | 'c8' |
np.complex128 | 复数,分别用两个64位浮点数表示实部和虚部 | 'c16' |
np.object_ | python对象 | 'O' |
np.string_ | 字符串 | 'S' |
np.unicode_ | unicode类型 | 'U' |
7、数组的索引和切片
(1)一维数组的操作方法
import numpy as np
a = np.arange(10)
# 冒号分隔切片参数 start:stop:step 来进行切片操作
print(a[2:7:2])
# 从索引 2 开始到索引 7 停止,间隔为 2
# 如果只放置一个参数,如 [2],将返回与该索引相对应的单个元素print(a[2],a)
# 如果为 [2:],表示从该索引开始以后的所有项都将被提取
print(a[2:])
(2)多维数组的操作方法
import numpy as np
t1 = np.arange(24).reshape(4,6)
print(t1)
print('*'*20)
print(t1[1]) # 取一行(一行代表是一条数据,索引也是从0开始的) print(t1[1,:]) # 取一行
print(t1[1:])# 取连续的多行
print(t1[1:3,:])# 取连续的多行
print(t1[[0,2,3]])# 取不连续的多行
print(t1[[0,2,3],:])# 取不连续的多行
print(t1[:,1])# 取一列
print(t1[:,1:])# 连续的多列print(t1[:,[0,2,3]])# 取不连续的多列print(t1[2,3])# # 取某一个值,三行四列
print(t1[[0,1,1],[0,1,3]])# 取多个不连续的值,[[行,行。。。],[列,列。。。]]
8、数组中的数值修改
t = np.arange(24).reshape(4,6)
# 修改某一行的值
t[1,:]=0
# 修改某一列的值
t[:,1]=0
# 修改连续多行
t[1:3,:]=0
# 修改连续多列
t[:,1:4]=0
# 修改多行多列,取第二行到第四行,第三列到第五列
t[1:4,2:5]=0
# 修改多个不相邻的点
t[[0,1],[0,3]]=0
# 可以根据条件修改,比如讲小于10的值改掉
t[t<10]=0
# 使用逻辑判断
# np.logical_and &
# np.logical_or |
# np.logical_not ~
t[(t>2)&(t<6)]=0 # 与
t[(t<2)|(t>6)]=0 # 或
t[~(t>6)]=0 # 非
print(t)
# 拓展
# 三目运算( np.where(condition, x, y)满足条件(condition),输出x,不满足输出y。))
score = np.array([[80,88],[82,81],[75,81]])
result = np.where(score>80,True,False)
print(result)
三、数组中的轴
1、什么是轴?
在 Numpy 中可以理解为方向,使用 0,1,2 数字表示,对于一个一维数组,只有一个 0 轴,
对于 2 维数组(shape(2, 2)) 有 0 轴和 1 轴,
对于3维数组(shape(2, 2, 3))有 0,1,2 轴
2、为什么要学习轴?
有了轴的概念后,我们计算会更加方便,比如计算一个 2 维数组的平均值,必须指定是计算哪个方向上面的数字的平均值。
二维数组轴三维数组中:
三维数组轴在计算的时候可以想象成是每一个坐标轴,分别计算这个轴上面的每一个刻度上的值,或者在二维数组中记住1表示列,0表示行。
四、数组的计算
1、数组和数的计算
由于 numpy 的广播机机制在运算过程中,加减乘除的值被广播到所有的元素上面。
t1 = np.arange(24).reshape((6,4))
print(t1+2)
print(t1*2)
print(t1/2)
2、数组与数组之间的操作
同种形状的数组(对应位置进行计算操作):
t1 = np.arange(24).reshape((6,4))
t2 = np.arange(100,124).reshape((6,4))
print(t1+t2)
print(t1*t2)
不种形状的多维数组不能计算:
t1 = np.arange(24).reshape((4,6))
t2 = np.arange(18).reshape((3,6))
print(t1)
print(t2)
print(t1-t2)
'''
ValueError: operands could not be broadcast together with shapes (4,6) (3,6) '''
行数或者列数相同的一维数组和多维数组可以进行计算。
行形状相同(会与每一行数组的对应位相操作):
t1 = np.arange(24).reshape((4,6))
t2 = np.arange(0,6)
print(t1-t2)
列形状相同(会与每一个相同维度的数组的对应位相操作):
t1 = np.arange(24).reshape((4,6))
t2 = np.arange(4).reshape((4,1))
print(t1-t2)
3、NumPy 的计算方法
import numpy as np
score = np.array([[80,88],[82,81],[75,81]])
# 1. 获取所有数据最大值
result = np.max(score)
# 2. 获取某一个轴上的数据最大值
result = np.max(score,axis=0)
# 3. 获取最小值
result = np.min(score)
# 4. 获取某一个轴上的数据最小值
result = np.min(score,axis=0)
# 5. 数据的比较
result = np.maximum([-2, -1, 0, 1, 2], 0) # 第一个参数中的每一个数与第二个参数比较返回大的
result = np.minimum([-2, -1, 0, 1, 2], 0) # 第一个参数中的每一个数与第二个参数比较返回小的
result = np.maximum([-2, -1, 0, 1, 2], [1,2,3,4,5]) # 接受的两个参数,也可以大小一致; 第二个参数只是一个单独的值时,其实是用到了维度的广播机制;
# 6. 求平均值
result = np.mean(score) # 获取所有数据的平均值
result = np.mean(score,axis=0) # 获取某一行或者某一列的平均值
# 7. 返回给定axis上的累计和
arr = np.array([[1,2,3], [4,5,6]])
print(arr)
print(arr.cumsum(0))
# 8. argmin求最小值索引
result = np.argmin(score,axis=0)
print(result)
# 9. 求每一列的标准差
# 标准差是一组数据平均值分散程度的一种度量。一个较大的标准差,代表大部分数值和其平均值之间差异较大;
# 一个较小的标准差,代表这些数据较接近平均值反应出数据的波动稳定情况,越大表示波动越大,越不稳定。
result = np.std(score,axis=0)
print(result)
# 10. 极值
# np.ptp(t,axis=None) 就是最大值和最小值的差
# 拓展:方差var, 协方差cov, 计算平均值 average, 计算中位数 median
通用函数:
numpy.sqrt(array) | 平方根函数 |
---|---|
numpy.exp(array) | e^array[i]的数组 |
numpy.abs/fabs(array) | 计算绝对值 |
numpy.square(array) | 计算各元素的平方 等于 array**2 |
numpy.log/log10/log2(array) | 计算各元素的各种对数 |
numpy.sign(array) | 计算各元素正负号 |
numpy.isnan(array) | 计算各元素是否为NaN |
numpy.isinf(array) | 计算各元素是否为NaN |
numpy.cos/cosh/sin/sinh/tan/tanh(array) | 三角函数 |
numpy.modf(array) | 将array中值得整数和小数分离,作两个数组返回 |
numpy.ceil(array) | 向上取整,也就是取比这个数大的整数 |
numpy.floor(array) | 向下取整,也就是取比这个数小的整数 |
numpy.rint(array) | 四舍五入 |
numpy.trunc(array) | 向0取整 |
numpy.cos(array) | 正弦值 |
numpy.sin(array) | 余弦值 |
numpy.tan(array) | 正切值 |
numpy.add(array1,array2) | 元素级加法 |
numpy.subtract(array1,array2) | 元素级减法 |
numpy.multiply(array1,array2) | 元素级乘法 |
numpy.sqrt(array) | 平方根函数 |
numpy.divide(array1,array2) | 元素级除法 array1./array2 |
numpy.power(array1,array2) | 元素级指数 array1.^array2 |
numpy.maximum/minimum(array1,aray2) | 元素级最大值 |
numpy.fmax/fmin(array1,array2) | 元素级最大值,忽略NaN |
numpy.mod(array1,array2) | 元素级求模 |
numpy.copysign(array1,array2) | 将第二个数组中值得符号复制给第一个数组中值 |
numpy.greater/greater_equal/less/less_equal/equal/not_equal (array1,array2) | 元素级比较运算,产生布尔数组 |
numpy.logical_end/logical_or/logic_xor(array1,array2) | 元素级的真值逻辑运算 |
五、数组操作
1、数组添加、删除和去重
(1)数组的添加
# 1. numpy.append 函数在数组的末尾添加值。追加操作会分配整个数组,并把原来的数组复制到新数组中。 此外,输入数组的维度必须匹配否则将生成ValueError。注意:最多两个数组拼接,不能三个及以上进行拼接
'''
参数说明:
arr:输入数组
values:要向arr添加的值,需要和arr形状相同(除了要添加的轴)
axis:默认为 None。当axis无定义时,是横向加成,返回总是为一维数组!当axis有定义的时候,分别为0和1的时候。当axis有定义的时候,分别为0的时候(列数要相同)。当axis为1时,数组是加在右边(行数 要相同)。
'''
a = np.array([[1,2,3],[4,5,6]])
print ('第一个数组:')
print (a)
print ('\n')
print ('向数组添加元素:')
print (np.append(a, [7,8,9]))
print ('\n')
print ('沿轴 0 添加元素:')
print (np.append(a, [[7,8,9]],axis = 0))
print ('\n')
print ('沿轴 1 添加元素:')
print (np.append(a, [[5,5,5],[7,8,9]],axis = 1))
# 2. numpy.insert 函数在给定索引之前,沿给定轴在输入数组中插入值。
# 如果值的类型转换为要插入,则它与输入数组不同。 插入没有原地的,函数会返回一个新数组。 此外,如果未提供轴,则输入数组会被展开。
a = np.array([[1,2],[3,4],[5,6]])
print ('第一个数组:')
print (a)
print ('\n')
print ('未传递 Axis 参数。 在插入之前输入数组会被展开。')
print (np.insert(a,3,[11,12]))
print ('\n')
print ('传递了 Axis 参数。 会广播值数组来配输入数组。')
print ('沿轴 0 广播:')
print (np.insert(a,1,11,axis = 0))
print ('\n')
print ('沿轴 1 广播:')
print (np.insert(a,1,11,axis = 1))
(2)数组中的删除
#numpy.delete 函数返回从输入数组中删除指定子数组的新数组。 与 insert() 函数的情况一样,如果未提供轴参数,则输入数组将展开。
'''
参数说明:
arr: 输入数组
obj:可以被切片,整数或者整数数组,表明要从输入数组删除的子数组
axis:沿着它删除给定子数组的轴,如果未提供,则输入数组会被展开
'''
a = np.arange(12).reshape(3,4)
print ('第一个数组:')
print (a)
print ('\n')
print ('未传递 Axis 参数。 在删除之前输入数组会被展开。')
print (np.delete(a,5))
print ('\n')
print ('删除每一行中的第二列:')
print (np.delete(a,1,axis = 1))
print ('\n')
(3)数组去重
# numpy.unique 函数用于去除数组中的重复元素。
'''
arr:输入数组,如果不是一维数组则会展开 return_index:如果为true,返回新列表元素在旧列表中的位置(下标),并以列表形式存储
return_inverse:如果为true,返回旧列表元素在新列表中的位置(下标),并以列表形式存储
return_counts:如果为true,返回去重数组中的元素在原数组中的出现次数
'''
a = np.array([5,2,6,2,7,5,6,8,2,9])
print ('第一个数组:')
print (a)
print ('\n')
print ('第一个数组的去重值:')
u = np.unique(a)
print (u)
print ('\n')
print ('去重数组的索引数组:')
u,indices = np.unique(a, return_index = True)
print (indices)
print ('\n')
print ('我们可以看到每个和原数组下标对应的数值:')
print (a)
print ('\n')
print ('去重数组的下标:')
u,indices = np.unique(a,return_inverse = True)
print (u)
print (indices) print ('\n')
print ('返回去重元素的重复数量:')
u,indices = np.unique(a,return_counts = True)
print (u)
print (indices)
2、数组的拼接
有的时候我们需要将两个数据加起来一起研究分析,我们就可以将其进行拼接然后分析。
# 1. 根据轴连接的数组序列
a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
# 要求a,b两个数组的维度相同
print ('沿轴 0 连接两个数组:')
print (np.concatenate((a,b),axis= 0))
print ('\n')
print ('沿轴 1 连接两个数组:')
print (np.concatenate((a,b),axis = 1))
# 2. 根据轴进行堆叠
print ('沿轴 0 连接两个数组:')
print (np.stack((a,b),axis= 0))
print ('\n')
print ('沿轴 1 连接两个数组:')
print (np.stack((a,b),axis = 1))
# 3. 矩阵垂直拼接
v1 = [[0,1,2,3,4,5],[6,7,8,9,10,11]]
v2 = [[12,13,14,15,16,17],[18,19,20,21,22,23]]
result = np.vstack((v1,v2))
print(result)
# 4. 矩阵水平拼接
v1 = [[0,1,2,3,4,5],[6,7,8,9,10,11]]
v2 = [[12,13,14,15,16,17],[18,19,20,21,22,23]]
result = np.hstack((v1,v2))
print(result)
3、数组的分割
# 1. 将一个数组分割为多个子数组
'''
参数说明:
ary: 被 分 割 的 数 组 indices_or_sections:果是一个整数,就用该数平均切分,如果是一个数组,为沿轴切分的位置(左开右 闭)
axis:沿着哪个维度进行切向,默认为0,横向切分。为1时,纵向切分'''
# arr = np.arange(9).reshape(3,3)
# print ('将数组分为三个大小相等的子数组:')
# b = np.split(arr,3)
# print (b)
# 2.numpy.hsplit 函数用于水平分割数组,通过指定要返回的相同形状的数组数量来拆分原数组。
# floor() 返回数字的下舍整数。
harr = np.floor(10 * np.random.random((2, 6)))
# print ('原array:')
# print(harr)
# print ('拆分后:')
# print(np.hsplit(harr, 3))
# 3.numpy.vsplit 沿着垂直轴分割
a = np.arange(16).reshape(4,4)
# print ('第一个数组:')
# print (a)
# print ('\n')
# print ('竖直分割:')
# b = np.vsplit(a,2)
# print (b)
六、数组中 nan
和 inf
C 语言中表示最大的正整数值是 0x7FFFFFFF,最小的负整数是 0x80000000。inf
表示无穷大,需要使用 float(‘inf’)
函数来转化,那么对应的就有 float('-inf')
表示无穷小了。这样你就可以使用任意数来判断和它的关系了。
那什么时候会出现 inf
呢?比如一个数字除以 0,Python 中会报错,但是 numpy 中会是一个 inf
或者 -inf
。
另外还有 nan
,这种写法在 pandas 中常见,表示缺失的数据,所以一般用 nan
来表示。任何与其做运算结果都是 nan
。
# 创建一个nan和inf
a = np.nan
b = np.inf
print(a,type(a))
print(b,type(b))
# --判断数组中为nan的个数(注意:float类型的数据才能赋值nan)
t = np.arange(24,dtype=float).reshape(4,6)
# 可以使用np.count_nonzero() 来判断非零的个数
print(np.count_nonzero(t))
# 将三行四列的数改成nan
t[3,4] = np.nan
# 并且 np.nan != np.nan 结果 是TRUE
# 所以我们可以使用这两个结合使用判断nan的个数
print(np.count_nonzero(t != t))
# 注意: nan和任何数计算都为nan
print(np.sum(t,axis=0))
# 将 nan 替换为 0
t[np.isnan(t)] = 0 print(t)
#----------练习: 处理数组中nan
t = np.arange(24).reshape(4,6).astype('float')
# 将数组中的一部分替换nan
t[1,3:] = np.nan
print(t)
# 遍历每一列,然后判断每一列是否有nan
for i in range(t.shape[1]):
#获取当前列数据
temp_col = t[:,i]
# 判断当前列的数据中是否含有nan
nan_num = np.count_nonzero(temp_col != temp_col)
if nan_num != 0: # 条件成立说明含有nan
# 将这一列不为nan的数据拿出来
temp_col_not_nan = temp_col[temp_col==temp_col]
# 将nan替换成这一列的平均值
temp_col[np.isnan(temp_col)] = np.mean(temp_col_not_nan)
print(t)
这里注意把握两个重点:
np.nan != np.nan
结果是True
,也就是np.nan != np.nan
结果为False
,nan
不等于nan
!nan
和任何数计算结果都为nan
七、二维数组的转置
#对换数组的维度
a = np.arange(12).reshape(3,4)
print ('原数组:')
print (a)
print ('\n')
print (' 对换数组 :')
print (np.transpose(a))
# 与transpose一致
a = np.arange(12).reshape(3,4)
print ('原数组:')
print (a)
print ('\n')
print ('转置数组:')
print (a.T)
# 函数用于交换数组的两个轴
t1 = np.arange(24).reshape(4,6)
re = t1.swapaxes(1,0)
print ('原数组:')
print (t1) print ('\n')
print ('调用 swapaxes 函数后的数组:')
print (re)
网友评论