NumPy教程3
本文最后更新于47 天前,其中的信息可能已经过时,如有错误请发送邮件到2031853749@qq.com

NumPy 统计函数

NumPy 提供了很多统计函数, 用于从数组中查找最小元素, 最大元素, 百分位标准差和方差等.

最小值和最大值

numpy.amin() 用于计算数组中的元素沿指定轴的最小值.

numpy.amin(a, axis=None, out=None, keepdims=<no value>, initial=<no value>, where=<no value>)
参数描述
a输入的数组, 可以是一个NumPy数组或类似数组的对象
axis可选参数, 用于指定在哪个轴上计算最小值. 如果不提供此参数, 则返回整个数组的最小值. 可以是一个整数表示轴的索引, 也可以是一个元组表示多个轴
out可选参数, 用于指定结果的存储位置
keepdims可选参数, 如果为True, 将保持结果数组的维度数目与输入数组相同. 如果为False(默认值), 则会去除计算后维度为1的轴
initial可选参数, 用于指定一个初始值, 然后在数组的元素上计算最小值
where可选参数, 一个布尔数组, 用于指定仅考虑满足条件的元素

numpy.amax() 用于计算数组中的元素沿指定轴的最大值.

numpy.amax(a, axis=None, out=None, keepdims=<no value>, initial=<no value>, where=<no value>)
参数描述
a输入的数组, 可以是一个NumPy数组或类似数组的对象
axis可选参数, 用于指定在哪个轴上计算最大值. 如果不提供此参数, 则返回整个数组的最大值. 可以是一个整数表示轴的索引, 也可以是一个元组表示多个轴
out可选参数, 用于指定结果的存储位置
keepdims可选参数, 如果为True, 将保持结果数组的维度数目与输入数组相同. 如果为False(默认值), 则会去除计算后维度为1的轴
initial可选参数, 用于指定一个初始值, 然后在数组的元素上计算最大值
where可选参数, 一个布尔数组, 用于指定仅考虑满足条件的元素
import numpy as np   
a = np.array([[3,7,5],[8,4,3],[2,4,9]])   
print ('数组是: ') 
print (a) 
print ('\n') 
print ('调用 amin() 函数: ') 
print (np.amin(a,1)) 
print ('\n') 
print ('再次调用 amin() 函数: ') 
print (np.amin(a,0)) 
print ('\n') 
print ('调用 amax() 函数: ') 
print (np.amax(a)) 
print ('\n') 
print ('再次调用 amax() 函数: ') 
print (np.amax(a, axis =  0))

输出:

数组是: 
[[3 7 5]
 [8 4 3]
 [2 4 9]]


调用 amin() 函数: 
[3 3 2]


再次调用 amin() 函数: 
[2 4 3]


调用 amax() 函数: 
9


再次调用 amax() 函数: 
[8 7 9]

极差

numpy.ptp()函数计算数组中元素最大值与最小值的差(极差).

numpy.ptp(a, axis=None, out=None, keepdims=<no value>, initial=<no value>, where=<no value>)
参数描述
a输入的数组, 可以是一个NumPy数组或类似数组的对象
axis可选参数, 用于指定在哪个轴上计算峰-峰值. 如果不提供此参数, 则返回整个数组的峰-峰值. 可以是一个整数表示轴的索引, 也可以是一个元组表示多个轴
out可选参数, 用于指定结果的存储位置
keepdims可选参数, 如果为True, 将保持结果数组的维度数目与输入数组相同. 如果为False(默认值), 则会去除计算后维度为1的轴
initial可选参数, 用于指定一个初始值, 然后在数组的元素上计算峰-峰值
where可选参数, 一个布尔数组, 用于指定仅考虑满足条件的元素
import numpy as np   
a = np.array([[3,7,5],[8,4,3],[2,4,9]])   
print ('我们的数组是: ') 
print (a) 
print ('\n') 
print ('调用 ptp() 函数: ') 
print (np.ptp(a)) 
print ('\n') 
print ('沿轴 1 调用 ptp() 函数: ') 
print (np.ptp(a, axis =  1)) 
print ('\n') 
print ('沿轴 0 调用 ptp() 函数: ') 
print (np.ptp(a, axis =  0))

输出:

我们的数组是: 
[[3 7 5]
 [8 4 3]
 [2 4 9]]


调用 ptp() 函数: 
7


沿轴 1 调用 ptp() 函数: 
[4 5 7]


沿轴 0 调用 ptp() 函数: 
[6 3 6]

百分位数

百分位数是统计中使用的度量, 表示小于这个值的观察值的百分比. 函数numpy.percentile()接受以下参数.

numpy.percentile(a, q, axis)

a为输入数组, q为要计算的百分位数, 在 0 ~ 100 之间. axis:为沿着它计算百分位数的轴.

**首先明确百分位数: **

第 p 个百分位数是这样一个值, 它使得至少有 p% 的数据项小于或等于这个值, 且至少有 (100-p)% 的数据项大于或等于这个值.

定义: 第 $p$ 百分位数( $0 < p < 100$ )是一个值,它将一组按升序排列的数据划分为两部分: 大约 $p\%$ 的数据小于或等于该值, 而 $(100 – p)\%$ 的数据大于该值.

例如第 25 百分位数(也称为第一四分位数, $Q_1$)意味着约25% 的数据小于或等于这个值; 第 50 百分位数(即中位数)表示约 50% 的数据小于或等于它; 第 75 百分位数(第三四分位数, $Q_3$)则表示约 75% 的数据小于或等于该值.

import numpy as np   
a = np.array([[10, 7, 4], [3, 2, 1]]) 
print ('我们的数组是: ') 
print (a)  
print ('调用 percentile() 函数: ') 
# 50% 的分位数, 就是 a 里排序之后的中位数 
print (np.percentile(a, 50))   
# axis 为 0, 在纵列上求 
print (np.percentile(a, 50, axis=0))   
# axis 为 1, 在横行上求 
print (np.percentile(a, 50, axis=1))   
# 保持维度不变 
print (np.percentile(a, 50, axis=1, keepdims=True))

输出结果为:

我们的数组是: 
[[10  7  4]
 [ 3  2  1]]
调用 percentile() 函数: 
3.5
[6.5 4.5 2.5]
[7. 2.]
[[7.]
 [2.]]

中位数

numpy.median()函数用于计算数组 a 中元素的中位数(中值)

numpy.median(a, axis=None, out=None, overwrite_input=False, keepdims=<no value>)
参数描述
a输入的数组, 可以是一个NumPy数组或类似数组的对象
axis可选参数, 用于指定在哪个轴上计算中位数. 如果不提供此参数, 则返回整个数组的中位数. 可以是一个整数表示轴的索引, 也可以是一个元组表示多个轴
out可选参数, 用于指定结果的存储位置
overwrite_input可选参数, 如果为True, 则允许在计算中使用输入数组的内存. 这可能会在某些情况下提高性能, 但可能会修改输入数组的内容.
keepdims可选参数, 如果为True, 将保持结果数组的维度数目与输入数组相同. 如果为False(默认值), 则会去除计算后维度为1的轴
import numpy as np  
a = np.array([[30,65,70],[80,95,10],[50,90,60]])   
print ('我们的数组是: ') 
print (a) 
print ('\n') 
print ('调用 median() 函数: ') 
print (np.median(a)) 
print ('\n') 
print ('沿轴 0 调用 median() 函数: ') 
print (np.median(a, axis =  0)) 
print ('\n') 
print ('沿轴 1 调用 median() 函数: ') 
print (np.median(a, axis =  1))

输出:

我们的数组是: 
[[30 65 70]
 [80 95 10]
 [50 90 60]]


调用 median() 函数: 
65.0


沿轴 0 调用 median() 函数: 
[50. 90. 60.]


沿轴 1 调用 median() 函数: 
[65. 80. 60.]

算术平均数

numpy.mean()函数返回数组中元素的算术平均值, 如果提供了轴, 则沿其计算. 算术平均值是沿轴的元素的总和除以元素的数量.

numpy.mean(a, axis=None, dtype=None, out=None, keepdims=<no value>)
参数描述
a输入的数组, 可以是一个NumPy数组或类似数组的对象
axis可选参数, 用于指定在哪个轴上计算平均值. 如果不提供此参数, 则返回整个数组的平均值. 可以是一个整数表示轴的索引, 也可以是一个元组表示多个轴
dtype可选参数, 用于指定输出的数据类型. 如果不提供, 则根据输入数据的类型选择合适的数据类型
out可选参数, 用于指定结果的存储位置
keepdims可选参数, 如果为True, 将保持结果数组的维度数目与输入数组相同. 如果为False(默认值), 则会去除计算后维度为1的轴
import numpy as np   
a = np.array([[1,2,3],[3,4,5],[4,5,6]])   
print ('数组是: ') 
print (a) 
print ('\n') 
print ('调用 mean() 函数: ') 
print (np.mean(a)) 
print ('\n') 
print ('沿轴 0 调用 mean() 函数: ') 
print (np.mean(a, axis =  0)) 
print ('\n') 
print ('沿轴 1 调用 mean() 函数: ') 
print (np.mean(a, axis =  1))

输出:

数组是: 
[[1 2 3]
 [3 4 5]
 [4 5 6]]


调用 mean() 函数: 
3.6666666666666665


沿轴 0 调用 mean() 函数: 
[2.66666667 3.66666667 4.66666667]


沿轴 1 调用 mean() 函数: 
[2. 4. 5.]

加权平均数

numpy.average() 函数根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值.

该函数可以接受一个轴参数. 如果没有指定轴, 则数组会被展开.

加权平均值即将各数值乘以相应的权数, 然后加总求和得到总体值, 再除以总的单位数.

考虑数组[1,2,3,4]和相应的权重[4,3,2,1], 通过将相应元素的乘积相加, 并将和除以权重的和, 来计算加权平均值.

$ave = \dfrac{14+23+32+41}{4+3+2+1}$

函数语法:

numpy.average(a, axis=None, weights=None, returned=False)
参数说明
a输入的数组, 可以是一个 NumPy 数组或类似数组的对象
axis可选参数, 用于指定在哪个轴上计算加权平均值. 如果不提供此参数, 则计算整个数组的加权平均值. 可以是一个整数表示轴的索引, 也可以是一个元组表示多个轴
weights可选参数, 用于指定对应数据点的权重. 如果不提供权重数组, 则默认为等权重
returned可选参数, 如果为True, 将同时返回加权平均值和权重总和.
import numpy as np   
a = np.array([1,2,3,4])   
print ('我们的数组是: ') 
print (a) 
print ('\n') 
print ('调用 average() 函数: ') 
print (np.average(a)) 
print ('\n') 
# 不指定权重时相当于 mean 函数 
wts = np.array([4,3,2,1])   
print ('再次调用 average() 函数: ') 
print (np.average(a,weights = wts)) 
print ('\n') 
# 如果 returned 参数设为 true, 则返回权重的和   
print ('权重的和: ') 
print (np.average([1,2,3,  4],weights =  [4,3,2,1], returned =  True))

输出:

我们的数组是: 
[1 2 3 4]


调用 average() 函数: 
2.5


再次调用 average() 函数: 
2.0


权重的和: 
(2.0, 10.0)

在多维数组中, 可以指定用于计算的轴.

import numpy as np   
a = np.arange(6).reshape(3,2)   
print ('我们的数组是: ') 
print (a) 
print ('\n') 
print ('修改后的数组: ') 
wt = np.array([3,5])   
print (np.average(a, axis =  1, weights = wt)) 
print ('\n') 
print ('修改后的数组: ') 
print (np.average(a, axis =  1, weights = wt, returned =  True))

输出:

我们的数组是: 
[[0 1]
 [2 3]
 [4 5]]


修改后的数组: 
[0.625 2.625 4.625]


修改后的数组: 
(array([0.625, 2.625, 4.625]), array([8., 8., 8.]))

标准差

标准差是一组数据平均值分散程度的一种度量. 标准差是方差的算术平方根.

标准差公式如下:

std = sqrt(mean((x - x.mean())**2))

如果数组是 [1, 2, 3, 4], 则其平均值为 2.5. 因此, 差的平方是 [2.25,0.25,0.25,2.25], 并且再求其平均值的平方根除以 4, 即 sqrt(5/4) , 结果为 1.1180339887498949.

import numpy as np   
print (np.std([1,2,3,4]))
#输出1.1180339887498949

方差

统计中的方差(样本方差)是每个样本值与全体样本值的平均数之差的平方值的平均数, 即

var = mean((x - x.mean())** 2) 

换句话说, 标准差是方差的平方根.

import numpy as np  
print (np.var([1,2,3,4]))
#输出1.25

NumPy 排序、条件筛选函数

NumPy 提供了多种排序的方法.

这些排序函数实现不同的排序算法, 每个排序算法的特征在于执行速度, 最坏情况性能, 所需的工作空间和算法的稳定性. 下表显示了三种排序算法的比较.

种类速度最坏情况工作空间稳定性
'quicksort'(快速排序)1O(n^2)0
'mergesort'(归并排序)2O(n*log(n))~n/2
'heapsort'(堆排序)3O(n*log(n))0

numpy.sort()

numpy.sort()函数返回输入数组的排序副本. 函数格式如下:

numpy.sort(a, axis, kind, order)

参数说明:

  • a: 要排序的数组
  • axis: 沿着它排序数组的轴, 如果没有数组会被展开, 沿着最后的轴排序, axis=0 按列排序, axis=1 按行排序
  • kind: 默认为quicksort(快速排序)
  • order: 如果数组包含字段, 则是要排序的字段
import numpy as np    
a = np.array([[3,7],[9,1]])   
print ('数组是: ') 
print (a) 
print ('\n') print ('调用 sort() 函数: ') 
print (np.sort(a)) 
print ('\n') 
print ('按列排序: ') 
print (np.sort(a, axis =  0)) 
print ('\n') 
# 在 sort 函数中排序字段  
dt = np.dtype([('name',  'S10'),('age',  int)])  
a = np.array([("raju",21),("anil",25),("ravi",  17),  ("amar",27)], dtype = dt)  
print ('数组是: ') 
print (a) 
print ('\n') 
print ('按 name 排序: ') 
print (np.sort(a, order =  'name'))

输出结果为:

数组是: 
[[3 7]
 [9 1]]


调用 sort() 函数: 
[[3 7]
 [1 9]]


按列排序: 
[[3 1]
 [9 7]]


数组是: 
[(b'raju', 21) (b'anil', 25) (b'ravi', 17) (b'amar', 27)]


按 name 排序: 
[(b'amar', 27) (b'anil', 25) (b'raju', 21) (b'ravi', 17)]

numpy.argsort()

numpy.argsort()函数返回的是数组值从小到大的索引值.

import numpy as np   
x = np.array([3,  1,  2])   
print ('数组是: ')
print (x) 
print ('\n') 
print ('对 x 调用 argsort() 函数: ') 
y = np.argsort(x)  
print (y) 
print ('\n') 
print ('以排序后的顺序重构原数组: ') 
print (x[y]) 
print ('\n') 
print ('使用循环重构原数组: ') 
for i in y:      
    print (x[i], end=" ")

输出:

我们的数组是: 
[3 1 2]


对 x 调用 argsort() 函数: 
[1 2 0]


以排序后的顺序重构原数组: 
[1 2 3]


使用循环重构原数组

1 2 3

numpy.lexsort()

numpy.lexsort()用于对多个序列进行排序. 把它想象成对电子表格进行排序, 每一列代表一个序列, 排序时优先照顾靠后的列.

numpy.lexsort()函数可以根据多个数组(键)进行排序, 排序时先按照最后一个键进行排序, 如果该键中的元素相等, 则按照倒数第二个键进行排序, 以此类推. 它返回的是一个索引数组, 该数组表示按照指定键排序后原数组元素的索引顺序.

import numpy as np   
nm =  ('raju','anil','ravi','amar')  
dv =  ('f.y.',  's.y.',  's.y.',  'f.y.')  
ind = np.lexsort((dv,nm))   
print ('调用 lexsort() 函数: ')  
print (ind)  
print ('\n')  
print ('使用这个索引来获取排序后的数据: ')  
print ([nm[i]  +  ", "  + dv[i]  for i in ind])

输出:

调用 lexsort() 函数: 
[3 1 0 2]


使用这个索引来获取排序后的数据: 
['amar, f.y.', 'anil, s.y.', 'raju, f.y.', 'ravi, s.y.']

上面传入 np.lexsort 的是一个tuple, 排序时首先排 nm, 顺序为: amar、anil、raju、ravi . 综上排序结果为 [3 1 0 2].

msort、sort_complex、partition、argpartition

函数描述
msort(a)数组按第一个轴排序, 返回排序后的数组副本. np.msort(a) 相等于 np.sort(a, axis=0).
sort_complex(a)对复数按照先实部后虚部的顺序进行排序.
partition(a, kth[, axis, kind, order])指定一个数, 对数组进行分区
argpartition(a, kth[, axis, kind, order])可以通过关键字 kind 指定算法沿着指定轴对数组进行分区

复数排序:

import numpy as np

np_c1 = np.sort_complex([5, 3, 6, 2, 1])
print(np_c1)
np_c2 = np.sort_complex([1 + 2j, 2 - 1j, 3 - 2j, 3 - 3j, 3 + 5j])
'''
array([ 1.+0.j,  2.+0.j,  3.+0.j,  5.+0.j,  6.+0.j])
输出array([ 1.+2.j,  2.-1.j,  3.-3.j,  3.-2.j,  3.+5.j])
'''

partition() 分区排序:

import numpy as np

a = np.array([3, 4, 2, 1])
print(np.partition(a, 3) ) 
# 将数组 a 中所有元素(包括重复元素)从小到大排列, 3 表示的是排序数组索引为 3 的数字, 比该数字小的排在该数字前面, 比该数字大的排在该数字的后面

np.partition(a, (1, 3))
# 小于 1 的在前面, 大于 3 的在后面, 1和3之间的在中间
'''
array([2, 1, 3, 4])
array([1, 2, 3, 4])
'''

找到数组的第 3 小(index=2)的值和第 2 大(index=-2)的值

import numpy as np

arr = np.array([46, 57, 23, 39, 1, 10, 0, 120])
print(arr[np.argpartition(arr, 2)[2]])#输出10
print(arr[np.argpartition(arr, -2)[-2]])#输出57

同时找到第 3 和第 4 小的值. 注意这里, 用 [2,3] 同时将第 3 和第 4 小的排序好, 然后可以分别通过下标 [2] 和 [3] 取得.

print(arr[np.argpartition(arr, [2,3])[2]])#输出10
print(arr[np.argpartition(arr, [2,3])[3]])#输出23

numpy.argmax() 和 numpy.argmin()

numpy.argmax()numpy.argmin()函数分别沿给定轴返回最大和最小元素的索引.

import numpy as np   
a = np.array([[30,40,70],[80,20,10],[50,90,60]])   
print  ('数组是: ')  
print (a) 
print ('\n') 
print ('调用 argmax() 函数: ')  
print (np.argmax(a)) 
print ('\n')  
print ('展开数组: ') 
print (a.flatten())  
print ('\n') 
print ('沿轴 0 的最大值索引: ') 
maxindex = np.argmax(a, axis =  0)   
print (maxindex) 
print ('\n') 
print ('沿轴 1 的最大值索引: ') 
maxindex = np.argmax(a, axis =  1)   
print (maxindex)  
print ('\n')  
print ('调用 argmin() 函数: ')  
minindex = np.argmin(a)  
print (minindex)  
print ('\n') 
print ('展开数组中的最小值: ')  
print (a.flatten()[minindex])  
print ('\n') 
print ('沿轴 0 的最小值索引: ')  
minindex = np.argmin(a, axis =  0)  
print (minindex)  
print ('\n')  
print ('沿轴 1 的最小值索引: ') 
minindex = np.argmin(a, axis =  1)   
print (minindex)

输出:

数组是: 
[[30 40 70]
 [80 20 10]
 [50 90 60]]


调用 argmax() 函数: 
7


展开数组: 
[30 40 70 80 20 10 50 90 60]


沿轴 0 的最大值索引: 
[1 2 0]


沿轴 1 的最大值索引: 
[2 0 1]


调用 argmin() 函数: 
5


展开数组中的最小值: 
10


沿轴 0 的最小值索引: 
[0 1 1]


沿轴 1 的最小值索引: 
[0 2 0]

numpy.nonzero()

numpy.nonzero() 函数返回输入数组中非零元素的索引.

import numpy as np   
a = np.array([[30,40,0],[0,20,10],[50,0,60]])   
print ('数组是: ') 
print (a)
print ('\n') 
print ('调用 nonzero() 函数: ') 
print (np.nonzero (a))

输出:

数组是: 
[[30 40  0]
 [ 0 20 10]
 [50  0 60]]


调用 nonzero() 函数: 
(array([0, 0, 1, 1, 2, 2]), array([0, 1, 1, 2, 0, 2]))

numpy.where()

numpy.where()函数返回输入数组中满足给定条件的元素的索引.

import numpy as np   
x = np.arange(9.).reshape(3,  3)   
print ('数组是: ') 
print (x) 
print ( '大于 3 的元素的索引: ')
y = np.where(x >  3)  
print (y) 
print ('使用这些索引来获取满足条件的元素: ')
print (x[y])

输出:

我们的数组是: 
[[0. 1. 2.]
 [3. 4. 5.]
 [6. 7. 8.]]
大于 3 的元素的索引: 
(array([1, 1, 2, 2, 2]), array([1, 2, 0, 1, 2]))
使用这些索引来获取满足条件的元素: 
[4. 5. 6. 7. 8.]

numpy.extract()

numpy.extract()函数根据某个条件从数组中抽取元素, 返回满条件的元素.

import numpy as np   
x = np.arange(9.).reshape(3,  3)  
print ('数组是: ')
print (x) # 定义条件, 选择偶数元素 
condition = np.mod(x,2)  ==  0  
print ('按元素的条件值: ')
print (condition)
print ('使用条件提取元素: ') 
print (np.extract(condition, x))

输出:

数组是: 
[[0. 1. 2.]
 [3. 4. 5.]
 [6. 7. 8.]]
按元素的条件值: 
[[ True False  True]
 [False  True False]
 [ True False  True]]
使用条件提取元素: 
[0. 2. 4. 6. 8.]

NumPy 字节交换

在几乎所有的机器上, 多字节对象都被存储为连续的字节序列. 字节顺序是跨越多字节的程序对象的存储规则.

  • **大端模式: **指数据的高字节保存在内存的低地址中, 而数据的低字节保存在内存的高地址中, 这样的存储模式有点儿类似于把数据当作字符串顺序处理: 地址由小向大增加, 而数据从高位往低位放;这和我们的阅读习惯一致.
  • **小端模式: **指数据的高字节保存在内存的高地址中, 而数据的低字节保存在内存的低地址中, 这种存储模式将地址的高低和数据位权有效地结合起来, 高地址部分权值高, 低地址部分权值低. numpy.ndarray.byteswap()

numpy.ndarray.byteswap() 函数将 ndarray 中每个元素中的字节进行大小端转换.

import numpy as np   
a = np.array([1,  256,  8755], dtype = np.int16)   
print ('我们的数组是: ') 
print (a) 
print ('以十六进制表示内存中的数据: ') 
print (map(hex,a)) 
# byteswap() 函数通过传入 true 来原地交换  
print ('调用 byteswap() 函数: ') 
print (a.byteswap(True)) 
print ('十六进制形式: ') 
print (map(hex,a)) 
# 我们可以看到字节已经交换了

输出:

我们的数组是: 
[   1  256 8755]
以十六进制表示内存中的数据: 
<map object at 0x104acb400>
调用 byteswap() 函数: 
[  256     1 13090]
十六进制形式: 
<map object at 0x104acb3c8>

NumPy 副本和视图

副本是一个数据的完整的拷贝, 如果我们对副本进行修改, 它不会影响到原始数据, 物理内存不在同一位置.

视图是数据的一个别称或引用, 通过该别称或引用亦便可访问、操作原有数据, 但原有数据不会产生拷贝. 如果我们对视图进行修改, 它会影响到原始数据, 物理内存在同一位置.

**视图一般发生在: **

  • numpy 的切片操作返回原数据的视图.
  • 调用 ndarray 的 view() 函数产生一个视图.

**副本一般发生在: **

  • Python 序列的切片操作, 调用deepCopy()函数.
  • 调用 ndarray 的copy()函数产生一个副本.

无复制

简单的赋值不会创建数组对象的副本. 相反, 它使用原始数组的相同id()来访问它. id()返回 Python 对象的通用标识符, 类似于 C 中的指针.

此外, 一个数组的任何变化都反映在另一个数组上. 例如, 一个数组的形状改变也会改变另一个数组的形状.

import numpy as np   
a = np.arange(6)   
print ('数组是: ') 
print (a) 
print ('调用 id() 函数: ') 
print (id(a)) 
print ('a 赋值给 b: ') 
b = a  
print (b) 
print ('b 拥有相同 id(): ')
print (id(b)) 
print ('修改 b 的形状: ')
b.shape =  3,2  
print (b) 
print ('a 的形状也修改了: ') 
print (a)

输出:

数组是: 
[0 1 2 3 4 5]
调用 id() 函数: 
4349302224
a 赋值给 b: 
[0 1 2 3 4 5]
b 拥有相同 id(): 
4349302224
修改 b 的形状: 
[[0 1]
 [2 3]
 [4 5]]
a 的形状也修改了: 
[[0 1]
 [2 3]
 [4 5]]

视图或浅拷贝

ndarray.view()方会创建一个新的数组对象, 该方法创建的新数组的维数变化不会改变原始数据的维数.

import numpy as np   
# 最开始 a 是个 3X2 的数组 
a = np.arange(6).reshape(3,2)   
print ('数组 a: ') 
print (a) 
print ('创建 a 的视图: ') 
b = a.view()   
print (b) 
print ('两个数组的 id() 不同: ') 
print ('a 的 id(): ') 
print (id(a))
print ('b 的 id(): ' ) 
print (id(b)) 
# 修改 b 的形状, 并不会修改a 
b.shape =  2,3 
print ('b 的形状: ') 
print (b) 
print ('a 的形状: ') 
print (a)

输出:

数组 a: 
[[0 1]
 [2 3]
 [4 5]]
创建 a 的视图: 
[[0 1]
 [2 3]
 [4 5]]
两个数组的 id() 不同: 
a 的 id(): 
4314786992
b 的 id(): 
4315171296
b 的形状: 
[[0 1 2]
 [3 4 5]]
a 的形状: 
[[0 1]
 [2 3]
 [4 5]]

使用切片创建视图修改数据会影响到原始数组:

import numpy as np   
arr = np.arange(12) 
print ('我们的数组: ') 
print (arr) 
print ('创建切片: ')
a=arr[3:] 
b=arr[3:] 
a[1]=123 
b[2]=234 
print(arr) 
print(id(a),id(b),id(arr[3:]))

输出:

我们的数组: 
[ 0  1  2  3  4  5  6  7  8  9 10 11]
创建切片: 
[  0   1   2   3 123 234   6   7   8   9  10  11]
4545878416 4545878496 4545878576

变量 a,b 都是 arr 的一部分视图, 对视图的修改会直接反映到原数据中. 但是我们观察 a,b 的 id, 他们是不同的, 也就是说, 视图虽然指向原数据, 但是他们和赋值引用还是有区别的.

副本或深拷贝

ndarray.copy() 函数创建一个副本. 对副本数据进行修改, 不会影响到原始数据, 它们物理内存不在同一位置.

import numpy as np   
a = np.array([[10,10],  [2,3],  [4,5]])   
print ('数组 a: ') 
print (a) 
print ('创建 a 的深层副本: ') 
b = a.copy()   
print ('数组 b: ')
print (b) 
# b 与 a 不共享任何内容  
print ('我们能够写入 b 来写入 a 吗?') 
print (b is a) 
print ('修改 b 的内容: ') 
b[0,0]  =  100  
print ('修改后的数组 b: ') 
print (b)
print ('a 保持不变: ') 
print (a)

输出:

数组 a: 
[[10 10]
 [ 2  3]
 [ 4  5]]
创建 a 的深层副本: 
数组 b: 
[[10 10]
 [ 2  3]
 [ 4  5]]
我们能够写入 b 来写入 a 吗?
False
修改 b 的内容: 
修改后的数组 b: 
[[100  10]
 [  2   3]
 [  4   5]]
a 保持不变: 
[[10 10]
 [ 2  3]
 [ 4  5]]

NumPy 矩阵库(Matrix)

NumPy 中包含了一个矩阵库numpy.matlib, 该模块中的函数返回的是一个矩阵, 而不是 ndarray 对象.

一个 $m\times n$的矩阵是一个由$m$行(row)$n$列(column)元素排列成的矩形阵列.

矩阵里的元素可以是数字、符号或数学式.

转置矩阵

NumPy 中除了可以使用numpy.transpose 函数来对换数组的维度, 还可以使用 $T$ 属性.

例如有个$m$行$n$列的矩阵, 使用 t()函数就能转换为 n 行 m 列的矩阵.
$$
(\boldsymbol{A}^T)^T=A
$$

$$
\begin{pmatrix}
1\quad2\\3\quad4\\5\quad6
\end{pmatrix}^T=
\begin{pmatrix}
1\quad3\quad5\\2\quad4\quad6
\end{pmatrix}
$$

import numpy as np 
a = np.arange(12).reshape(3,4)  
print ('原数组: ') 
print (a) 
print ('\n')  
print ('转置数组: ') 
print (a.T)

输出:

原数组: 
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]


转置数组: 
[[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]]

matlib.empty()

matlib.empty() 函数返回一个新的矩阵, 语法格式为:

numpy.matlib.empty(shape, dtype, order)

shape为定义新矩阵形状的整数或整数元组.dtype可选, 数据类型.order为 C( 行序优先 ) 或者 F(列序优先)

import numpy.matlib  
import numpy as np 
print (np.matlib.empty((2,2))) 
# 填充为随机数据
'''
[[-1.49166815e-154 -1.49166815e-154]
 [ 2.17371491e-313  2.52720790e-212]]
'''

numpy.matlib.zeros()

numpy.matlib.zeros()函数创建一个以 0 填充的矩阵.

import numpy.matlib  
import numpy as np  
print (np.matlib.zeros((2,2)))
'''
[[0. 0.]
 [0. 0.]]
'''

numpy.matlib.ones()

numpy.matlib.ones()函数创建一个以 1 填充的矩阵.

import numpy.matlib  
import numpy as np   
print (np.matlib.ones((2,2)))
'''
[[1. 1.]
 [1. 1.]]
'''

numpy.matlib.eye()

numpy.matlib.eye()函数返回一个矩阵, 对角线元素为 1, 其他位置为零.

numpy.matlib.eye(n, M,k, dtype)

n为返回矩阵的行数.M为返回矩阵的列数, 默认为 n.k为对角线的索引.dtype为数据类型.

import numpy.matlib  
import numpy as np  
print (np.matlib.eye(n =  3, M =  4, k =  0, dtype =  float))
'''
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]]
'''

numpy.matlib.identity()

numpy.matlib.identity()函数返回给定大小的单位矩阵.

单位矩阵是个方阵, 从左上角到右下角的对角线( 称为主对角线) 上的元素均为 1, 除此以外全都为 0.
$$
I_1=\begin{pmatrix}
1
\end{pmatrix},
I_2=\begin{pmatrix}
1 & 0\\
0 & 1\
\end{pmatrix},
I_3=\begin{pmatrix}
1\quad0\quad0\\
0\quad1\quad0\\
0\quad0\quad1
\end{pmatrix},
\cdots,
I_n=\begin{pmatrix}
1 & 0 & \cdots & 0 \\
0 & 1 & \cdots & 0 \\
\vdots & \vdots & \ddots & \vdots \\
0 & 0 & \cdots & 1
\end{pmatrix}
$$

import numpy.matlib  
import numpy as np   
# 大小为 5, 类型位浮点型 
print (np.matlib.identity(5, dtype =  float))

输出:

[[ 1.  0.  0.  0.  0.] 
 [ 0.  1.  0.  0.  0.] 
 [ 0.  0.  1.  0.  0.] 
 [ 0.  0.  0.  1.  0.] 
 [ 0.  0.  0.  0.  1.]]

numpy.matlib.rand()

numpy.matlib.rand()函数创建一个给定大小的矩阵, 数据是随机填充的.

import numpy.matlib  
import numpy as np  
print (np.matlib.rand(3,3))
'''
[[0.23966718 0.16147628 0.14162   ]
 [0.28379085 0.59934741 0.62985825]
 [0.99527238 0.11137883 0.41105367]]
'''

矩阵总是二维的, 而 ndarray 是一个 n 维数组. 两个对象都是可互换的.

import numpy.matlib  
import numpy as np    
i = np.matrix('1,2;3,4')   
print (i)
'''
[[1  2] 
 [3  4]]
'''
import numpy.matlib  
import numpy as np    
j = np.asarray(i)   
print (j)
'''
[[1  2] 
 [3  4]]
'''
import numpy.matlib  
import numpy as np    
k = np.asmatrix (j)  
print (k)
'''
[[1  2] 
 [3  4]]
'''

NumPy 线性代数

NumPy 提供了线性代数函数库 linalg, 该库包含了线性代数所需的所有功能, 可以看看下面的说明:

函数描述
dot两个数组的点积, 即元素对应相乘.
vdot两个向量的点积
inner两个数组的内积
matmul两个数组的矩阵积
determinant数组的行列式
solve求解线性矩阵方程
inv计算矩阵的乘法逆矩阵

numpy.dot()

numpy.dot()对于两个一维的数组, 计算的是这两个数组对应下标元素的乘积和(数学上称之为向量点积);

对于二维数组, 计算的是两个数组的矩阵乘积;

对于多维数组, 它的通用计算公式如下, 即结果数组中的每个元素都是数组a的最后一维上的所有元素与数组b的倒数第二位上的所有元素的乘积和 ( 通常遵循广播规则 ):

dot(a, b)[i,j,k,m] = sum(a[i,j,:] * b[k,:,m]).

numpy.dot(a, b, out=None) 

ab都是 ndarray 数组. out是ndarray对象, 可选, 用来保存dot()的计算结果.

import numpy.matlib 
import numpy as np  
a = np.array([[1,2],[3,4]]) 
b = np.array([[11,12],[13,14]]) 
print(np.dot(a,b))
'''
[[37  40] 
 [85  92]]
'''

计算式为:
$$
\begin{pmatrix}1\quad2\\3\quad4 \end{pmatrix}\cdot\begin{pmatrix}11\quad12\\13\quad14 \end{pmatrix}=\begin{pmatrix}1\times11+2\times13\quad1\times12+2\times14\\3\times11+4\times13\quad3\times12+4\times14 \end{pmatrix}=\begin{pmatrix}37\quad40\\85\quad92 \end{pmatrix}
$$

numpy.vdot()

numpy.vdot()函数是两个向量的点积. 如果第一个参数是复数, 那么它的共轭复数会用于计算. 如果参数是多维数组, 它会被展开.

import numpy as np   
a = np.array([[1,2],[3,4]])  
b = np.array([[11,12],[13,14]])   
# vdot 将数组展开计算内积 
print (np.vdot(a,b)) #130

计算式为:
$$
1\times11 + 2\times12 + 3\times13 + 4\times14 = 130
$$

numpy.inner()

numpy.inner()函数返回一维数组的向量内积. 对于更高的维度, 它返回最后一个轴上的和的乘积.

import numpy as np   
print (np.inner(np.array([1,2,3]),np.array([0,1,0]))) 
# 输出2
# 等价于 1*0+2*1+3*0

多维数组:

import numpy as np 
a = np.array([[1,2], [3,4]])   
print ('数组 a: ') 
print (a) 
b = np.array([[11, 12], [13, 14]])  
print ('数组 b: ') 
print (b) 
print ('内积: ') 
print (np.inner(a,b))

输出:

数组 a: 
[[1 2]
 [3 4]]
数组 b: 
[[11 12]
 [13 14]]
内积: 
[[35 41]
 [81 95]]
数组 a: 
[[1 2]
 [3 4]]
数组 b: 
[[11 12]
 [13 14]]
内积: 
[[35 41]
 [81 95]]

numpy.matmul

numpy.matmul函数返回两个数组的矩阵乘积. 虽然它返回二维数组的正常乘积, 但如果任一参数的维数大于2, 则将其视为存在于最后两个索引的矩阵的栈, 并进行相应广播.

另一方面, 如果任一参数是一维数组, 则通过在其维度上附加 1 来将其提升为矩阵, 并在乘法之后被去除.

对于二维数组, 它就是矩阵乘法:

import numpy.matlib  
import numpy as np   
a = [[1,0],[0,1]]  
b = [[4,1],[2,2]]  
print (np.matmul(a,b))
'''
[[4  1] 
 [2  2]]
'''

二维和一维运算:

import numpy.matlib  
import numpy as np  
a = [[1,0],[0,1]]  
b = [1,2]  
print (np.matmul(a,b)) #输出[1  2]
print (np.matmul(b,a)) #输出[1  2] 

维度大于二的数组 :

import numpy.matlib  
import numpy as np   
a = np.arange(8).reshape(2,2,2)  
b = np.arange(4).reshape(2,2)  
print (np.matmul(a,b))
'''
[[[ 2  3]
  [ 6 11]]

 [[10 19]
  [14 27]]]
'''

numpy.linalg.det()

numpy.linalg.det()函数计算输入矩阵的行列式.

行列式在线性代数中是非常有用的值. 具体的计算请参照线性代数教材.

import numpy as np 
a = np.array([[1,2], [3,4]])   
print (np.linalg.det(a))
#输出-2.0
import numpy as np  
b = np.array([[6,1,1], [4, -2, 5], [2,8,7]])  
print (b) 
print (np.linalg.det(b)) 
print (6*(-2*7 - 5*8) - 1*(4*7 - 5*2) + 1*(4*8 - -2*2))

输出:

[[ 6  1  1]
 [ 4 -2  5]
 [ 2  8  7]]
-306.0
-306

numpy.linalg.solve()

numpy.linalg.solve()函数给出了矩阵形式的线性方程的解.

考虑以下线性方程:
$$
\begin{cases}
x + y + z &= 6\\
2y + 5z &= -4\\
2x + 5y – z &= 27
\end{cases}
$$
可以使用矩阵表示为:
$$
\begin{pmatrix}1 & 1 & 1 \\
0 & 2 & 5 \\
2 & 5 & -1\end{pmatrix}\begin{pmatrix}x\\y\\z\end{pmatrix}=\begin{pmatrix}6\\-1\\27 \end{pmatrix}
$$
写成矩阵形式, 方程变为:
$$
\boldsymbol{AX=B}
$$

import numpy as np
A = np.array([[3, 1], [1, 2]])
b = np.array([9, 8])

# 求解线性方程组
x = np.linalg.solve(A, b)
print(x)
#输出[2. 3.]

numpy.linalg.inv()

numpy.linalg.inv()函数计算矩阵的乘法逆矩阵.

逆矩阵(inverse matrix): 设$\boldsymbol{A}$是数域上的一个$n$阶矩阵, 若在相同数域上存在另一个$n$阶矩阵$\boldsymbol{B}$, 使得$\boldsymbol{AB=BA=E}$ , 则我们称$\boldsymbol{B}$是$\boldsymbol{B}$的逆矩阵, 而$\boldsymbol{A}$则被称为可逆矩阵.

则$\boldsymbol{AX=B}$可以写为$\boldsymbol{X=A^{-1}B}$

import numpy as np   
x = np.array([[1,2],[3,4]])  
y = np.linalg.inv(x)  
print (x) 
print (y) 
print (np.dot(x,y))

输出:

[[1 2]
 [3 4]]
[[-2.   1. ]
 [ 1.5 -0.5]]
[[1.0000000e+00 0.0000000e+00]
 [8.8817842e-16 1.0000000e+00]]

现在创建一个矩阵A的逆矩阵:

import numpy as np   
a = np.array([[1,1,1],[0,2,5],[2,5,-1]])   
print ('数组 a: ') 
print (a) 
ainv = np.linalg.inv(a)   
print ('a 的逆: ') 
print (ainv)  
print ('矩阵 b: ') 
b = np.array([[6],[-4],[27]])  
print (b)  
print ('计算: A^(-1)B: ') 
x = np.linalg.solve(a,b)  
print (x) # 这就是线性方程的解
y = np.dot(ainv,b)
print(y)

输出:

数组 a: 
[[ 1  1  1]
 [ 0  2  5]
 [ 2  5 -1]]
a 的逆: 
[[ 1.28571429 -0.28571429 -0.14285714]
 [-0.47619048  0.14285714  0.23809524]
 [ 0.19047619  0.14285714 -0.0952381 ]]
矩阵 b: 
[[ 6]
 [-4]
 [27]]
计算: A^(-1)B: 
[[ 5.]
 [ 3.]
 [-2.]]
[[ 5.]
 [ 3.]
 [-2.]]

NumPy IO

Numpy 可以读写磁盘上的文本数据或二进制数据. NumPy 为 ndarray 对象引入了一个简单的文件格式: npy.

npy 文件用于存储重建 ndarray 所需的数据、图形、dtype 和其他信息.

常用的 IO 函数有:

  • load()save()函数是读写文件数组数据的两个主要函数, 默认情况下, 数组是以未压缩的原始二进制格式保存在扩展名为 .npy 的文件中.
  • savez()函数用于将多个数组写入文件, 默认情况下, 数组是以未压缩的原始二进制格式保存在扩展名为 .npz 的文件中.
  • loadtxt()savetxt()函数处理正常的文本文件(.txt 等)

numpy.save()

numpy.save()函数将数组保存到以.npy 为扩展名的文件中.

numpy.save(file, arr, allow_pickle=True)
  • file: 要保存的文件, 扩展名为 .npy, 如果文件路径末尾没有扩展名.npy, 该扩展名会被自动加上.
  • arr: 要保存的数组.
  • allow_pickle: 可选, 布尔值, 允许使用 Python pickles 保存对象数组, Python 中的 pickle 用于在保存到磁盘文件或从磁盘文件读取之前, 对对象进行序列化和反序列化.
import numpy as np   
a = np.array([1,2,3,4,5])   # 保存到 outfile.npy 文件上 
np.save('outfile.npy',a)   # 保存到 outfile2.npy 文件上, 如果文件路径末尾没有扩展名 .npy, 该扩展名会被自动加上 
np.save('outfile2',a)

我们可以查看文件内容:

$ cat outfile.npy 
?NUMPYv{'descr': '<i8', 'fortran_order': False, 'shape': (5,), }  
$ cat outfile2.npy 
?NUMPYv{'descr': '<i8', 'fortran_order': False, 'shape': (5,), } 

可以看出文件是乱码的, 因为它们是 Numpy 专用的二进制格式后的数据.

我们可以使用 load() 函数来读取数据就可以正常显示了:

import numpy as np   
b = np.load('outfile.npy')   
print (b)
#输出[1 2 3 4 5]

np.savez

numpy.savez()函数将多个数组保存到以 npz 为扩展名的文件中.

numpy.savez(file, *args, **kwds)
  • file: 要保存的文件, 扩展名为 .npz, 如果文件路径末尾没有扩展名 `.npz, 该扩展名会被自动加上.
  • args: 要保存的数组, 可以使用关键字参数为数组起一个名字, 非关键字参数传递的数组会自动起名为 arr_0, arr_1
  • kwds: 要保存的数组使用关键字名称.
import numpy as np   
a = np.array([[1,2,3],[4,5,6]]) 
b = np.arange(0, 1.0, 0.1) 
c = np.sin(b) 
# c使用了关键字参数sin_array 
np.savez("runoob.npz", a, b, sin_array = c) 
r = np.load("runoob.npz")   
print(r.files)
# 查看各个数组名称 
print(r["arr_0"]) # 数组 a
print(r["arr_1"]) # 数组 b 
print(r["sin_array"]) # 数组 c

输出:

['sin_array', 'arr_0', 'arr_1']
[[1 2 3]
 [4 5 6]]
[0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]
[0.         0.09983342 0.19866933 0.29552021 0.38941834 0.47942554
 0.56464247 0.64421769 0.71735609 0.78332691]

savetxt()

savetxt() 函数是以简单的文本文件格式存储数据, 对应的使用 loadtxt() 函数来获取数据.

np.loadtxt(FILENAME, dtype=int, delimiter=' ')
np.savetxt(FILENAME, a, fmt="%d", delimiter=",")

参数 delimiter 可以指定各种分隔符、针对特定列的转换器函数、需要跳过的行数等.

import numpy as np   
a = np.array([1,2,3,4,5])  
np.savetxt('out.txt',a)  
b = np.loadtxt('out.txt')    
print(b)
#输出[1. 2. 3. 4. 5.]

使用 delimiter 参数:

import numpy as np    
a=np.arange(0,10,0.5).reshape(4,-1) 
np.savetxt("out.txt",a,fmt="%d",delimiter=",") # 改为保存为整数, 以逗号分隔
b = np.loadtxt("out.txt",delimiter=",") # load 时也要指定为逗号分隔 
print(b)

输出:

[[0. 0. 1. 1. 2.]
 [2. 3. 3. 4. 4.]
 [5. 5. 6. 6. 7.]
 [7. 8. 8. 9. 9.]]

NumPy Matplotlib

Matplotlib 是 Python 的绘图库. 它可与 NumPy 一起使用, 提供了一种有效的 MatLab 开源替代方案. 它也可以和图形工具包一起使用, 如 PyQt 和 wxPython.

pip安装:

pip install matplotlib

安装完后, 你可以使用 python -m pip list 命令来查看是否安装了 matplotlib 模块.

$ pip3 list | grep matplotlib
matplotlib        3.3.0  

之后我们也会介绍Matplotlib

本文为2305拾柒原创.
文章作者:拾 柒
文章链接:NumPy教程3
版权声明:本博客所有文章除特别声明外,均采用CC BY-NC-SA 4.0许可协议. 转载请注明来自拾 柒
如果觉得有用,可以分享出去~
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇