文章目录
官方中文文档[https://www.numpy.org.cn/]
简介
NumPy是Python中科学计算的基础包。它是一个Python库,提供多维数组对象,各种派生对象(如掩码数组和矩阵),以及用于数组快速操作的各种API,有包括数学、逻辑、形状操作、排序、选择、输入输出、离散傅立叶变换、基本线性代数,基本统计运算和随机模拟等等。
NumPy包的核心是 ndarray 对象。它封装了python原生的同数据类型的 n 维数组,为了保证其性能优良,其中有许多操作都是代码在本地进行编译后执行的。
NumPy 最重要的一个特点是其 N 维数组对象 ndarray,它是一系列同类型数据的集合,以 0 下标为开始进行集合中元素的索引。ndarray 对象是用于存放同类型元素的多维数组。ndarray 中的每个元素在内存中都有相同存储大小的区域。
NumPy数组 和 原生Python Array(数组)之间有几个重要的区别:
- NumPy 数组在创建时具有固定的大小,与Python的原生数组对象(可以动态增长)不同。更改ndarray的大小将创建一个新数组并删除原来的数组。
- NumPy 数组中的元素都需要具有相同的数据类型,因此在内存中的大小相同。 例外情况:Python的原生数组里包含了NumPy的对象的时候,这种情况下就允许不同大小元素的数组。
- NumPy 数组有助于对大量数据进行高级数学和其他类型的操作。通常,这些操作的执行效率更高,比使用Python原生数组的代码更少。
- 越来越多的基于Python的科学和数学软件包使用NumPy数组; 虽然这些工具通常都支持Python的原生数组作为参数,但它们在处理之前会还是会将输入的数组转换为NumPy的数组,而且也通常输出为NumPy数组。换句话说,为了高效地使用当今科学/数学基于Python的工具(大部分的科学计算工具),你只知道如何使用Python的原生数组类型是不够的 - 还需要知道如何使用 NumPy 数组。
python数组与ndarray数组的运算方式不同,+在python数组中代表追加,ndarray中代表对应元素相加,且数组的shape必须一致,而*在python中代表重复两个python数组不能相乘,ndarray就是数组的乘法
numpy的使用
ndarry的创建
方法一: 直接将数组/列表传入array方法中, 将数据类型转换为ndarray.得到的数组的类型是从Python列表中元素的类型推导出来的。
>>> import numpy as np
>>> a = np.array([1,2,3,4,5])
>>> b = np.array([1.2,3,4,5])
>>> print(a.dtype)
int64
>>> print(b.dtype)
float64
# array方法传入的值可以是range对象
>>> c = np.array(range(1,6))
>>> d = [1.1,2,3,4,5]
# 转换数据类型时可以通过dtype对数组的所有对象转换类型. eg: dtype=np.int将元素转成int
>>> d1 = np.array(d,dtype=np.int)
>>> d1
array([1, 2, 3, 4, 5])
>>> type(d)
<class ‘list’>
>>> type(d1)
<class ‘numpy.ndarray’>
方法2:直接生成指定的数值
为了创建数字组成的数组,NumPy提供了一个类似于range的函数,该函数返回数组而不是列表。
>>> a = np.arange(1,6)
>>> b = np.arange(2.2,13.3,0.5)
>>> a
array([1, 2, 3, 4, 5])
>>> b
array([ 2.2, 2.7, 3.2, 3.7, 4.2, 4.7, 5.2, 5.7, 6.2, 6.7, 7.2,
7.7, 8.2, 8.7, 9.2, 9.7, 10.2, 10.7, 11.2, 11.7, 12.2, 12.7,
13.2])
方法3:linspace 获取指定长度的数组
当arange与浮点参数一起使用时,由于有限的浮点精度,通常不可能预测所获得的元素的数量。出于这个原因,通常最好使用linspace函数来接收我们想要的元素数量的函数,而不是步长(step)
>>> c = np.linspace(0,2,9)
>>> c
array([0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ])
# 2). 查看numpy创建的数组类型
>>> type(a)
<class ‘numpy.ndarray’>
>>> type(b)
<class ‘numpy.ndarray’>
>>> type©
<class ‘numpy.ndarray’>
numpy的数据类型
查看数组的数据类型
>>> a.dtype
dtype(‘int64’)
创建数组时设定数据类型
>>> d = np.array([1.1,0,1.3,5],dtype=np.float)
>>> print(d,d.dtype)
[1.1 0. 1.3 5. ] float64
修改数组的数据类型
>>> e = d.astype(‘int64’)
>>> print(e,e.dtype)
[1 0 1 5] int64
修改浮点值的小数位数为3位
>>> g = np.round(f,3)
>>> print(g)
[[0.214 0.03 0.776 0.871]
[0.099 0.323 0.391 0.864]
[0.624 0.503 0.01 0.811]]
数据类型对象dtype
数据类型对象是用来描述与数组对应的内存区域如何使用,这依赖如下几个方面:
- 数据的类型(整数,浮点数或者 Python 对象)
- 数据的大小(例如, 整数使用多少个字节存储)
- 数据的字节顺序(小端法或大端法)
- 在结构化类型的情况下,字段的名称、每个字段的数据类型和每个字段所取的内存块的部分
- 如果数据类型是子数组,它的形状和数据类型
import numpy as np
# int8, int16, int32, int64 四种数据类型可以使用字符串 ‘i1’, ‘i2’,‘i4’,‘i8’ 代替
dt = np.dtype(‘i4’)
print(dt)
下面实例展示结构化数据类型的使用,类型字段和对应的实际类型将被创建。
# 首先创建结构化数据类型
import numpy as np
dt = np.dtype([(‘age’,np.int8)])
print(dt)
# 类型字段名可以用于存取实际的 age 列
import numpy as np
dt = np.dtype([(‘age’,np.int8)])
a = np.array([(10,),(20,),(30,)], dtype = dt)
print(a[‘age’])
下面的示例定义一个结构化数据类型 student,包含字符串字段 name,整数字段 age,及浮点字段 marks,并将这个 dtype 应用到 ndarray 对象。
import numpy as np
student = np.dtype([(‘name’,‘S20’), (‘age’, ‘i1’), (‘marks’, ‘f4’)])
a = np.array([(‘abc’, 21, 50),(‘xyz’, 18, 75)], dtype = student)
print(a)
numpy数组的转置,共有三种方法,知道一种即可
import numpy as np
data = np.random.random((3, 4))
# 转换数据结构 # 2,6
data = data.reshape((2, 6))
print(data)
print("转置: ", data.T)
print("转置: ", data.transpose())
print("转置: ", data.swapaxes(1, 0))
numpy的索引和切片
# numpy数组的索引和切片
import numpy as np
# 1、生成测试数据
a = np.arange(12).reshape((3, 4))
print(a)
# *************获取单行或单列*******************
# # 取第2行; a[i]=> 获取第i+1行
# print('第2行内容:', a[1])
# # 获取第2列,a[:,i] => 获取第i+1列
# print('第二列内容:', a[:, 1])
# # 获取第二行第三列
# print('第二行第三列的内容:', a[1, 2])
# ****************连续行或者列****************
# # 获取第二行和第三行 a[i:j] ===> 获取i+1行到j行
# print(a[1:3])
# # 获取第三列和第四列;a[:,i:j] ===> 获取i+1列到j列
# print(a[:, 1:3])
#
# # 获取前两行和第二列
# print(a[0:2, 1])
# print(a[0:2, 1:2])
"""
需求:拿出2*2的数组
1 2
5 6
1). 先获取前2行
2). 在前2行的基础上获取第2列和第3列
"""
# print(a[:2, 1:3])
# ***********获取不连续的行或者列**************
# 获取第一行和第三行的所有元素
print(a[[0, 2], :])
# 获取第一列和第四列的所有元素
print(a[:, [0, 3]])
# 获取第一行第一列的元素, 和第三行第4列的元素
print(a[[0, 2], [0, 3]])
numpy中数值的修改
# numpy中数值的修改
import numpy as np
# 指定行和指定列的修改
# 生成指定数据
t = np.arange(24).reshape((4, 6))
# print(t)
# 方法一:根据索引和切片对元素进行赋值
# 将第一列到第三列设置位0
# t[:, 0:3] = 0
# print(t)
# # 方法二:布尔索引,满足条件bool=True,则赋值,否则不做修改
# print(t < 10) # 返回的矩阵存储的是bool类型的数据,满足条件为T,否则为F
#
# t[t < 10] = 100
# print(t)
# t[t > 20] = 200
# print(t)
# 方法三:numpy的三元运算符
# 满足条件/Bool=True,则赋值=value1, 否则,赋值=value2
t1 = np.where(t<100, 0, 1)
print(t)
print(t1)
小案例:获取二维数组的四角元素
import numpy as np
# 获取矩阵的四角元素
def get_edge(data):
row, column = data.shape
rows = np.array([[0, 0], [row - 1, row - 1]])
cols = np.array([[0, column - 1], [0, column - 1]])
print(rows,cols)
return data[rows, cols]
if __name__ == '__main__':
x = np.arange(30).reshape((5, 6))
print(x[[[0,0],[4,4]],[[0,5],[0,5]]])
print('result:', get_edge(x))
花式索引
"""
花式索引
花式索引指的是利用整数数组进行索引。
花式索引根据索引数组的值作为目标数组的某个轴的下标来取值。对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应位置的元素;
如果目标是二维数组,那么就是对应下标的行。
花式索引跟切片不一样,它总是将数据复制到新数组中。
"""
import numpy as np
# 传入顺序索引数组
x = np.arange(32).reshape((8,4))
print(x)
print(x[[4, 2, 1, 7]])
# 传入倒序索引数组
print(x[[-2, -4, -1, -7]])
传入多个索引数组
# 传入多个索引数组(要使用np.ix_)
"""
原理:np.ix_函数就是输入两个数组,产生笛卡尔积的映射关系
将数组[1,5,7,2]和数组[0,3,1,2]产生笛卡尔积,就是得到
(1,0),(1,3),(1,1),(1,2);(5,0),(5,3),(5,1),(5,2);(7,0),(7,3),(7,1),(7,2);(2,0),(2,3),(2,1),(2,2);
"""
x=np.arange(32).reshape((8,4))
print(x)
print (x[np.ix_([1,5,7,2],[0,3,1,2])])
数组形状的修改
reshape 不改变数据的条件下修改形状
numpy.reshape(arr, newshape, order=‘C’)
order:‘C’ – 按行,‘F’ – 按列,‘A’ – 原顺序,‘k’ – 元素在内存中的出现顺序。
flat 数组元素迭代器
flatten 返回一份数组拷贝,对拷贝所做的修改不会影响原始数组
ravel 返回展开数组
import numpy as np
# ************flat***************
a = np.arange(9).reshape((3, 3))
print('原始数据:')
for row in a:
print(row)
# 对数组的每个元素都进行处理(展开),可以使用flat属性,该属性是一个数组元素的迭代器
print('迭代后的数组:')
# print(a.flat)
for element in a.flat:
print(element)
print('************flatten****************')
a = np.arange(8).reshape(2, 4)
print('原属组:')
print(a)
print('\n')
# 默认按行
print('展开的数组:')
print(a.flatten())
print('\n')
print('以F风格顺序展开的数组:')
print(a.flatten(order='F'))
print('**************ravel*********************')
a = np.arange(8).reshape(2, 4)
print('原数组:' + '\n', a)
print('调用ravel函数之后:')
print(a.ravel())
print('以F风格顺序调用reval函数之后:')
print(a.ravel(order='F'))
数组拼接
concatenate 连接沿现有轴的数组序列
stack 沿着新的轴加入一系列数组。
hstack 水平堆叠序列中的数组(列方向)
vstack 竖直堆叠序列中的数组(行方向)
# 09_数组拼接
import numpy as np
# print('***************concatenate************')
# a = np.array([[1, 2], [3, 4]])
# print('第一个数组:')
# print(a)
# print('\n')
# b = np.array([[5, 6], [7, 8]])
# print('第二个数组:')
# print(b)
# print('\n')
#
# # 两个数组维度相同
# # 0轴和1轴分别代表x轴和y轴
# print('沿0轴连接两个数组')
# print(np.concatenate((a, b)))
# print('\n')
# #
# print('沿轴1连接两个数组:')
# print(np.concatenate((a, b), axis=1))
# print("*************************stack*********************************")
# a = np.array([[1, 2], [3, 4]])
# print('第一个数组:')
# print(a)
# print('\n')
# b = np.array([[5, 6], [7, 8]])
# print('第二个数组:')
# print(b)
# print('\n')
#
# print('沿轴0堆叠两个数组:')
# stack_0 = np.stack((a, b), axis=0)
# print(stack_0)
# print(stack_0.shape)
# print('沿轴 1 堆叠两个数组:')
# print(np.stack((a, b), axis=1))
print("**************************************hstack + vstack*************************************")
a = np.array([[1, 2], [3, 4]])
print('第一个数组:')
print(a)
print('\n')
b = np.array([[5, 6], [7, 8]])
print('第二个数组:')
print(b)
print('\n')
print('水平堆叠:')
c = np.hstack((a, b))
print(c)
print('\n')
print('竖直堆叠:')
c = np.vstack((a, b))
print(c)
print('\n')
数据分割
split 将一个数组分割为多个子数组
numpy.split(ary, indices_or_sections, axis)
hsplit 将一个数组水平分割为多个子数组(按列)
vsplit 将一个数组垂直分割为多个子数组(按行)
# 数据分割
# print("**********************split******************************")
# a = np.arange(9)
# print('第一个数组:')
# print(a)
# print('\n')
# print('将数组分为三个大小相等的子数组:')
# b = np.split(a, 3)
# print(b)
# print('\n')
#
# print('将数组在一维数组中表明的位置分割:')
# b = np.split(a, [1, 7])
# print(b)
# print('******************hsplit*****************')
# harr = np.arange(12).reshape((3, 4))
# print('原array:')
# print(harr)
#
# print('横向拆分后:')
# print(np.hsplit(harr, 2))
#
#
#
print("***************************vsplit****************************")
a = np.arange(12).reshape(4, 3)
print('第一个数组:')
print(a)
print('\n')
print('竖直分割:')
b = np.vsplit(a, 2)
print(b)
数组元素的添加和删除
resize 返回指定形状的新数组
append 将值添加到数组末尾
insert 沿指定轴将值插入到指定下标之前
delete 删掉某个轴的子数组,并返回删除后的新数组
unique 查找数组内的唯一元素
arr:输入数组,如果不是一维数组则会展开
return_index:如果为true,返回新列表元素在旧列表中的位置(下标),并以列表形式储
return_counts:如果为true,返回去重数组中的元素在原数组中的出现次数
# 11_数组元素的添加与删除
print('****************append******************')
a = np.array([[1, 2, 3], [4, 5, 6]])
print('第一个数组:')
print(a)
print('向数组添加元素:')
# 没有指定行/列追加元素时, 默认先把前面的元素展开,再追加
print(np.append(a, [7, 8]))
print('沿轴0添加元素')
print(np.append(a, [[7, 8, 9]], axis=0)) # 添加的数组的列数,与原数组相同
print('沿1轴添加元素')
print(np.append(a, [[7, 8], [9, 10]], axis=1)) #添加的数组的行数,与原数组相同
print('***********insert**************')
a = np.array([[1, 2], [3, 4], [5, 6]])
print('第一个数组:')
print(a)
print('未传递 Axis 参数。 在插入之前输入数组会被展开。')
print(np.insert(a, 3, [11, 12]))
print('传递Axis参数')
print('沿0轴插入')
print(np.insert(a, 1, [11, 100], axis=0))
print('沿1轴插入')
print(np.insert(a, 1, [7, 8, 9], axis=1))
print('*******************delete********************')
a = np.arange(12).reshape(3, 4)
print('第一个数组')
print(a)
print('未传递 Axis 参数。 在删除之前输入数组会被展开。')
print(np.delete(a, 1))
print('删除第二列:')
print(np.delete(a, 1, axis=1))
print('\n')
print('删除第二行:')
print(np.delete(a, 1, axis=0))
print('\n')
print('从数组中删除切片')
a = np.array([1,2,3,4,5,6,7,8,9,10])
print(np.s_[::2]) # 返回的是一个切片对象
print(np.delete(a, np.s_[1::2]))
print('删除二维数组')
data = np.arange(12).reshape((3, 4))
print('数组元素')
print(data)
print(np.delete(data, np.s_[::2], axis=0))
print(np.delete(data, np.s_[::2], axis=1))
print('*******************unique*********************')
a = np.array([5, 2, 6, 2, 7, 5, 6, 8, 2, 9])
print('第一个数组:')
print(a)
print('第一个数组的去重值')
u = np.unique(a) # 去除重复的值,并按由小到大的顺序排列
print(u)
print('取重数组的索引组')
u, indices = np.unique(a, return_index=True)
print(u, indices)
print('返回去重元素的重复数量')
u, indices = np.unique(a, return_counts=True)
print(indices)
numpy的统计函数
numpy.amin() 用于计算数组中的元素沿指定轴的最小值。
numpy.amax() 用于计算数组中的元素沿指定轴的最大值。
numpy.ptp()函数计算数组中元素最大值与最小值的差(最大值 - 最小值)。
numpy.percentile() 百分位数是统计中使用的度量,表示小于这个值的观察值的百分比。
numpy.median() 函数用于计算数组 a 中元素的中位数(中值)
# 平均值, 各个值的比重/权重一样. 语文: 100 数学:70 英语: 80 (100+70+80)/3
numpy.mean() 函数返回数组中元素的算术平均值。 如果提供了轴,则沿其计算。
# 加权平均值, 各个值的比重/权重不一样. 语文: 100 (40%)数学:70(40%) 英语: 80(20%) (10040%+7040%+80*20%)/3
numpy.average() 函数根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。 average()
np.std() 标准差是一组数据平均值分散程度的一种度量。
标准差公式如下:std = sqrt(((x - x.mean())2))/n
np.var() 统计中的方差(样本方差)是每个样本值与全体样本值的平均数之差的平方值的平均数,即 ((x - x.mean()) 2)/n。
标准差是方差的平方根。
# numpy的统计函数
a = np.arange(12).reshape(3, 4)
print(a)
print(np.amin(a))
print(np.amax(a))
print(np.ptp(a))
print(np.percentile(a, 70)) # 算出数组中评价在70%的值,说明在数组中有30%的比这个值大
print(np.percentile(a, 50, axis=1)) # 每一行的中位数
print(np.percentile(a, 100/3, axis=0)) # 每一列的中位数
print(np.median(a))
print(np.mean(a))
print(np.mean(a, axis=0)) # 每一列的平均值
print(np.mean(a, axis=1)) # 每一行的平均值
print(np.average(a, axis=1, weights=[1, 2, 3, 4])) # 求加权平均数,weight中是权值
print(np.std(a))
print(np.var(a))
案例:统计学生信息
根据表中的信息完成以下需求:
需求1:
获取所有男生的身高, 求平均值;获取所有女生的身高, 求平均值;并绘制柱状图显示
1). 读取文件中的Sex和Height
2). 根据布尔索引判断姓名, 获取男性的身高或者女性的身高 data[‘gender’] == ‘M’
3). 求平均值mean函数
需求2:
获取所有男生的体重, 求平均值;获取所有女生的体重, 求平均值;并绘制柱状图显示
import numpy as np
def get_avg_height():
fname = "doc/eg6-a-student-data.txt"
# 定义读取列的数据类型
dtype = np.dtype([('gender', '|S1'), ('height', 'f2')])
# 读取文件的第2列和第3列, 前9行忽略;
data = np.loadtxt(fname=fname, dtype=dtype, skiprows=9,
usecols=(1, 3))
# print(data)
# print(type(data)) # 通过np加载文件, 返回的是ndarray的数据类型
# print(data['gender']) # 获取gender列信息
# print(data['height']) # 获取height列信息
# print(data['height'][data['gender'] == b'M'].mean())
# print(data['height'][data['gender'] == b'F'].mean())
# 判断是否性别为那男的表达式
isMale = (data['gender'] == b'M')
male_avg_height = data['height'][isMale].mean()
# ~代表取反
female_avg_height = data['height'][~isMale].mean()
return male_avg_height, female_avg_height
def parser_weight(weight):
# 对于体重数据的处理, 如果不能转换为浮点数据类型, 则返回缺失值;
try:
return float(weight)
except ValueError as e:
return -99
def get_avg_weight():
fname = "doc/eg6-a-student-data.txt"
# 定义读取列的数据类型
dtype = np.dtype([('gender', '|S1'), ('weight', 'f2')])
# 读取文件的第2列和第4列, 前9行忽略;
data = np.loadtxt(fname=fname, dtype=dtype, skiprows=9,
usecols=(1, 4), converters={4:parser_weight})
# 判断是否性别为男的平均身高
isMale = data['gender'] == b'M'
# 判断是否性别为男的平均体重
is_weight_vaild = data['weight'] > 0
male_avg_weight = data['weight'][isMale & is_weight_vaild].mean()
female_avg_weight = data['weight'][~isMale & is_weight_vaild].mean()
return male_avg_weight, female_avg_weight
if __name__ == '__main__':
print(get_avg_height())
print(get_avg_weight())