1. 什么是 NumPy?
- NumPy是一个功能强大的Python库,主要用于对多维数组执行计算。NumPy这个词来源于两个单词-- Numerical和Python.NumPy提供了大量的库函数和操作,可以帮助程序员轻松地进行数值计算。这类数值计算广泛用于以下任务:
- 机器学习模型:在编写机器学习算法时,需要对矩阵进行各种数值计算。例如矩阵乘法、换位、加法等。NumPy提供了一个非常好的库,用于简单(在编写代码方面)和快速(在速度方面)计算。NumPy数组用于存储训练数据和机器学习模型的参数。
- 图像处理和计算机图形学:计算机中的图像表示为多维数字数组。NumPy成为同样情况下最自然的选择。实际上,NumPy提供了一些优秀的库函数来快速处理图像。例如,镜像图像、按特定角度旋转图像等。
- 数学任务:NumPy对于执行各种数学任务非常有用,如数值积分、微分、内插、外推等。因此,当涉及到数学任务时,它形成了一种基于Python的MATLAB的快速替代。
2. 我们为什么要掌握NumPy
- 人们有时会说,与C++这种低级语言相比,Python以运行速度为代价改善了开发时间和效率。幸运的是,有一些方法可以在不牺牲易用性的情况下加速Python中的操作运行时。适用于快速数值运算的一个选项是NumPy,它当之无愧地将自己称为使用Python进行科学计算的基本软件包。
- 通常,矢量化数组操作通常比其纯Python等价物快一个或两个(或更多)数量级,在任何类型的数值计算中都具有最大的影响。
- 在Python中循环数组或任何数据结构时,会涉及很多开销。 NumPy中的向量化操作将内部循环委托给高度优化的C和Fortran函数,从而实现更清晰,更快速的Python代码。
3. NumPy 简单实用
3.1 使用方式¶
可以使用如下的方式来安装numpy库:
pip install numpy
根据惯例,使用numpy库的导入方式为:
import numpy as np
在导入之后,我们可以通过:
np.__version__
来查看Numpyu库的版本信息。
import numpy as np
print(np.__version__)
运行结果
1.16.4
3.2 创建一维NumPy数组
Numpy提供了很多方式(函数)来创建数组对象,常用的方式如下:
- array
- arange
- ones / ones_like
- zeros / zeros_like
- empty / empty_like
- full / full_like
- eye / identity
- linspace
- logspace
# 快速定义一维NumPy数组
a = np.array([0, 1, 2, 3, 4])
b = np.array((0, 1, 2, 3, 4))
c = np.arange(5)
d = np.linspace(0, 2*np.pi, 5)
print(a)
print(b)
print(c)
print(d)
# 创建一个长度为5的NumPy数组,但所有元素都为0
my_new_array_0 = np.zeros((5))
# 创建一个长度为5的NumPy数组,但所有元素都为1
my_new_array_1 = np.ones((5))
# 使用的是随机函数,它为每个元素分配0到1之间的随机值
my_random_array = np.random.random((5))
print (my_new_array_0)
print (my_new_array_1)
print (my_random_array)
运行结果
[0 1 2 3 4]
[0 1 2 3 4]
[0 1 2 3 4]
[0. 1.57079633 3.14159265 4.71238898 6.28318531]
[0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1.]
[0.92576367 0.91505031 0.21331558 0.28572705 0.69022813]
3.3 创建二维NumPy数组
# 使用NumPy创建二维数组
a = np.arange(6).reshape(2,-1)
# print(a.resize((2,3))) ## 就地修改
print(a)
# Create an array of all zeros
a = np.zeros((2,2))
# Create an array of all ones
b = np.ones((1,2))
# Create a constant array
c = np.full((2,2), 999)
# Create a 2x2 identity matrix
d = np.eye(2)
print(a)
print(b)
print(c)
print(d)
运行结果
[[0 1 2]
[3 4 5]]
[[0. 0.]
[0. 0.]]
[[1. 1.]]
[[999 999]
[999 999]]
[[1. 0.]
[0. 1.]]
3.4 数组属性
数组对象具有如下常用属性:
- ndim
- shape
- dtype
- size
- itemsize
- nbytes
- astype
- reshape
- resize
# 数组属性
# Array properties
a = np.array([[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25],
[26, 27, 28 ,29, 30],
[31, 32, 33, 34, 350]])
print(type(a))
print(a.dtype)
print(a.size)
print(a.shape)
# itemsize属性是每个项占用的字节数。
# 如果数据类型是int 64,一个int 64中有64位,一个字节中有8位,除以64除以8,你就可以得到它占用了多少字节,
print(a.itemsize)
print(a.ndim)
# nbytes 属性是数组中的所有数据消耗掉的字节数。
# 你应该注意到,这并不计算数组的开销,因此数组占用的实际空间将稍微大一点。
print(a.nbytes)
运行结果
int32
25
(5, 5)
4
2
100
3.5 修改元素
# 修改一个元素
my_array = np.array([1,2,3,4,5,6])
my_array[0] = -1
print (my_array)
# 修改多个元素(也可以切片,但是我们要改变指定不连续索引的值,就不能使用切片)
my_array[[0,1,2]] = -1
print (my_array)
运行结果
[-1 2 3 4 5 6]
[-1 -1 -1 4 5 6]
3.6 索引
# 多维数组可以用 my_array[i][j] 符号来索引,其中i表示行号,j表示列号
my_array = np.array([[4, 5], [6, 1]])
print (my_array)
print (my_array[0][1])
# print(my_array[1, 2])
# 提取第二列(索引1)的所有元素
my_array_column_2 = my_array[:, 1]
print (my_array_column_2)
# 提取第二行(索引1)的所有元素
my_array_column_2 = my_array[1, :]
print (my_array_column_2)
运行结果
[[4 5]
[6 1]]
5
[5 1]
[6 1]
# 花式索引:是获取数组中我们想要的特定元素的有效方法。
a = np.arange(0, 100, 10)
indices = [1, 5, -1]
b = a[indices]
print(a)
print(b)
运行结果
[ 0 10 20 30 40 50 60 70 80 90]
[10 50 90]
import matplotlib.pyplot as plt
a = np.linspace(0, 2 * np.pi, 50)
b = np.sin(a)
plt.plot(a,b)
# mask = b >= 0
# plt.plot(a[mask], b[mask], 'bo')
mask = (b >= 0) & (a <= np.pi)
plt.plot(a[mask], b[mask], 'go')
plt.show()
运行结果
# 缺省索引
# 不完全索引是从多维数组的第一个维度获取索引或切片的一种方便方法
# Incomplete Indexing
a = np.arange(0, 100, 10)
b = a[:5]
c = a[a >= 50]
print(a)
print(b)
print(c)
运行结果
[ 0 10 20 30 40 50 60 70 80 90]
[ 0 10 20 30 40]
[50 60 70 80 90]
# where() 函数是另外一个根据条件返回数组中的值的有效方法。
# 只需要把条件传递给它,它就会返回一个使得条件为真的元素的索引。
a = np.arange(0, 100, 10)
b = np.where(a < 50)
c = np.where(a >= 50)[0]
print(b)
print(c)
运行结果
(array([0, 1, 2, 3, 4], dtype=int64),)
[5 6 7 8 9]
# 整数数组索引: 使用切片索引到numpy数组时,生成的数组视图将始终是原始数组的子数组。
# 相反,整数数组索引允许你使用另一个数组中的数据构造任意数组。
a = np.array([[1,2,3], [4,5,6], [7,8,9], [10, 11, 12]])
b = np.array([0, 2, 0, 1])
print(a)
print(a[np.arange(4), b])
a[np.arange(4), b] += 10
print(a)
运行结果
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
[ 1 6 7 11]
[[11 2 3]
[ 4 5 16]
[17 8 9]
[10 21 12]]
3.7 切片
数组的切片返回的是原数组数据的视图(回忆:Python中呢? python中,切片是浅拷贝).如果需要复制底层的数组元素,可以使用数组对象的copy方法。
注意:视图是共享底层的数组元素,但视图并不是赋值。
python中,切片是浅拷贝。切片后,原对象改变不会影响切片后的对象,切片后的对象改变会影响原对象.
数组的切片,返回的是视图,原数组改变会影响切片后的数组,但是切片后的数组的元素改变也会影响原数组.
通过数组对象的copy方法,实现底层数据的复制,而不是返回底层数据的视图。数组的 copy 方法对复制前后,互不影响.
# 使用多维数组表示矩阵
# MD Array,
a = np.array([[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(a[2,4])
# 多维数组切片
# MD slicing
print(a[0, 1:4])
print(a[1:4, 0])
print(a[::2,::2])
print(a[:, 1])
运行结果
25
[12 13 14]
[16 21 26]
[[11 13 15]
[21 23 25]
[31 33 35]]
[12 17 22 27 32]
3.8 加减乘除运算
# numpy数组的加减乘除是相应位置的运算,且形状一样。与矩阵的乘法有区别
a = np.array([1.0, 2.0])
b = np.array([3, 4])
sum = a + b
difference = a - b
product = a * b
quotient = a / b
print ("Sum = \n", sum )
print ("Difference = \n", difference )
print ("Product = \n", product )
print ("Quotient = \n", quotient )
# 乘法运算符执行逐元素乘法而不是矩阵乘法。 要执行矩阵乘法,你可以执行以下操作
matrix_product = a.dot(b)
# matrix_product = np.dot(a,b)
print ("Matrix Product = ", matrix_product)
运行结果
Sum =
[4. 6.]
Difference =
[-2. -2.]
Product =
[3. 8.]
Quotient =
[0.33333333 0.5 ]
Matrix Product = 11.0
3.9 比较运算符
# 数组中使用
a = np.array([[0, 1, 2],
[3, 4, 5]])
b = np.array([[0, 2, 2],
[3, 3, 5]])
print(a)
print(b)
# 返回,布尔类型
print(a < b)
print(a == b)
print(a != b)
print(a >= b)
运行结果
[[0 1 2]
[3 4 5]]
[[0 2 2]
[3 3 5]]
[[False True False]
[False False False]]
[[ True False True]
[ True False True]]
[[False True False]
[False True False]]
[[ True False True]
[ True True True]]
3.10 位运算符
a = np.array([True, True, False, False])
b = np.array([True, False, True, False])
print(a & b)
print(a | b)
print(~a)
print(a & True)
print(a & False)
运行结果
[ True False False False]
[ True True True False]
[False False True True]
[ True True False False]
[False False False False]
# 逻辑与
a = np.logical_and([True, False],
[False, False])
print(a)
x = np.arange(5)
y = np.logical_and(x>1, x<4)
print(y) # [False, False, True, True, False]
# 逻辑或
b = np.logical_or([True, False],
[False, False])
print(b) # [ True, False]
x = np.arange(5)
y = np.logical_or(x < 1, x > 3)
print(y) # [ True, False, False, False, True]
# 逻辑非
c = np.logical_not([True, False, 0, 1])
print(c) # [False, True, True, False]
x = np.arange(5)
y = np.logical_not(x<3)
print(y) # [False, False, False, True, True]
# 逻辑异或
d = np.logical_xor([True, True, False, False],
[True, False, True, False])
print(d) # [False, True, True, False], dtype=bool)
x = np.arange(5)
y = np.logical_xor(x < 1, x > 3)
print(y) # [ True, False, False, False, True]
运行结果
[False False]
[False False True True False]
[ True False]
[ True False False False True]
[False True True False]
[False False False True True]
[False True True False]
[ True False False False True]
3.12 数学运算符
# 数组数学函数
# sin, cos, tan
a = np.array([0,30,60,90])
# 通过乘 pi/180 转化为弧度
print ('正弦值',np.sin(a*np.pi/180))
print ('余弦值',np.cos(a*np.pi/180))
print ('正切值',np.tan(a*np.pi/180))
# arcsin,arccos,和 arctan 函数返回给定角度的 sin,cos 和 tan 的反三角函数。
# 通过 numpy.degrees() 函数将弧度转换为角度。
a1 = np.arcsin(np.sin(a*np.pi/180))
print('反正弦:',a1)
print('转化为角度:',np.degrees(a1))
运行结果
正弦值 [0. 0.5 0.8660254 1. ]
余弦值 [1.00000000e+00 8.66025404e-01 5.00000000e-01 6.12323400e-17]
正切值 [0.00000000e+00 5.77350269e-01 1.73205081e+00 1.63312394e+16]
反正弦: [0. 0.52359878 1.04719755 1.57079633]
转化为角度: [ 0. 30. 60. 90.]
# numpy.around(a,decimals)
# 函数返回指定数字的四舍五入值。
# * a: 数组
# * decimals: 舍入的小数位数。 默认值为0。 如果为负,整数将四舍五入到小数点左侧的位置
a = np.array([1.0,5.55, 123, 0.567, 25.532])
print(a)
print(np.around(a, decimals = 1))
print(np.around(a, decimals = -1))
运行结果
[ 1. 5.55 123. 0.567 25.532]
[ 1. 5.6 123. 0.6 25.5]
[ 0. 10. 120. 0. 30.]
# numpy.floor()
# 返回数字的向下取整。
a = np.array([-1.7, 1.5, -0.2, 0.6, 10])
print (a)
print (np.floor(a))
运行结果
[-1.7 1.5 -0.2 0.6 10. ]
[-2. 1. -1. 0. 10.]
# numpy.ceil()
# 返回数字的向上取整。
print (np.ceil(a))
运行结果
[-1. 2. -0. 1. 10.]
# add(),subtract(),multiply() 和 divide()。
# 需要注意的是数组必须具有相同的形状或符合数组广播规则。
a = np.arange(9, dtype = np.float_).reshape(3,3)
b = np.array([2,4,6])
print (a)
print (b)
print ('两个数组相加:\n')
# print (a+b)
print (np.add(a,b))
print ('两个数组相减:\n')
# print (a-b)
print (np.subtract(a,b))
print ('两个数组相乘:\n')
# print(a*b)
print (np.multiply(a,b))
print ('两个数组相除:\n')
# print(a/b)
print (np.divide(a,b))
# numpy.reciprocal() 函数返回参数逐元素的倒数
a = np.array([0.25, 2, 1, 100])
print (a)
print (np.reciprocal(a))
# numpy.power()
# 函数将第一个输入数组中的元素为底数,计算它与第二个输入数组相应元素的幂。
a = np.array([10,100,1000])
b = np.array([1,2,3])
print (np.power(a,2))
print (np.power(a,b))
# numpy.mod(),numpy.remainder()
# 算输入数组中相应元素的相除后的余数
a = np.array([10,20,30])
b = np.array([3,5,7])
print (np.mod(a,b))
print (np.remainder(a,b))
# numpy.amin() 和 numpy.amax()
# numpy.amin() 用于计算数组中的元素沿指定轴的最小值。
# numpy.amax() 用于计算数组中的元素沿指定轴的最大值。
a = np.array([[3,7,5],[8,4,3],[2,4,9]])
print (a)
print ('axis=None ',np.amin(a))
print ('axis=1 ',np.amin(a,1))
print ('axis=0 ',np.amin(a,0))
# numpy.ptp()
# 函数计算数组中元素最大值与最小值的差(最大值 - 最小值)。
a = np.array([[3,7,5],[8,4,3],[2,4,9]])
print(a)
print('axis=None',np.ptp(a))
print('axis=1',np.ptp(a,axis=1))
print('axis=0',np.ptp(a,axis=0))
# numpy.percentile(a, q, axis)
# 百分位数是统计中使用的度量,表示小于这个值的观察值的百分比。
# a: 输入数组
# q: 要计算的百分位数,在 0 ~ 100 之间
# axis: 沿着它计算百分位数的轴
a = np.array([[10, 7, 4],
[3, 2, 1]])
print (a)
# 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))
# numpy.median() 函数用于计算数组 a 中元素的中位数(中值)
a = np.array([[10, 7, 4],
[3, 2, 1]])
print (np.median(a))
# numpy.mean() 函数返回数组中元素的算术平均值。
a = np.array([[1,2,3],[3,4,5],[4,5,6]])
print(np.mean(a))
# numpy.average()
# 函数根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。
a = np.array([1,2,3,4])
wts = np.array([4,3,2,1])
print(np.average(a))
print(np.average(a,weights=wts))
# If returned=True, the tuple (`average`, `sum_of_weights`)
print(np.average(a,weights=wts, returned=True))
运行结果
2.5
2.0
(2.0, 10.0)
# numpy.std()
# 标准差是一组数据平均值分散程度的一种度量。
# std = sqrt(mean((x - x.mean())**2))
print(np.std([1,2,3,4])
# np.var()
# 方差(样本方差)是每个样本值与全体样本值的平均数之差的平方值的平均数,
# var = mean((x - x.mean())** 2)
print(np.var([1,2,3,4]))
3.13 数组扁平化
我们可以通过调用ravel或flatten方法,对数组对象进行扁平化处理。
- np.ravel / ravel
- flatten
二者的区别在于,ravel返回原数组的视图,而flatten返回原数组的拷贝。
x = np.arange(12).reshape(3, -1)
# print(np.ravel(x))
print(x.ravel())
print(x.flatten())
运行结果
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
3.14 连接与拆分函数
- np.concatenate 对多个数组按指定轴的方向进行连接。
- np.vstack / np.hstack
- np.split / np.hsplit / np.vsplit
a = np.random.randint(1,9,size=(2,2))
b = np.random.randint(1,9,size=(2,2))
print(a)
print(b)
#按指定轴的方向进行拼接, 默认axis=0
np.concatenate((a,b))
运行结果
[[7 3]
[6 1]]
[[3 3]
[3 6]]
array([[7, 3],
[6, 1],
[3, 3],
[3, 6]])
#对ndarray数组进行切分,axis可以指定方向
#切分时,可以指定一个标量,表示均等分,若不能均等分,则抛错
a = np.random.randint(0,20,size=(4,5))
print(np.split(a,2))
# #若不想进行均等切分,可以指定一个列表,来指定切分的索引
np.split(a,[1,3],axis=0)
运行结果
[array([[ 9, 2, 11, 19, 12],
[ 8, 6, 14, 11, 18]]), array([[11, 14, 17, 5, 1],
[10, 16, 5, 11, 18]])]
[array([[ 9, 2, 11, 19, 12]]), array([[ 8, 6, 14, 11, 18],
[11, 14, 17, 5, 1]]), array([[10, 16, 5, 11, 18]])]
3.15 sort方法
- np.sort 返回新创建的数组对象,原有的数组对象不会进行修改
- 数组对象的sort 返回的None,原有的对象会改变,(就地修改)
a = np.array([5,-2,4,-3])
print(np.sort(a))
print(a)
a = np.array([5,-2,4,-3])
print(a.sort())
print(a)
运行结果
[-3 -2 4 5]
[ 5 -2 4 -3]
None
[-3 -2 4 5]
4 NumPy 练习
4.1 计算距离
from scipy.spatial.distance import pdist, squareform
# https://docs.scipy.org/doc/scipy/reference
# /generated/scipy.spatial.distance.pdist.html
# 'braycurtis', 'canberra', 'chebyshev', 'cityblock',
# 'correlation', 'cosine', 'dice', 'euclidean', 'hamming',
# 'jaccard', 'jensenshannon', 'kulsinski', 'mahalanobis', 'matching',
# 'minkowski', 'rogerstanimoto', 'russellrao', 'seuclidean',
# 'sokalmichener', 'sokalsneath', 'sqeuclidean', 'yule'
x = np.array([[0, 1,2,3],
[1, 0,2,3],
[2, 0,2,3]])
a = pdist(x, 'euclidean')
b = squareform(pdist(x, 'euclidean'))
print(a)
print(b)
运行结果
[1.41421356 2.23606798 1. ]
[[0. 1.41421356 2.23606798]
[1.41421356 0. 1. ]
[2.23606798 1. 0. ]]
4.2 所有奇数替换为-1
# 将arr中的所有奇数替换为-1。
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
arr[arr % 2 == 1] = -1
print(arr)
# 将arr中的所有奇数替换为-1,而不改变arr。
arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
out = np.where(arr % 2 == 1, -1, arr)
print(arr)
print(out)
运行结果
[ 0 -1 2 -1 4 -1 6 -1 8 -1]
[0 1 2 3 4 5 6 7 8 9]
[ 0 -1 2 -1 4 -1 6 -1 8 -1]
4.3 生成自定义序列
# 不使用硬编码,生成numpy中的自定义序列
a = np.array([1,2,3])
# np.r_[np.repeat(a, 3), np.tile(a, 3)]
np.concatenate([np.repeat(a, 3), np.tile(a, 3)])
运行结果
array([1, 1, 1, 2, 2, 2, 3, 3, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3])
4.4 获取数组之间的公共项
# 获取数组a和数组b之间的公共项。
a = np.array([1,2,3,2,3,4,3,4,5,6]).reshape(2,-1)
b = np.array([7,2,10,2,7,4,9,4,9,8]).reshape(2,-1)
np.intersect1d(a,b)
运行结果
array([2, 4])
4.5 从数组中删除另一个数组中的所有项
# 从数组a中删除数组b中的所有项。
a = np.array([1,2,3,4,5])
b = np.array([5,6,7,8,9])
np.setdiff1d(a,b)
运行结果
array([1, 2, 3, 4])
4.6 获取数组中元素匹配的位置
# 获取a和b元素匹配的位置。
a = np.array([1,2,3,2,3,4,3,4,5,6])
b = np.array([7,2,10,2,7,4,9,4,9,8])
np.where(a == b)
运行结果
(array([1, 3, 5, 7], dtype=int64),)
4.7 数组中提取给定范围的元素
# 从numpy数组中提取给定范围内的所有数字
# 获取5到10之间的所有元素 [6, 9, 10]
a = np.array([2, 6, 1, 9, 10, 3, 27])
# Method 1
index = np.where((a >= 5) & (a <= 10))
a[index]
# Method 2:
index = np.where(np.logical_and(a>=5, a<=10))
a[index]
# Method 3:
a[(a >= 5) & (a <= 10)]
运行结果
array([ 6, 9, 10])
numpy.vectorize
numpy.vectorize(pyfunc, otypes=None, doc=None, excluded=None, cache=False, signature=None)
Parameters:
pyfunc : python函数或方法
otypes : 输出数据类型。必须将其指定为一个typecode字符串或一个数据类型说明符列表。每个输出应该有一个数据类型说明符。
doc : 函数的docstring。如果为None,则docstring将是 pyfunc.doc。
excluded : 表示函数不会向量化的位置或关键字参数的字符串或整数集。这些将直接传递给未经修改的pyfunc
cache :如果为True,则缓存第一个函数调用,该函数调用确定未提供otype的输出数。
signature : 广义通用函数签名,例如,(m,n),(n)->(m)用于矢量化矩阵 - 向量乘法。如果提供的话,pyfunc将调用(并期望返回)具有由相应核心维度的大小给出的形状的数组。默认情况下,pyfunc假定将标量作为输入和输出。
Returns:
vectorized :向量化的数组
4.8 多个数组对应位置的最大值
# 转换适用于两个标量的函数maxx,以处理两个数组。
a = np.array([5, 7, 9, 8, 6, 4, 5])
b = np.array([6, 3, 4, 8, 9, 7, 1])
# Method 1
def maxx(x, y):
"""Get the maximum of two items"""
if x >= y:
return x
else:
return y
pair_max = np.vectorize(maxx, otypes=[float])
pair_max(a, b)
# Method 2
c = np.concatenate((a,b)).reshape(2,-1)
np.max(c,axis=0)
运行结果
array([6, 7, 9, 8, 9, 7, 5])
4.9 交换行,列
# 在数组arr中交换列1和2。
arr = np.arange(9).reshape(3,3)
print(arr)
print(arr[:, [1,0,2]])
# 交换数组arr中的第1和第2行:
arr[[1,0,2], :]
运行结果
[[0 1 2]
[3 4 5]
[6 7 8]]
[[1 0 2]
[4 3 5]
[7 6 8]]
array([[3, 4, 5],
[0, 1, 2],
[6, 7, 8]])
4.10 反转行,列
# 反转二维数组arr的行。
print(arr[::-1,:])
# 反转二维数组arr的列。
print(arr[:,::-1])
运行结果
[[6 7 8]
[3 4 5]
[0 1 2]]
[[2 1 0]
[5 4 3]
[8 7 6]]
random模块提供生成随机数的功能(伪随机数)。常用功能如下:
- random():返回一个0 ~ 1之间的浮点数,包括0,不包括1。
- randint(a, b):返回一个a ~ b之间的整数。包括a与b。
- randrange(start, stop[, step]):参数与range函数的意义相同,相当于从相同参数的range函数可能产生的值中,随便选择一个。
- uniform(a, b):返回a与b之间的浮点数,包括端点。
- choice(seq):从seq(可迭代对象)中随机选择一个元素。如果序列为空,则产生错误。该抽样是放回抽样。
- choices(iterable, weights=None, *, cum_weights=None, k=1):从iterable(可迭代对象)中选择k个元素,放入一个新列表(不会改变原有的列表)并返回。如果提供了weights(权重)或cum_weights(累积权重),则元素的选择概率会根据权重(累积权重)决定。权重与累积权重不能同时指定,因为权重内部会转换成累积权重,这样会造成不一致。如果没有指定权重与累积权重,则各个元素的选择概率相同。
- sample(iterable, k):从iterable(可迭代对象)中选择k个元素,返回元素组成的新列表(不会改变原有的列表)。该抽样是不放回抽样。
- shuffle(x[, random]):对x(序列)进行洗牌。random是一个可选的生成随机数的函数,函数的返回值为[0, 1),默认使用random模块的random函数。(就地修改)
np.random模块提供生成随机数的功能(伪随机数)
- np.random.rand
- np.random.random
- np.random.randn
- np.random.normal
- np.random.randint
- np.random.seed
- np.random.shuffle
- np.random.uniform
4.11 创建指定区间的随机数
# 创建一个形状为5x3的二维数组,以包含5到10之间的随机十进制数。
arr = np.arange(9).reshape(3,3)
# Solution Method 1:
rand_arr = np.random.randint(low=5, high=10, size=(5,3)) + np.random.random((5,3))
# print(rand_arr)
# Solution Method 2:
rand_arr = np.random.uniform(5,10, size=(5,3))
print(rand_arr)
运行结果
[[7.00895215 5.34171314 9.02545605]
[8.77938223 9.15814271 5.46713387]
[8.35351152 7.02282564 9.59648514]
[6.10883598 8.04277479 8.60606051]
[9.54183886 5.38980032 8.69235166]]
4.12 保留指定小数点位数
# 只打印或显示numpy数组rand_arr的小数点后3位。
rand_arr = np.random.random([5,3])
# Limit to 3 decimal places
np.set_printoptions(precision=3)
rand_arr
运行结果
array([[0.18 , 0.728, 0.831],
[0.146, 0.64 , 0.984],
[0.08 , 0.556, 0.083],
[0.156, 0.224, 0.255],
[0.964, 0.317, 0.955]])
4.13 科学记数法
# 通过e式科学记数法来打印rand_arr(如1e10)
np.set_printoptions(suppress=False)
# Create the random array
np.random.seed(100)
rand_arr = np.random.random([3,3])/1e3
print(rand_arr)
np.set_printoptions(suppress=True, precision=6) # precision is optional
rand_arr
运行结果
[[5.434e-04 2.784e-04 4.245e-04]
[8.448e-04 4.719e-06 1.216e-04]
[6.707e-04 8.259e-04 1.367e-04]]
array([[0.000543, 0.000278, 0.000425],
[0.000845, 0.000005, 0.000122],
[0.000671, 0.000826, 0.000137]])
4.14 指定打印的元素个数
# 如何限制numpy数组输出中打印的项目数?
np.set_printoptions(threshold=6)
a = np.arange(15)
print(a)
# 如何打印完整的numpy数组而不截断
np.set_printoptions(threshold=1000)
a = np.arange(15)
print(a)
运行结果
[ 0 1 2 ... 12 13 14]
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
4.15 规范化数组
如何规范化数组,使数组的值正好介于0和1之间?
# Input
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
sepallength = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[0])[0:50]
# Solution
Smax, Smin = sepallength.max(), sepallength.min()
S = (sepallength - Smin)/(Smax - Smin)
# or
S = (sepallength - Smin)/sepallength.ptp()
print(S)
4.16 数组的百分位数
# 如何找到numpy数组的百分位数?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
sepallength = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[0])
# Solution
np.percentile(sepallength, q=[5, 95])
运行结果
array([4.6 , 7.255])
numpy.where() 有两种用法:
-
- np.where(condition, x, y)
- 满足条件(condition),输出x,不满足输出y。
- np.where(condition, x, y)
-
- np.where(condition)
- 只有条件 (condition),没有x和y,则输出满足条件 (即非0) 元素的坐标 (等价于numpy.nonzero)。这里的坐标以tuple的形式给出,通常原数组有多少维,输出的tuple中就包含几个数组,分别对应符合条件元素的各维坐标。
- np.where(condition)
4.17 随机位置插入值
# 如何在数组中的随机位置插入值?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris_2d = np.genfromtxt(url, delimiter=',', dtype='object')
# Method 1
i, j = np.where(iris_2d)
# i, j contain the row numbers and column numbers of 600 elements of iris_x
np.random.seed(100)
iris_2d[np.random.choice((i), 20), np.random.choice((j), 20)] = np.nan
# Method 2
np.random.seed(100)
iris_2d[np.random.randint(150, size=20), np.random.randint(4, size=20)] = np.nan
# Print first 10 rows
print(iris_2d[:10])
运行结果
[[b'5.1' b'3.5' b'1.4' b'0.2' b'Iris-setosa']
[b'4.9' b'3.0' b'1.4' b'0.2' b'Iris-setosa']
[b'4.7' b'3.2' b'1.3' b'0.2' b'Iris-setosa']
[b'4.6' b'3.1' b'1.5' b'0.2' b'Iris-setosa']
[b'5.0' b'3.6' b'1.4' b'0.2' b'Iris-setosa']
[b'5.4' b'3.9' b'1.7' b'0.4' b'Iris-setosa']
[b'4.6' b'3.4' b'1.4' b'0.3' b'Iris-setosa']
[b'5.0' b'3.4' b'1.5' b'0.2' b'Iris-setosa']
[b'4.4' nan b'1.4' b'0.2' b'Iris-setosa']
[b'4.9' b'3.1' b'1.5' b'0.1' b'Iris-setosa']]
4.18 查询缺失值的位置
# 如何在numpy数组中找到缺失值的位置?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris_2d = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[0,1,2,3])
iris_2d[np.random.randint(150, size=20), np.random.randint(4, size=20)] = np.nan
# Solution
print("Number of missing values: \n", np.isnan(iris_2d[:, 0]).sum())
print("Position of missing values: \n", np.where(np.isnan(iris_2d[:, 0])))
运行结果
Number of missing values:
5
Position of missing values:
(array([ 38, 80, 106, 113, 121], dtype=int64),)
4.19 筛选数据
# 如何根据两个或多个条件过滤numpy数组?
# 过滤具有petallength(第3列)> 1.5 和 sepallength(第1列)< 5.0 的数据
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris_2d = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[0,1,2,3])
# Solution
condition = (iris_2d[:, 2] > 1.5) & (iris_2d[:, 0] < 5.0)
iris_2d[condition]
运行结果
array([[4.8, 3.4, 1.6, 0.2],
[4.8, 3.4, 1.9, 0.2],
[4.7, 3.2, 1.6, 0.2],
[4.8, 3.1, 1.6, 0.2],
[4.9, 2.4, 3.3, 1. ],
[4.9, 2.5, 4.5, 1.7]])
4.20 删除包含缺失值的行
# 如何从numpy数组中删除包含缺失值的行?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris_2d = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[0,1,2,3])
iris_2d[np.random.randint(150, size=20), np.random.randint(4, size=20)] = np.nan
# Solution
# No direct numpy function for this.
# Method 1:
any_nan_in_row = np.array([~np.any(np.isnan(row)) for row in iris_2d])
iris_2d[any_nan_in_row][:5]
# Method 2: (By Rong)
iris_2d[np.sum(np.isnan(iris_2d), axis = 1) == 0][:5]
运行结果
array([[4.9, 3. , 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
[4.6, 3.1, 1.5, 0.2],
[5. , 3.6, 1.4, 0.2],
[4.6, 3.4, 1.4, 0.3]])
4.21 数组相关性
# 如何找到numpy数组的两列之间的相关性?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[0,1,2,3])
# Solution 1
print(np.corrcoef(iris[:, 0], iris[:, 2])[0, 1])
# Solution 2
from scipy.stats.stats import pearsonr
corr, p_value = pearsonr(iris[:, 0], iris[:, 2])
print(corr)
运行结果
0.8717541573048718
0.8717541573048713
4.22 查找数组是否具有任何空值
# 如何查找给定数组是否具有任何空值?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris_2d = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[0,1,2,3])
np.isnan(iris_2d).any()
运行结果
False
4.23 用指定值替换所有缺失值
# 如何在numpy数组中用0替换所有缺失值?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris_2d = np.genfromtxt(url, delimiter=',', dtype='float', usecols=[0,1,2,3])
iris_2d[np.random.randint(150, size=20), np.random.randint(4, size=20)] = np.nan
iris_2d[np.isnan(iris_2d)] = 0
iris_2d[:4]
运行结果
array([[5.1, 3.5, 1.4, 0.2],
[4.9, 3. , 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
[4.6, 3.1, 1.5, 0.2]])
4.24 查找唯一值的计数
# 如何在numpy数组中查找唯一值的计数?
# Import iris keeping the text column intact
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='object')
names = ('sepallength', 'sepalwidth', 'petallength', 'petalwidth', 'species')
# Solution
# Extract the species column as an array
species = np.array([row.tolist()[4] for row in iris])
# Get the unique values and the counts
np.unique(species, return_counts=True)
运行结果
(array([b'Iris-setosa', b'Iris-versicolor', b'Iris-virginica'],
dtype='|S15'), array([50, 50, 50], dtype=int64))
4.25 数字转换为文本数组
# 如何将数字转换为分类(文本)数组?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='object')
names = ('sepallength', 'sepalwidth', 'petallength', 'petalwidth', 'species')
# Bin petallength
petal_length_bin = np.digitize(iris[:, 2].astype('float'), [0, 3, 5, 10])
# Map it to respective category
label_map = {1: 'small', 2: 'medium', 3: 'large', 4: np.nan}
petal_length_cat = [label_map[x] for x in petal_length_bin]
# View
petal_length_cat[:4]
运行结果
['small', 'small', 'small', 'small']
4.26 利用现有列创建新列
# 如何从numpy数组的现有列创建新列?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris_2d = np.genfromtxt(url, delimiter=',', dtype='object')
# Solution
# Compute volume
sepallength = iris_2d[:, 0].astype('float')
petallength = iris_2d[:, 2].astype('float')
volume = (np.pi * petallength * (sepallength**2))/3
print(volume.shape)
# Introduce new dimension to match iris_2d's
volume = volume[:, np.newaxis]
print(volume.shape)
# Add the new column
out = np.hstack([iris_2d, volume])
# View
out[:4]
运行结果
(150,)
(150, 1)
array([[b'5.1', b'3.5', b'1.4', b'0.2', b'Iris-setosa',
38.13265162927291],
[b'4.9', b'3.0', b'1.4', b'0.2', b'Iris-setosa',
35.200498485922445],
[b'4.7', b'3.2', b'1.3', b'0.2', b'Iris-setosa', 30.0723720777127],
[b'4.6', b'3.1', b'1.5', b'0.2', b'Iris-setosa',
33.238050274980004]], dtype=object)
使用np.c_和np.r_实现数组转换成矩阵
- np.r_是按列连接多个矩阵,就是把多矩阵上下相加,要求列数相等。
- eg:(3,5),(2,5) --> (5,5)
- np.c_是按行连接多个矩阵,就是把多矩阵左右相加,要求行数相等。
- eg:(5,3),(5,2) --> (5,5)
4.27 查找数组在另一个数组中的位置
# 二分法查找b在a中的位置,返回位置索引值
np.searchsorted([1,2,3,4,5], [-10, 10, 2, 3])
运行结果
array([0, 5, 1, 2], dtype=int64)
4.28 概率抽样数据
# 如何在numpy中进行概率抽样?
# 随机抽鸢尾属植物的种类,使得刚毛的数量是云芝和维吉尼亚的两倍
# Import iris keeping the text column intact
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='object')
# Solution
# Get the species column
species = iris[:, 4]
# Approach 1: Generate Probablistically
np.random.seed(100)
a = np.array(['Iris-setosa', 'Iris-versicolor', 'Iris-virginica'])
species_out = np.random.choice(a, 150, p=[0.5, 0.25, 0.25])
# Approach 2: Probablistic Sampling (preferred)
np.random.seed(100)
probs = np.r_[np.linspace(0, 0.500, num=50), np.linspace(0.501, .750, num=50), np.linspace(.751, 1.0, num=50)]
index = np.searchsorted(probs, np.random.random(150))
species_out = species[index]
print(np.unique(species_out, return_counts=True))
运行结果
(array([b'Iris-setosa', b'Iris-versicolor', b'Iris-virginica'],
dtype=object), array([77, 37, 36], dtype=int64))
4.29 按另一个数组分组时获取数组的第二大值
# 如何在按另一个数组分组时获取数组的第二大值?
# 问题:第二长的物种setosa的价值是多少
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='object')
# Solution
# Get the species and petal length columns
petal_len_setosa = iris[iris[:, 4] == b'Iris-setosa', [2]].astype('float')
# Get the second last value
np.unique(np.sort(petal_len_setosa))[-2]
4.30 对数组进行排序
print(iris[iris[:,0].argsort()][:20])
4.31 数组中众数
# 如何在numpy数组中找到众数?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='object')
# Solution:
vals, counts = np.unique(iris[:, 0], return_counts=True)
print(vals[np.argmax(counts)])
from scipy import stats
print(stats.mode(iris)[0][0])
#bincount():统计非负整数的个数,不能统计浮点数
counts = np.bincount(np.array([1,2,3,5,6,6,6,4,7,8]))
#返回众数
print(np.argmax(counts))
运行结果
b'5.0'
[b'5.0' b'3.0' b'1.5' b'0.2' b'Iris-setosa']
6
4.32 查找数组中大于指定值的位置及值
x = np.array([[3, 0, 0],
[0, 4, 0],
[5, 6, 0]])
print(np.nonzero(x>3))
print(np.transpose(np.nonzero(x>3)))
print(x[np.nonzero(x>3)])
运行结果
(array([1, 2, 2], dtype=int64), array([1, 0, 1], dtype=int64))
[[1 1]
[2 0]
[2 1]]
[4 5 6]
4.33 首次出现的值大于给定值的位置
# 如何找到第一次出现的值大于给定值的位置?
# 查找第一次出现的值大于1.0的位置。
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='object')
# method 1:
print(np.transpose(np.nonzero(iris[:, 3].astype(float)>1.0))[0])
# method 2:
np.argwhere(iris[:, 3].astype(float) > 1.0)[0]
4.34 大于给定值的所有值替换为给定值
# 如何将大于给定值的所有值替换为给定的截止值?
# 问题:从数组a中,替换所有大于30的值更改为30 和 小于10的值更改为10。
np.set_printoptions(precision=2)
np.random.seed(100)
a = np.random.uniform(1,50, 20)
print(a)
# Solution 1: Using np.clip
print(np.clip(a, a_min=10, a_max=30))
# Solution 2: Using np.where
print(np.where(a<10, 10, np.where(a>30,30,a)))
运行结果
[27.63 14.64 21.8 42.39 1.23 6.96 33.87 41.47 7.7 29.18 44.67 11.25
10.08 6.31 11.77 48.95 40.77 9.43 41. 14.43]
[27.63 14.64 21.8 30. 10. 10. 30. 30. 10. 29.18 30. 11.25
10.08 10. 11.77 30. 30. 10. 30. 14.43]
[27.63 14.64 21.8 30. 10. 10. 30. 30. 10. 29.18 30. 11.25
10.08 10. 11.77 30. 30. 10. 30. 14.43]
np.argpartition()
- numpy.argpartition(a, kth, axis=-1, kind='introselect', order=None)
- 在快排算法中,有一个典型的操作:partition。这个操作指:根据一个数值x,把数组中的元素划分成两半,使得index前面的元素都不大于x,index后面的元素都不小于x。
- numpy中的argpartition()函数就是起的这个作用。对于传入的数组a,先用O(n)复杂度求出第k大的数字,然后利用这个第k大的数字将数组a划分成两半。
- 此函数不对原数组进行操作,它只返回分区之后的下标。一般numpy中以arg开头的函数都是返回下标而不改变原数组。
4.35 数组5个最大值的位置
# 问题:获取给定数组a中前5个最大值的位置。
np.random.seed(100)
a = np.random.uniform(1,50, 20)
# Method 1:
print(a.argsort()[::-1][:5])
# Method 2:
print(np.argpartition(-a,kth=5)[:5])
4.36 按行计算唯一值的计数
# 问题:按行计算唯一值的计数。
# 输出包含10列,表示从1到10的数字。这些值是各行中数字的计数。
np.random.seed(100)
arr = np.random.randint(1,11,size=(6, 10))
print(arr)
# Solution 1:
def counts_of_all_values_rowwise(arr2d):
# Unique values and its counts row wise
num_counts_array = [np.unique(row, return_counts=True) for row in arr2d]
# Counts of all values row wise
return([[int(b[a==i]) if i in a else 0 for i in np.unique(arr2d)] for a, b in num_counts_array])
# [ 1 2 3 4 5 6 7 8 9 10]
print(counts_of_all_values_rowwise(arr))
运行结果
[[ 9 9 4 8 8 1 5 3 6 3]
[ 3 3 2 1 9 5 1 10 7 3]
[ 5 2 6 4 5 5 4 8 2 2]
[ 8 8 1 3 10 10 4 3 6 9]
[ 2 1 8 7 3 1 9 3 6 2]
[ 9 2 6 5 3 9 4 6 1 10]]
[[1, 0, 2, 1, 1, 1, 0, 2, 2, 0],
[2, 1, 3, 0, 1, 0, 1, 0, 1, 1],
[0, 3, 0, 2, 3, 1, 0, 1, 0, 0],
[1, 0, 2, 1, 0, 1, 0, 2, 1, 2],
[2, 2, 2, 0, 0, 1, 1, 1, 1, 0],
[1, 1, 1, 1, 1, 2, 0, 0, 2, 1]]
4.37 扁平化数组
# 如何将数组转换为平面一维数组?
arr_2d = np.arange(20).reshape(4,-1)
print(arr_2d)
# Solution 1
arr_1d = np.array([a for i in arr_2d for a in i])
print(arr_1d)
# Solution 2:
arr_1d = np.concatenate(arr_2d)
print(arr_1d)
# flatten()分配了新的内存,但ravel()返回的是一个数组的视图
print(arr_2d.flatten())
print(arr_2d.ravel())
4.38 单热编码
# 如何在numpy中为数组生成单热编码?
np.random.seed(101)
arr = np.random.randint(1,4, size=6)
print(arr)
# Solution:
def one_hot_encodings(arr):
uniqs = np.unique(arr)
out = np.zeros((arr.shape[0], uniqs.shape[0]))
for i, k in enumerate(arr):
out[i, k-1] = 1
return out
print(one_hot_encodings(arr))
# Method 2:
print((arr[:, None] == np.unique(arr)).view(np.int8))
运行结果
[2 3 2 2 2 1]
[[0. 1. 0.]
[0. 0. 1.]
[0. 1. 0.]
[0. 1. 0.]
[0. 1. 0.]
[1. 0. 0.]]
[[0 1 0]
[0 0 1]
[0 1 0]
[0 1 0]
[0 1 0]
[1 0 0]]
4.39 按分类变量分组
# 如何创建按分类变量分组的行号?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
species = np.genfromtxt(url, delimiter=',', dtype='str', usecols=4)
np.random.seed(100)
species_small = np.sort(np.random.choice(species, size=20))
print(species_small)
print([i for val in np.unique(species_small) for i,grp in enumerate(species_small[species_small==val])])
运行结果
['Iris-setosa' 'Iris-setosa' 'Iris-setosa' 'Iris-setosa' 'Iris-setosa'
'Iris-versicolor' 'Iris-versicolor' 'Iris-versicolor' 'Iris-versicolor'
'Iris-versicolor' 'Iris-versicolor' 'Iris-versicolor' 'Iris-versicolor'
'Iris-versicolor' 'Iris-virginica' 'Iris-virginica' 'Iris-virginica'
'Iris-virginica' 'Iris-virginica' 'Iris-virginica']
[0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 1, 2, 3, 4, 5]
4.40 分类变量创建组ID
# 如何根据给定的分类变量创建组ID?
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
species = np.genfromtxt(url, delimiter=',', dtype='str', usecols=4)
np.random.seed(100)
species_small = np.sort(np.random.choice(species, size=20))
print(species_small)
# Solution: For Loop version
output = []
uniqs = np.unique(species_small)
for val in uniqs: # uniq values in group
for s in species_small[species_small==val]: # each element in group
groupid = np.argwhere(uniqs == s).tolist()[0][0] # groupid
output.append(groupid)
print(output)
output = [np.argwhere(np.unique(species_small) == s).tolist()[0][0] for val in np.unique(species_small) for s in species_small[species_small==val]]
print(output)
运行结果
['Iris-setosa' 'Iris-setosa' 'Iris-setosa' 'Iris-setosa' 'Iris-setosa'
'Iris-versicolor' 'Iris-versicolor' 'Iris-versicolor' 'Iris-versicolor'
'Iris-versicolor' 'Iris-versicolor' 'Iris-versicolor' 'Iris-versicolor'
'Iris-versicolor' 'Iris-virginica' 'Iris-virginica' 'Iris-virginica'
'Iris-virginica' 'Iris-virginica' 'Iris-virginica']
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2]
[0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2]
argsort()函数是用来返回数组值从小到大索引值的。
- a = [6,4,5]
- 矩阵a从小到大排序,记排序后的矩阵为 b = [4,5,6]
- a.argsort() = [1,2,0]
- 矩阵a和b的关系:
- b的第一个元素“4”对应的是a矩阵的第2个元素,也就是a[1]
- b的第二个元素“5”对应的是a矩阵的第3个元素,也就是a[2]
- b的第三个元素“6”对应的是a矩阵的第1个元素,也就是a[0]
4.41 数组中的元素排名
# 如何使用numpy对数组中的项进行排名?
np.random.seed(10)
a = np.random.randint(20, size=10)
print('Array: ', a)
# Solution
print(a.argsort().argsort())
print('Array: ', a)
运行结果
Array: [ 9 4 15 0 17 16 17 8 9 0]
[4 2 6 0 8 7 9 3 5 1]
Array: [ 9 4 15 0 17 16 17 8 9 0]
4.42 多维数组中的每一项进行排名
# 如何使用numpy对多维数组中的每一项进行排名?
np.random.seed(10)
a = np.random.randint(20, size=[2,5])
print(a)
# Solution
print(a.ravel().argsort().argsort().reshape(a.shape))
运行结果
[[ 9 4 15 0 17]
[16 17 8 9 0]]
[[4 2 6 0 8]
[7 9 3 5 1]]
4.43 数组的每一行中找到最大值
# 如何在二维numpy数组的每一行中找到最大值?
np.random.seed(100)
a = np.random.randint(1,10, [5,3])
print(a)
# Solution 1
print(np.amax(a, axis=1))
# Solution 2
print(np.apply_along_axis(np.max, arr=a, axis=1))
运行结果
[[9 9 4]
[8 8 1]
[5 3 6]
[3 3 3]
[2 1 9]]
[9 8 6 3 9]
[9 8 6 3 9]
4.44 数组的每一行中找到最小值
# 如何计算二维numpy数组每行的最小值?
np.random.seed(100)
a = np.random.randint(1,10, [5,3])
print(a)
# Solution
print(np.apply_along_axis(lambda x: np.min(x), arr=a, axis=1))
运行结果
[[9 9 4]
[8 8 1]
[5 3 6]
[3 3 3]
[2 1 9]]
[4 1 3 3 1]
4.45 标记重复的元素
# 问题:在给定的numpy数组中找到重复的条目(第二次出现以后),并将它们标记为True。第一次出现应该是False的。
np.random.seed(100)
a = np.random.randint(0, 5, 10)
print(a)
# Find the index positions of unique elements
unique_positions = np.unique(a, return_index=True)[1]
# Mark those positions as False
out[unique_positions] = False
print(out)
4.46 按分类列分组的数值列的平均值
# 问题:在二维数字数组中查找按分类列分组的数值列的平均值
url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data'
iris = np.genfromtxt(url, delimiter=',', dtype='object')
names = ('sepallength', 'sepalwidth', 'petallength', 'petalwidth', 'species')
# Solution
# No direct way to implement this. Just a version of a workaround.
numeric_column = iris[:, 1].astype('float') # sepalwidth
grouping_column = iris[:, 4] # species
# List comprehension version
[[group_val, numeric_column[grouping_column==group_val].mean()] for group_val in np.unique(grouping_column)]
# For Loop version
output = []
for group_val in np.unique(grouping_column):
output.append([group_val, numeric_column[grouping_column==group_val].mean()])
output
运行结果
[[b'Iris-setosa', 3.418],
[b'Iris-versicolor', 2.7700000000000005],
[b'Iris-virginica', 2.974]]
4.47 PIL图像转换为numpy数组
# 如何将PIL图像转换为numpy数组?
from io import BytesIO
from PIL import Image
import PIL, requests
# Import image from URL
URL = 'https://upload.wikimedia.org/wikipedia/commons/8/8b/Denali_Mt_McKinley.jpg'
response = requests.get(URL)
# Read it as Image
I = Image.open(BytesIO(response.content))
# Optionally resize
I = I.resize([150,150])
# Convert to numpy array
arr = np.asarray(I)
# Optionaly Convert it back to an image and show
im = PIL.Image.fromarray(np.uint8(arr))
Image.Image.show(im)
4.48 组中删除所有NaN值
# 问题:从一维numpy数组中删除所有NaN值
a = np.array([1,2,3,np.nan,5,6,7,np.nan])
print(a)
print(a[~np.isnan(a)])
4.49 范数
# np.linalg.norm(求范数)
# linalg=linear(线性)+algebra(代数),norm则表示范数。
import numpy as np
x = np.array([[0, 3, 4],
[1, 6, 4]])
#默认参数ord=None,axis=None,keepdims=False
print ("默认参数(矩阵整体元素平方和开根号,不保留矩阵二维特性):\n",np.linalg.norm(x))
print ("矩阵整体元素平方和开根号,保留矩阵二维特性:\n",np.linalg.norm(x,keepdims=True))
print ("矩阵每个行向量求向量的2范数:\n",np.linalg.norm(x,axis=1,keepdims=True))
print ("矩阵每个列向量求向量的2范数:\n",np.linalg.norm(x,axis=0,keepdims=True))
print ("矩阵1范数:\n",np.linalg.norm(x,ord=1,keepdims=True))
print ("矩阵2范数:\n",np.linalg.norm(x,ord=2,keepdims=True))
print ("矩阵∞范数:\n",np.linalg.norm(x,ord=np.inf,keepdims=True))
print ("矩阵每个行向量求向量的1范数:\n",np.linalg.norm(x,ord=1,axis=1,keepdims=True))
运行结果
默认参数(矩阵整体元素平方和开根号,不保留矩阵二维特性):
8.831760866327848
矩阵整体元素平方和开根号,保留矩阵二维特性:
[[8.83]]
矩阵每个行向量求向量的2范数:
[[5. ]
[7.28]]
矩阵每个列向量求向量的2范数:
[[1. 6.71 5.66]]
矩阵1范数:
[[9.]]
矩阵2范数:
[[8.7]]
矩阵∞范数:
[[11.]]
矩阵每个行向量求向量的1范数:
[[ 7.]
[11.]]
4.50 欧氏距离
# 问题:计算两个数组a和数组b之间的欧氏距离。
a = np.array([1,2,3,4,5])
b = np.array([4,5,6,7,8])
# Solution
dist = np.linalg.norm(a-b)
print(dist)
dist = np.sqrt(((a-b)**2).sum())
print(dist)
4.51 数组中的所有峰值
# 问题:找到一个一维数字数组a中的所有峰值。峰顶是两边被较小数值包围的点。
a = np.array([1, 3, 7, 1, 2, 6, 0, 1, 1])
doublediff = np.diff(np.sign(np.diff(a)))
peak_locations = np.where(doublediff == -2)[0] + 1
peak_locations
运行结果
array([2, 5], dtype=int64)
4.52 第n次重复元素的索引
# 如何查找数组中项的第n次重复索引?
x = np.array([1, 2, 1, 1, 3, 4, 3, 1, 1, 2, 1, 1, 2])
n = 5
# Solution 1: List comprehension
a = [i for i, v in enumerate(x) if v == 1][n-1]
print(a)
# Solution 2: Numpy version
b = np.where(x == 1)[0][n-1]
print(a)
4.53 datetime64转换为datetime
# 将numpy的datetime64对象转换为datetime的datetime对象
import pandas as pd
dt64 = np.datetime64('2018-02-25 22:10:10')
# Solution
from datetime import datetime
print(type(dt64.tolist()))
print(type(dt64.astype(datetime)))
print(dt64.astype(datetime))
print(pd.to_datetime(dt64))
运行结果
2018-02-25 22:10:10
2018-02-25 22:10:10
4.54 计算窗口大小为3的移动平均值
# 问题:对于给定的一维数组,计算窗口大小为3的移动平均值。
def moving_average(a, n=3) :
ret = np.cumsum(a, dtype=float)
ret[n:] = ret[n:] - ret[:-n]
return ret[n-1:] / n
np.random.seed(100)
Z = np.random.randint(10, size=10)
print('array: ', Z)
# Method 1
print(moving_average(Z, n=3).round(8))
# Method 2:
# np.ones(3)/3 gives equal weights. Use np.ones(4)/4 for window size 4.
print(np.convolve(Z, np.ones(3)/3, mode='valid'))
运行结果
array: [8 8 3 7 7 0 4 2 5 2]
[6.33 6. 5.67 4.67 3.67 2. 3.67 3. ]
[6.33 6. 5.67 4.67 3.67 2. 3.67 3. ]
4.55 填写缺失的日期
# 问题:给定一系列不连续的日期序列。填写缺失的日期,使其成为连续的日期序列。
dates = np.arange(np.datetime64('2018-02-01'), np.datetime64('2018-02-25'), 2)
print(dates)
# Solution ---------------
filled_in = np.array([np.arange(date, (date+d)) for date, d in zip(dates, np.diff(dates))]).reshape(-1)
# add the last day
output = np.hstack([filled_in, dates[-1]])
print(output)
4.56 生成一个二维矩阵
# 问题:从给定的一维数组arr中,利用步进生成一个二维矩阵,窗口长度为4,步距为2,
# 类似于 [[0,1,2,3], [2,3,4,5], [4,5,6,7]..]
def gen_strides(a, stride_len=5, window_len=5):
n_strides = ((a.size-window_len)//stride_len) + 1
# return np.array([a[s:(s+window_len)] for s in np.arange(0, a.size, stride_len)[:n_strides]])
return np.array([a[s:(s+window_len)] for s in np.arange(0, n_strides*stride_len, stride_len)])
a = np.arange(15)
print(a)
print(gen_strides(a, window_len=4, stride_len=2))
运行结果
[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14]
[[ 0 1 2 3]
[ 2 3 4 5]
[ 4 5 6 7]
[ 6 7 8 9]
[ 8 9 10 11]
[10 11 12 13]]