NumPy 数组结构和 Python 列表 list 对比:
标准的 Python 中,用列表 list 保存数组的数值。由于列表中的元素可以是任意的对象,所以列表中list保存的是对象的指针。虽然在 Python 编程中隐去了指针的概念,但是数组有指针,Python 的列表 list 其实就是数组。这样如果我要保存一个简单的数组 [0,1,2],就需要有 3 个指针和 3 个整数的对象,这样对于 Python 来说是非常不经济的,浪费了内存和计算时间。
列表 list 的元素在系统内存中是分散存储的,而 NumPy 数组存储在一个均匀连续的内存块中。这样数组计算遍历所有的元素,不像列表 list 还需要对内存地址进行查找,从而节省了计算资源。另外在内存访问模式中,缓存会直接把字节块从 RAM 加载到CPU 寄存器中。因为数据连续的存储在内存中,NumPy 直接利用现代 CPU 的矢量化指令计算,加载寄存器中的多个连续浮点数。另外 NumPy 中的矩阵计算可以采用多线程的方式,充分利用多核 CPU 计算资源,大大提升了计算效率。
当然除了使用 NumPy 外,你还需要一些技巧来提升内存和提高计算资源的利用率。一个重要的规则就是:避免采用隐式拷贝,而是采用就地操作的方式。举个例子,如果我想让一个数值 x 是原来的两倍,可以直接写成 x*=2,而不要写成 y=x*2。
ndarray对象:
创建数组:
import numpy as np
a = np.array([1, 2, 3])
b = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
b[1,1]=10
print(a.shape)
print(b.shape)
print(a.dtype)
print(b)
# 运行结果:
(3,)
(3, 3)
int32
[[ 1 2 3]
[ 4 10 6]
[ 7 8 9]]
结构数组:
import numpy as np
persontype = np.dtype({
'names':['name', 'age', 'chinese', 'math', 'english'],
'formats':['S32','i', 'i', 'i', 'f']})
peoples = np.array([("ZhangFei",32,75,100, 90),("GuanYu",24,85,96,88.5),
("ZhaoYun",28,85,92,96.5),("HuangZhong",29,65,85,100)],
dtype=persontype)
ages = peoples['age']
chineses = peoples['chinese']
maths = peoples['math']
englishs = peoples['english']
print(np.mean(ages))
print(np.mean(chineses))
print(np.mean(maths))
print(np.mean(englishs))
# 运行结果
28.25
77.5
93.25
93.75
答疑 :定义结构数组中的 S32 代表什么意思?
这里实际上用的是 numpy 中的字符编码来表示数据类型的定义,比如 i 代表整数,f 代表单精度浮点数,S 代表字符串,S32 代表的是 32 个字符的字符串。
# 如果数据中使用了中文,可以把类型设置为 U32,比如:
import numpy as np
persontype = np.dtype({
'names':['name', 'age', 'chinese', 'math', 'english'],
'formats':['U32','i', 'i', 'i', 'f']})
peoples = np.array([(" 张飞 ",32,75,100, 90),(" 关羽 ",24,85,96,88.5), (" 赵云 ",28,85,92,96.5),(" 黄忠 ",29,65,85,100)], dtype=persontype)
ufunc运算:
连续数组的创建:
x1 = np.arange(1,11,2) # 初始值、终值、步长
x2 = np.linspace(1,9,5) # 初始值、终值、元素个数
算数运算:
x1 = np.arange(1,11,2)
x2 = np.linspace(1,9,5)
print(np.add(x1, x2)) # 加
print(np.subtract(x1, x2)) # 减
print(np.multiply(x1, x2)) # 乘
print(np.divide(x1, x2)) # 除
print(np.power(x1, x2)) # 幂
print(np.remainder(x1, x2)) # 取余
# 运行结果:
[ 2. 6. 10. 14. 18.]
[0. 0. 0. 0. 0.]
[ 1. 9. 25. 49. 81.]
[1. 1. 1. 1. 1.]
[1.00000000e+00 2.70000000e+01 3.12500000e+03 8.23543000e+05
3.87420489e+08]
[0. 0. 0. 0. 0.]
统计函数:
import numpy as np
a = np.array([[1,2,3], [4,5,6], [7,8,9]])
print(np.min(a)) # 全部元素的最小值
print(np.min(a,0)) # 竖轴方向的最小值
print(np.min(a,1)) # 横轴方向的最小值
print(np.max(a))
print(np.max(a,0))
print(np.max(a,1))
# 运行结果:
1
[1 2 3]
[1 4 7]
9
[7 8 9]
[3 6 9]
数组中最大值与最小值的差:
a = np.array([[1,2,3], [4,5,6], [7,8,9]])
print(np.ptp(a)) # 全部元素最大值和最小值的差
print(np.ptp(a,0)) # 竖轴方向最大值和最小值的差
print(np.ptp(a,1)) # 横轴方向最大值和最小值的差
# 运行结果:
8
[6 6 6]
[2 2 2]
统计数组的百分位数 percentile()
a = np.array([[1,2,3], [4,5,6], [7,8,9]])
print(np.percentile(a, 50)) # 所有元素中第50%位元素
print(np.percentile(a, 50, axis=0)) # 竖轴方向第50%位元素
print(np.percentile(a, 50, axis=1)) # 横轴方向第50%位元素
# 输出结果:
5.0
[4. 5. 6.]
[2. 5. 8.]
统计数组中的加权平均值 average()
a = np.array([1,2,3,4])
wts = np.array([1,2,3,4])
print(np.average(a))
print(np.average(a,weights=wts))
# 输出结果:
2.5
3.0
加权平均的意思就是每个元素可以设置个权重,默认情况下每个元素的权重是相同的,所以 np.average(a)=(1+2+3+4)/4=2.5,
你也可以指定权重数组 wts=[1,2,3,4],这样加权平均 np.average(a,weights=wts)=(1*1+2*2+3*3+4*4)/(1+2+3+4)=3.0
统计数组中的标准差 std()、方差 var()
a = np.array([1,2,3,4])
print(np.std(a))
print(np.var(a))
# 输出结果:
1.118033988749895
1.25
方差的计算是指每个数值与平均值之差的平方求和的平均值,标准差是方差的算术平方根。在数学意义上,代表的是一组数据离平均值的分散程度。
NumPy 排序
a = np.array([[4,3,2],[2,4,1]])
print(np.sort(a)) # 默认横轴方向升序
print(np.sort(a, axis=None)) # 降维+升序
print(np.sort(a, axis=0)) # 竖轴方向升序
print(np.sort(a, axis=1)) # 横轴方向升序
# 运行结果:
[[2 3 4]
[1 2 4]]
[1 2 2 3 4 4]
[[2 3 1]
[4 4 2]]
[[2 3 4]
[1 2 4]]
sort(a, axis=-1, kind=‘quicksort’, order=None),默认情况下使用的是快速排序;在 kind 里,可以指定quicksort、mergesort、heapsort
分别表示快速排序、合并排序、堆排序。同样 axis 默认是 -1,即沿着数组的最后一个轴进行排序,也可以取不同的 axis 轴,或者 axis=None
代表采用扁平化的方式作为一个向量进行排序。另外 order 字段,对于结构化的数组可以指定按照某个字段进行排序。
练习题:
假设一个团队里有 5 名学员,成绩如下表所示。你可以用 NumPy 统计下这些人在语文、英语、数学中的平均成绩、最小成绩、最大成绩、方差、标准差。然后把这些人的总成绩排序,得出名次进行成绩输出。
persontype = np.dtype({
'names':['name', 'chinese','english','math' ],
'formats':['S32', 'i', 'i', 'i']})
peoples = np.array([("ZhangFei",66,65,30),("GuanYu",95,85,98),
("ZhaoYun",93,92,96),("HuangZhong",90,88,77),
("DianWei",80,90,90)],dtype=persontype)
name = peoples['name']
chinese = peoples['chinese']
english = peoples['english']
math = peoples['math']
#定义函数用于显示每一排的内容
def show(name,cj):
print('{} | {} | {} | {} | {} | {} '
.format(name,np.mean(cj),np.min(cj),np.max(cj),np.var(cj),np.std(cj)))
print("科目 | 平均成绩 | 最小成绩 | 最大成绩 | 方差 | 标准差")
show("语文", chinese)
show("英语", english)
show("数学", math)
print("排名:")
ranking = sorted(peoples,key=lambda x:x[1]+x[2]+x[3])
print(ranking) # 默认升序