一、numpy简介
NumPy是使用Python进行科学计算的基础软件包。 它包含以下内容:
(1)一个强大的N维数组对象
(2)复杂(广播)功能
(3)用于集成C / C ++和Fortran代码的工具
(4)非常有用的线性代数,傅里叶变换和随机数操作
(5)除了其明显的科学用途,NumPy也可以用作通用数据的高效多维容器。 可以定义任意数据类型。 这使NumPy能够无缝地,快速地与各种数据库集成。
可能大家对"广播"一词不太了解,广播的意思可以这样理解,当我有两个维度不一样的array(数组)运算时,我可以用低维的数组复制成高维数组参与运算(因为运算要符合一定结构)
- numpy官方网站:http://www.numpy.org/
- numpy快速入门官方文档:https://docs.scipy.org/doc/numpy-dev/user/quickstart.html
Numpy的主要对象是同种元素的多维数组。这是一个所有的元素都是一种类型、通过一个正整数元组索引的元素表格(通常是元素是数字)。在Numpy中维度(dimensions)叫做轴(axes),轴的个数叫做秩(rank)。
例如,在3D空间一个点的坐标[1, 2, 3]是一个秩为1的数组,因为它只有一个轴。那个轴长度为3.又例如,在以下例子中,数组的秩为2(它有两个维度).第一个维度长度为2,第二个维度长度为3.
[[ 1., 0., 0.],
[ 0., 1., 2.]]
Numpy的数组类被称作ndarray
。通常被称作数组。注意numpy.array
和标准Python
库类array.array
并不相同,后者只处理一维数组和提供少量功能。更多重要ndarray
对象属性有:
ndarray.ndim
数组轴的个数,在python的世界中,轴的个数被称作秩
ndarray.shape
数组的维度。这是一个指示数组在每个维度上大小的整数元组。例如一个n
排m
列的矩阵,它的shape
属性将是(2,3),这个元组的长度显然是秩,即维度或者ndim
属性
ndarray.size
数组元素的总个数,等于shape
属性中元组元素的乘积。
ndarray.dtype
一个用来描述数组中元素类型的对象,可以通过创造或指定dtype
使用标准Python
类型。另外Numpy提供它自己的数据类型。
ndarray.itemsize
数组中每个元素的字节大小。例如,一个元素类型为float64
的数组itemsiz
属性值为8(=64/8),又如,一个元素类型为complex32
的数组item
属性为4(=32/8)
.
ndarray.data
包含实际数组元素的缓冲区,通常我们不需要使用这个属性,因为我们总是通过索引来使用数组中的元素。
import numpy as np
a = np.arange(15)
print(a.reshape(3,5))
- 维度是一组数据的组织形式
- 数组要求数据类型相同,列表不需要
a = np.array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
print(a)
二、数组的创建和转换
从列表,元组创建,可指定数据类型
np.array函数就可以了,可以用的type指定类型
使用Numpy自带的函数ones,zeros等
ones_like(a),根据a的形状生成一个一样的为1的数组
list1 = [[1,2,3,4],[2,3,4,5],[3,4,5,6]]
# 使用 array 创建np数组
np1 = np.array(list1, dtype=np.int)
print(np1)
# 获取np数 组 的形状
print(np1.shape)
# 获取np数组的维度
print(np1.ndim)
# 获取np数组的元素类型
print(np1.dtype)
# 获取np数组的元素个数
print(np1.size)
np.linspace(1, 10, 4)
np.linspace(1, 10, 4, endpoint = False)#10不作为最后一个值出现
#查看数组的属性
arr2 = np.array([(1.3, 9, 2.0), (7, 6, 1)])
#通过元组创建数组
print(arr2.shape)
# 返回矩阵的规格
# result: (2,3)
print(arr2.ndim)
# 返回矩阵的秩
# result: 2
print(arr2.size)
# 返回矩阵元素总数
# result: 6
print(arr2.itemsize)
# # result: 8
print(arr2.nbytes)
# # result: 48
print(arr2.dtype.name)
# 返回矩阵元素的数据类型
# result: float64
print(type(arr2))
# 查看整个数组对象的类型
# result: <class 'numpy.ndarray'>
b = np.array([1. + 1.j, 3. + 2.j])
b.real
# result:array([1., 3.])
b.imag
# result:array([1., 2.])
b = np.arange(4).reshape(2, 2)
b.flat
# result:<numpy.flatiter object at 0x0000024FF4C32CF0>
b.flat[2]
# result:2
对创建好的数组,可以变换维度,改变类型
reshape不改变原数组,resize改变原数组
通常,数组的元素开始都是未知的,但是它的大小已知。因此,Numpy提供了一些使用占位符创建数组的函数。这最小化了扩展数组的需要和高昂的运算代价。
函数function
创建一个全是0的数组,函数ones
创建一个全1的数组,函数empty
创建一个内容随机并且依赖与内存状态的数组。默认创建的数组类型(dtype)
都是float64
。
三、 numpy基本运算和常用函数
# 使用填充值创建数组 one zero empty
np4 = np.ones((3,4), dtype=np.int)
print(np4)
np5 = np.ones_like(np4)
# 创建单位矩阵
np6 = np.eye(6)
a = np.array([20, 30, 40, 50])
b = np.arange(4)
##加减乘除
a + b
a - b
a * b
b / a
a ** b
np.cos(a) + np.sin(b)
a < 35
c = np.array([[1, 1],
[2, 2]])
d = np.array([[2, 2],
[1, 1]])
c += d
c
np.dot(c, d)
c * d
c += d
e = np.exp(c * 1j)
e.dtype.name
d.sum()
d.mean()
d.min()
四、索引、切片和迭代
4.1 一维数组
a = np.array([0, 1, 2, 3])
a[0]
a[0] = 10
a = np.array([11,12,13,14,15])
a[1:3]
a[1:-2]
a[-4:3]
test:假设我们记录一辆汽车表盘上每天显示的里程数为:od = array([21000, 21180, 21240, 22100, 22400]), 计算每天的旅程
4.2 多维数组
a = np.array([[ 0, 1, 2, 3],
[10,11,12,13]])
a[1, 3]
# 其中,1是行索引,3是列索引,中间用逗号隔开,
#事实上,**Python**会将它们看成一个元组(1,3),然后按照顺序进行对应。
# 可以利用索引给它赋值:
a[1, 3] = -1
a[1]
a = np.array([[ 0, 1, 2, 3, 4, 5],
[10,11,12,13,14,15],
[20,21,22,23,24,25],
[30,31,32,33,34,35],
[40,41,42,43,44,45],
[50,51,52,53,54,55]])
a[0, 3:5]
a[4:, 4:]
a[:, 2]
a[2::2, ::2]
a = np.array([0,1,2,3,4])
b = a[2:4].copy()
b[0] = 10
a
##搞懂切片和直接复制之间的区别
4.3 花式索引 (比较花)
a = np.arange(0, 80, 10)
indices = [1, 2, -3]
y = a[indices]
print( y)
mask = np.array([0,1,1,0,0,1,0,0],
dtype=bool)
a[mask]
from numpy.random import rand
a = rand(10)
mask = a > 0.5
a[mask]
a = np.array([[ 0, 1, 2, 3, 4, 5],
[10,11,12,13,14,15],
[20,21,22,23,24,25],
[30,31,32,33,34,35],
[40,41,42,43,44,45],
[50,51,52,53,54,55]])
#####################二维花式索引################
#对于二维花式索引,我们需要给定 row 和 col 的值
#################################
a[(0,1,2,3,4), (1,2,3,4,5)]
a[3:, [0,2,5]]
mask = np.array([1,0,1,0,0,1],
dtype=bool)
a[mask, 2]
花式索引返回的是复制而不是引用
a = np.arange(64)
a.shape = 4,4,4
y = a[:,:,[2, -1]]
y
4.4 where语句
where
函数会返回所有非零元素的索引。
a = np.array([0, 12, 5, 20])
a > 10
np.where(a > 10)
注意到 where
的返回值是一个元组。
使用元组是由于 where 可以对多维数组使用,此时返回值就是多维的。
在使用的时候,我们可以这样:
a = np.array([[0, 12, 5, 20],
[1, 2, 11, 15]])
loc = np.where(a > 10)
a[loc]
rows, cols = np.where(a>10)
a[rows, cols]
五、排序和方法
5.1 排序
names = np.array(['bob', 'sue', 'jan', 'ad'])
weights = np.array([20.8, 93.2, 53.4, 61.8])
np.sort(weights)
ordered_indices = np.argsort(weights)
ordered_indices
names[ordered_indices]
#沿着最后一维开始排序
a = np.array([
[.2, .1, .5],
[.4, .8, .3],
[.9, .6, .7]
])
np.sort(a)
np.sort(a, axis = 0)
#默认沿着每一行排序
searchsorted(sorted_array, values)
searchsorted
接受两个参数,其中,第一个必需是已排序的数组。
sorted_array = np.linspace(0,1,5)
values = np.array([.1,.8,.3,.12,.5,.25])
np.searchsorted(sorted_array, values)
searchsorted
返回的值相当于保持第一个数组的排序性质不变,将第二个数组中的值插入第一个数组中的位置:
例如 0.1
在 [0.0, 0.25]
之间,所以插入时应当放在第一个数组的索引 1
处,故第一个返回值为 1
。
from numpy.random import rand
data = rand(100)
data.sort()
bounds = .4, .6
low_idx, high_idx = np.searchsorted(data, bounds)
data[low_idx:high_idx]
5.2 方法
arr = np.random.randn(5,4)
arr.mean()
np.mean
arr.sum()
np.sum(arr)
arr.mean(axis=1)
arr.sum(0)
arr = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8]])
arr.cumsum(axis=0)
arr.cumprod(axis=0)
# fromfunction函数的第一个参数为计算每个数组元素的函数,第二个参数为数组的大小(shape)
#因为 它支持多维数组,所以第二个参数必须是一个序列,本例中用(10,)创建一个10元素的一维数组
def func(i):
return i % 4 + 1
print(np.fromfunction(func, (10,)))
创建一个二维数组表示九九乘法表,输出的数组a中的每个元素a[i, j]都等于func2(i, j)
def func2(i, j):
return (i + 1) * (j + 1)
a = np.fromfunction(func2, (9, 9))
print(a)
#求积
a.prod()
np.prod(a, axis=0)
a.min()
a.min(axis=0)
a.max()
a.max(axis=0)
a.argmin()
a.argmin(axis=0)
a.argmax()
a.argmax(axis=0)
a.clip(30,50)
#把数值限定在30和50之间
a.ptp(axis=1)
a.ptp()
#最大值和最小值之差
# np.reshape(np1, (2,6)) # 返回形状为(2,6)的新矩阵
# np.ravel(np1) # 返回元素平铺
# np.vstack((np1, np2)) # 纵向连接
# np.hstack((np1, np2)) # 横向连接
# np.vsplit(np1, n) # 纵向拆分(横向hsplit)
# np.concatnate((np1,np2), axis) # 按轴拼接
# np.where(cond, v1, v2) # 符合cond条件,返回v1,否则v2
# np1.T # transpose() : 求取转置矩阵
# np.swapaxes(np1, 0, 1) # 交换轴元素
# np.abs(np1) # fabs(np1) : 求取元素级整数,浮点数的绝对值
# np.sqrt(np1) # 求取各元素的平方根,相当于np1 ** 0.5
# np.square(np1) # 求取元素级的平方,相当于np1 ** 2
# np.exp(np1) # 对各元素求取e^*,组成新数组返回
# np.log # log10, log2, log1p : 对各元素求取底数为e,10, 2,(1+x)的对数
# np.sign(np1) # 计算各元素的符号,正数为1,零为0, 负数为-1
# np.ceil() # floor(), rint(): 圆整,ceil求取大于等于该元素的最小整数,rint是四舍五入
# np.modf(np1) # 返回浮点数的小数和整数两个数组
# np.isnan() # isfinite, isinf : 对各元素的判断,返回bool型数组,不是一个数字,有穷的,无穷的
# np.cos() # cosh(), sin(), sinh() : 三角函数
创建一个 3x3 的二维数组,并将列按升序排序
创建一个长度为 5 的一维数组,并将其中最大值替换成 0
将随机二维数组按照第 3 列从上到下进行升序排列
从随机一维数组中找出距离给定数值(0.5)最近的数
a = np.array(([1,4,3],[6,2,9],[4,7,2]))
返回每列最大值
返回每行最小值
返回每列最大值索引
返回每行最小值索引
统计数组各列的中位数
统计数组各行的算术平均值
统计数组各列的加权平均值
统计数组各行的方差
统计数组各列的标准偏差
六、数组形状
6.1 更改形状
b = np.arange(24).reshape(2, 3, 4)
print(b)
print(b.ravel())
print(b.flatten())
b.shape = (6, 4)
print(b)
print(b.transpose())
print(b.T)
b.resize((2, 12))
print(b)
#使用 newaxis 增加数组维数
a = np.arange(3)
a.shape
y = a[np.newaxis, :]
np.shape(y)
y = a[np.newaxis, np.newaxis, :]
np.shape(y)
6.2 数组合并
a = np.arange(9).reshape(3, 3)
print(a)
b = 2 * a
print(b)
print(np.vstack((a, b))) #纵向合并数组,由于与堆栈类似,故命名为vstack
print(np.concatenate((a, b), axis=0))
print(np.hstack((a, b))) #横向合并数组
print(np.concatenate((a, b), axis=1))
print(np.dstack((a, b)))
print(np.column_stack((a, b)))
print(np.column_stack((a, b)) == np.hstack((a, b)))
print(np.row_stack((a, b)))
print(np.row_stack((a, b)) == np.vstack((a, b)))
oned = np.arange(2)
print(oned)
twice_oned = 2 * oned
print(twice_oned)
print(np.column_stack((oned, twice_oned)))
print(np.row_stack((oned, twice_oned)))
6.3 数组分割
a = np.arange(9).reshape(3, 3)
print(a)
print(np.split(a, 3, axis=1))
print(np.hsplit(a, 3)) # 将数组横向分为2部分
print(np.vsplit(a, 3))
# 数组纵向分为2部分
print(np.split(a, 3, axis=0))
c = np.arange(27).reshape(3, 3, 3)
print(c)
print(np.dsplit(c, 3))
6.4 复制与视图
当运算和处理数组时,它们的数据有时被拷贝到新的数组有时不是。这通常是新手的困惑之源。这有三种情况:
- 完全不拷贝
- 简单的赋值不拷贝数组对象或它们的数据。
a = np.arange(12)
b = a # no new object is created
b is a
b.shape = 3,4 # changes the shape of a
a.shape
- 视图(view)和浅复制
- 不同的数组对象分享同一个数据。视图方法创造一个新的数组对象指向同一数据。
c = a.view()
c is a
c.base is a
c.shape = 2,6 # a's shape doesn't change
a.shape
c[0,4] = 1234 # a's data changesa
a
s = a[ : , 1:3] # spaces added for clarity; could also be written "s = a[:,1:3]"
s[:] = 10 # s[:] is a view of s. Note the difference between s=10 and s[:]=10
#切片就是返回一个视图
- 深复制
- 这个方法完全复制数组和它的数据
d = a.copy() # a new array object with new data is created
d is a
题目
a = np.random.randint(10, size=(3, 3))
b = np.random.randint(10, size=(3, 3))
水平拼合数组
垂直拼合数组
沿横轴分割数组
沿纵轴分割数组
七、随机函数
np.random.rand(2, 3, 4)
np.random.randn(2, 3, 4)
m = np.random.randint(20, 300, (3, 4))
m
np.random.seed(10) # 种子
np.random.shuffle(m)
np.random.permutation(m)
随机漫步
随机漫步(Random walk),也称随机游走,是一种数学统计模型,它由一连串轨迹所组成,其中每一次都是随机的,它能用来表示不规则的变动形式,如同一个人乱步所形成的随机记录。
随机游走的一个基本例子是整数线上的随机游走,从0开始,每一步以相同的概率移动+1或-1。
八、线性代数
#一维的数据斜率
c = np.arange(15)
np.gradient(c)
#二维的数据斜率,两个方向
c = np.arange(15).reshape(3,5)
np.gradient(b)
x = np.arange(9).reshape((3,3))
print(x)
# 取对角线上的数据
print(np.diag(x))
# k>0,主对角线之上
print(np.diag(x, k=1))
# k<0,主对角线之下
print(np.diag(x, k=-1))
# 通过对角线上的数据数组创建矩阵
print(np.diag(np.diag(x)))
A = np.arange(9).reshape((3,3))
print(A)
B = np.arange(6).reshape((3,2))
print(B)
print(A.dot(B))
print(np.dot(A,B))
print(A.trace())
print(np.trace(A))
8.1 矩阵求逆
## 创建一个矩阵
A = np.mat("0 1 2; 1 0 3; 4 -3 8")
A
#用INV函数求逆
## 注:矩阵必须是方阵且可逆,否则会抛出LinAlgError异常。
inv = np.linalg.inv(A)
inv
# 验证一下求得对不对
A * inv
广义矩阵的逆
扩充了逆的范围,不局限于方阵了
使用numpy.linalg模块中的pinv函数进行求解。
注:inv函数只接受方阵作为输入矩阵,而pinv函数则没有这个限制
#搞个矩阵
E = np.mat("4 11 14;8 7 -2")
E
#算广义的逆
pinv = np.linalg.pinv(E)
E * pinv
8.2 解方程
函数solve可以求解形如 Ax = b 的线性方程组,其中 A 为矩阵,b 为一维或二维的数组,x 是未知变量
#方程为
#x-2y+z=0
#2y-8z=8
#-4x+5y+9z=-9
B = np.mat("1 -2 1; 0 2 -8; -4 5 9")
b = np.array([0,8,-9])
x = np.linalg.solve(B,b)
x
#验证一波
np.dot(B, x)
8.3 特征值和特征向量
注:特征值(eigenvalue)即方程 Ax = ax 的根,是一个标量。其中 A 是一个二维矩阵,x 是一个一维向量。
特征向量(eigenvector)是关于特征值的向量
函数 eigvals 函数可以计算矩阵的特征值,而 eig 函数可以返回一个包含特征值和对应的特征向量的元组
#来一个矩阵
C = np.mat("3 -2;1 0")
#求一下特征值
c0 = np.linalg.eigvals(C)
c0
# 求特征值和特征根,得到第一个为特征向量,第二个是特征根
np.linalg.eig(C)
8.4 奇异值分解(SVD)
SVD(Singular Value Decomposition,奇异值分解)是一种因子分解运算,将一个矩阵分解为3个矩阵的乘积
函数 svd 可以对矩阵进行奇异值分解,该函数返回3个矩阵--U、Sigma和V,其中U和V是正交矩阵,Sigma包含输入矩阵的奇异值
#搞个矩阵
D = np.mat("4 12 14;8 7 -2")
D
#奇异值分解一波,会生成三个矩阵
U, Sigma, V = np.linalg.svd(D,full_matrices=False)
print ("U:", U)
#将三个矩阵相乘
U * np.diag(Sigma) * V