43.Python编程:NumPy详解

前言

numpy是支持 Python语言的数值计算扩充库,其拥有强大的高维度数组处理与矩阵运算能力。除此之外,numpy还内建了大量的函数,方便你快速构建数学模型。

NumPy官网:http://www.numpy.org/
NumPy官网教程:https://docs.scipy.org/doc/numpy/user/quickstart.html

安装及导入numpy

安装numpy:

pip install numpy

导入numpy,推荐做法是:

import numpy as np

当然,如果你不想像上面导入,你也可以和其他模块导入方式一样直接import numpy,但还是推荐用import numpy as np这种方式,后面用到numpy的地方都可以用别名np了,更加简洁。

numpy数学中的计算

学习完后,可以熟练掌握数组各种方式的创建、属性及数组操作;对矩阵的常见操作、也可以对多项式求导、作图等。

1.求矩阵A的秩
提示:在线性代数中,一个矩阵A的列秩是A的线性独立的纵列的极大数目。类似地,行秩是A的线性无关的横行的极大数目。通俗一点说,如果把矩阵看成一个个行向量或者列向量,秩就是这些行向量或者列向量的秩,也就是极大无关组中所含向量的个数。

矩阵A

解析:在numpy中,求矩阵的秩用nf.linalg.matrix_rank(array)

2.求矩阵A的转置矩阵
转置矩阵:将矩阵的行列互换得到的新矩阵称为转置矩阵,转置矩阵的行列式不变。
解析:在numpy中,求矩阵A的转置矩阵用A.T
上面两个问题用numpy可快速计算出来:

import numpy as nf

A = nf.mat([[3, 2, 0, 5, 0],
            [3, -2, 3, 6, -1],
            [2, 0, 1, 5, -3],
            [1, 6, -4, -1, 4]])

print("矩阵A:")
print(A)
print("A的秩为:{}".format(nf.linalg.matrix_rank(A)))

print("A的转置矩阵:")
print(A.T)

运行结果:

矩阵A:
[[ 3  2  0  5  0]
 [ 3 -2  3  6 -1]
 [ 2  0  1  5 -3]
 [ 1  6 -4 -1  4]]

A的秩为:3

A的转置矩阵:
[[ 3  3  2  1]
 [ 2 -2  0  6]
 [ 0  3  1 -4]
 [ 5  6  5 -1]
 [ 0 -1 -3  4]]

手动求解:


手动求解矩阵A的秩

3.求矩阵A的逆矩阵
说明:逆矩阵是对方阵定义的,因此逆矩阵一定是方阵。
逆矩阵:设A是数域上的一个n阶矩阵,若在相同数域上存在另一个n阶矩阵B,使得: AB=BA=E ,则我们称B是A的逆矩阵,而A则被称为可逆矩阵。注:E为单位矩阵。

矩阵A

解析:在numpy中,求矩阵A的转置矩阵用A.I

import numpy as nf

A = nf.mat([[0, 1, 2],
            [1, 1, 4],
            [2, -1, 0]])

print("矩阵A:")
print(A)

print("A的逆矩阵:")
print(A.I)

运行结果:

矩阵A:
[[ 0  1  2]
 [ 1  1  4]
 [ 2 -1  0]]

A的逆矩阵:
[[ 2.  -1.   1. ]
 [ 4.  -2.   1. ]
 [-1.5  1.  -0.5]]

手动计算:


手动计算求矩阵A的逆矩阵

4.求y = -2x^2 + 4x + 16的根,并求出其导函数

多项式 -2x^2 + 4x + 16的图像

解析:为了形象展示多项式,我们借用matplotlib顺便绘制了该函数的图像。后面会专门学习如何绘制,此处大概了解一下matplotlib即可。numpy中的多项式:np.poly1d(arr),需要把参数传入。本例子中放在了一个数组中arr = np.array([-2, 4, 16])传入的。对多项式求导,想要求几阶导数,只需要这里实参m传入数字几即可。func.deriv(m=1);定制定义域np.linspace(-4, 6, 100),这样把-6--6之间进行100等分,利用这些数据创建了一个长度为100的数组。

import numpy as np
import matplotlib.pyplot as plt

# y = -2x^2 + 4x + 16
arr = np.array([-2, 4, 16])
func = np.poly1d(arr)

# m=1表示求一阶导数,依次类推
func1 = func.deriv(m=1)

# 设置定义域-4,6;并将定义域等分了100份
x = np.linspace(-4, 6, 100)

y = func(x)
y1 = func1(x)


# 打印多项式
print(func)

# 打印多项式对应的一阶导数
print(func1)

# 绘制
plt.plot(x, y, label="{}".format(func))
plt.plot(x, y1, label="{}".format(func1))
plt.xlabel("x")
plt.ylabel("y")

# 显示图例
plt.legend()

print("多项式的根:")
print(np.roots(func))

# 显示图像
plt.show()

运行结果:


多项式求根及一阶导数

数组的重要属性

numpy的主要操作对象是同类的多维数组,即一个由相同类型元素(通常是数字)组成的、以正数为索引的数据表。在numpy里面,维度称为“轴”。

举例来说,三维空间内一点的坐标[1,2,1]有一个轴,三个元素,所以我们通常称它的长度为3。在以下所示的例子中,数组有两个轴,第一个轴的长度为2,第二个轴的长度为3。

[[ 1., 0., 0.],
 [ 0., 1., 2.]]

numpy的数组类型叫做ndarray,也就是numpy数组(以下简称为数组)。需要注意的是,numpy.array不同于Python标准库中的array.array,后者只处理一维的数组并且提供了很少的功能。一个ndarray对象有以下一些重要的属性:

  • ndarray.ndim

数组的轴的数量,即维度数量。

  • ndarray.shape

数组的维度。返回的是一个整数元组,指示了一个数组在各个维度的大小。对于一个n行m列的矩阵来说,它的shape(n,m)shape的元组长度因此是轴的数量,即ndim

  • ndarray.size

数组所有元素的数量,等于shape返回元组元素的乘积。

  • ndarray.dtype

一个用于描述数组元素类型的对象。可以用标准Python类型来创造或指定dtype的类型。另外,Numpy也提供了自己的类型,如numpy.int32numpy.int16numpy.float64等。

  • ndarray.itemsize

数组每个元素的字节大小。比如一个数组的元素为float64,它的itemsize8(=64/8)

complex32itemsize4(=32/8)。这个属性等同于ndarray.dtype.itemsize

  • ndarray.data

包含了数组每个实际元素的缓冲器。一般来说我们不会用到这个属性因为我们可以通过索引工具来获取到数组的每个元素的值。

数组的创建

通过上面知识,我们已经知道在numpy中,数组是ndarray类型的,接下来我们就看看学习如何利用numpy来创建各种数组。

1.利用构造函数array()创建

利用构造函数array()创建一维或多维数组,其参数是类似于数组的对象,如列表等。当然,也可以在创建的时候传入数据类型,通过dtype=指定,取值:
int系列包括np.int64(默认)、np.int16np.int32np.int128
float系列包括:np.float64(默认)、np.float16np.float32np.float84np.float96np.float128np.float256等,示例如下:

import numpy as np

# 构造函数构建
arr1 = np.array([[1, 2, 3],
                [4, 5, 6]])

# 创建的同时指定数据类型为float64
arr2 = np.array([[11, 22, 33],
                [44, 55, 66]], dtype=np.float64)

print(arr1)
print(arr2)

运行结果:

[[1 2 3]
 [4 5 6]]

[[11. 22. 33.]
 [44. 55. 66.]]
2.利用arrange()创建

numpyarrange()的用法和Pythonrange()一样,我们可以直接传入一个size,也可以指定起始值-结束值-步长,numpyarrange()还可以重新定义reshape(shape),如下面例子2.3中:np.arange(12).reshape((3, 4))。示例如下:

import numpy as np

# 2.1利用arrange()来创建
arr3 = np.arange(12)
print(arr3)
print("-" * 20)

# 2.2利用arrange()来创建,
arr4 = np.arange(10, 21)
print(arr4)
print("+" * 20)

# 2.3利用arrange()来创建,重新定义shape
arr5 = np.arange(12).reshape((3, 4))
print(arr5)

运行结果:

[ 0  1  2  3  4  5  6  7  8  9 10 11]
--------------------
[10 11 12 13 14 15 16 17 18 19 20]
++++++++++++++++++++
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
3.生产随机数来创建

利用np.random.random(12)会生产一系列从0-1之间的符合标准正态分布随机数组成的数组。我们指定随机数的个数,即要得到的数组长度,还可以在创建的同时重新定义shape:np.random.random((3, 4))。示例如下,要注意观察不同:

import numpy as np

# 3.1 利用随机数创建数组
random_arr4 = np.random.random(12)
print(random_arr4)

print("-" * 20)

# 3.2 利用随机数创建数组, 并指定shape
random_arr5 = np.random.random((3, 4))
print(random_arr5)

运行结果:

[0.47430035 0.27107492 0.786811  0.4158894  0.09536015  0.87473283  0.10045984 0.70662808 0.15931372 0.96116861 0.45779735 0.18718144]
--------------------
[[0.4010681  0.0760198  0.03891688 0.80331814]
 [0.33589807 0.43356063 0.79576128 0.74174092]
 [0.31945365 0.21740648 0.68029056 0.32781636]]
4.利用linspace()线性等分来创建

numpylinspace(start, end, total_count)线性等分来创建数组时,需要传入起始值、结束值、将这段数等分为total_count份。

这种创建方式特别适用于:知道起始值、结束值和总个数的情况。常用来设置自变量的取值,例如:x = np.linspace(-10, 10, 100),将会得到(-10, 10)等分100份后的数据组成的数组。

import numpy as np

# 4 利用线性等分,创建数组
x = np.linspace(-10, 10, 50)
print(x)

运行结果:

[-10.          -9.59183673  -9.18367347  -8.7755102   -8.36734694
  -7.95918367  -7.55102041  -7.14285714  -6.73469388  -6.32653061
  -5.91836735  -5.51020408  -5.10204082  -4.69387755  -4.28571429
  -3.87755102  -3.46938776  -3.06122449  -2.65306122  -2.24489796
  -1.83673469  -1.42857143  -1.02040816  -0.6122449   -0.20408163
   0.20408163   0.6122449    1.02040816   1.42857143   1.83673469
   2.24489796   2.65306122   3.06122449   3.46938776   3.87755102
   4.28571429   4.69387755   5.10204082   5.51020408   5.91836735
   6.32653061   6.73469388   7.14285714   7.55102041   7.95918367
   8.36734694   8.7755102    9.18367347   9.59183673  10.        ]
5.全为0的数组np.zeros(shape)

numpy提供了可以直接创建所有元素为0的数组,方式为:np.zeros(shape)

官网的解释:The function zeros creates an array full of zeros,示例如下:

import numpy as np

# 5 全为0的数组
arr5 = np.zeros((3, 4))
print(arr5)

运行结果:

[[0. 0. 0. 0.]
 [0. 0. 0. 0.]
 [0. 0. 0. 0.]]
6.全为1的数组np.ones(shape)

numpy提供了可以直接创建所有元素为1的数组,方式为:np.ones(shape)

官网的解释:the function ones creates an array full of ones,示例如下:

import numpy as np

# 6 全为1的数组
arr6 = np.ones((2, 3, 4))
print(arr6)

运行结果:

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

 [[1. 1. 1. 1.]
  [1. 1. 1. 1.]
  [1. 1. 1. 1.]]]
7.空元素数组

numpy提供了可以直接创建所有元素为1的数组,方式为:np.empty(shape),要注意的是它的元素的初始值是随机的,这取决于这块内存中的值。

官网的解释:the function empty creates an array whose initial content is random and depends on the state of the memory. By default, the dtype of the created array is float64,示例如下:

import numpy as np

# 创建空元素数组
arr7 = np.empty((3, 4))
print(arr7)
numpy中dtype类型
numpy数组生成函数汇总表

数组的常见操作

1.基本运算
  • 加、减、乘、除(+、-、*、/)

对两个数组做加(减、乘、除)法运算,是对应位置的元素分别做加(减、乘、除)法运算。
示例如下:

import numpy as np

arr1 = np.array([[11, 12, 13],
                 [14, 15, 16]])

arr2 = np.array([[1, 2, 3],
                 [4, 5, 6]])

print("arr1:")
print(arr1)
print("arr2:")
print(arr2)

print("arr1 + arr2 = ")
print(arr1 + arr2)

print("arr1 - arr2 = ")
print(arr1 - arr2)

print("arr2 * arr1 = ")
print(arr2 * arr1)

print("arr1 / arr2 = ")
print(arr1 / arr2)

运行结果:

arr1:
[[11 12 13]
 [14 15 16]]

arr2:
[[1 2 3]
 [4 5 6]]

arr1 + arr2 = 
[[12 14 16]
 [18 20 22]]

arr1 - arr2 = 
[[10 10 10]
 [10 10 10]]

arr2 * arr1 = 
[[11 24 39]
 [56 75 96]]

arr1 / arr2 = 
[[11.          6.          4.33333333]
 [ 3.5         3.          2.66666667]]

说明:对两个数组做加(减、乘、除)法运算,是对应位置的元素分别做加(减、乘、除)法运算。正因为如此规则,所以要求参与运算的两个数组为同形数组,也就是要求shape必须一样,否则会报错ValueError: operands could not be broadcast together with shapes

下面例子中,保持arr1shape(2, 3)不变;利用reshape()修改arr2shape(6,),此时再进行加法运算操作:

import numpy as np

arr1 = np.array([[11, 12, 13],
                 [14, 15, 16]])

arr2 = np.array([[1, 2, 3],
                 [4, 5, 6]]).reshape((6,))

print("arr1:")
print(arr1)
print("arr2:")
print(arr2)

print("arr1 + arr2 = ")
print(arr1 + arr2)

运算结果:

Traceback (most recent call last):
  File "D:/TensorFlowProjects/np_numpy/numpy_jianshu.py", line 15, in <module>
    print(arr1 + arr2)
ValueError: operands could not be broadcast together with shapes (2,3) (6,) 
  • 多次方(**)

在numpy中,多次方运算同样作用于数组中每个元素。运算符号为**,运算符**后面是几就做几次运算。同样要求参与运算的两个数组为同形数组,也就是要求shape必须一样,否则会报错ValueError: operands could not be broadcast together with shapes

例如:arr1 ** 2表示对数组arr1中每个元素做平方运算。
再如:arr1 ** 3表示对数组arr1中每个元素做3次方运算。

import numpy as np

arr1 = np.arange(6).reshape((2, 3))
print("arr1: ")
print(arr1)

print("-" * 20)

# 2次方运算
print(arr1 ** 2)

print("-" * 20)

# 3次方运算
print(arr1 ** 3)

运算结果:

arr1: 
[[0 1 2]
 [3 4 5]]
--------------------
[[ 0  1  4]
 [ 9 16 25]]
--------------------
[[  0   1   8]
 [ 27  64 125]]
  • 矩阵乘

矩阵乘是用np提供的dot,形如:np.dot(arr1, arr2)arr1.dot(arr2)。需要注意的是,参与运算的两个数组要符合矩阵乘的乘法要求:前一个矩阵的列必须等于后一个矩阵的行。如果不满足此,则会运行报错。

下面例子,3行4列 x 4行2列,计算后将会得到3行2列的矩阵。

import numpy as np


arr1 = np.arange(12).reshape((3, 4))
arr2 = np.arange(8).reshape((4, 2))
print("arr1 = ")
print(arr1)
print("arr2 = ")
print(arr2)

print("-" * 20)
print(np.dot(arr1, arr2))

print("+" * 20)
print(arr1.dot(arr2))

运算结果:

arr1 = 
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
arr2 = 
[[0 1]
 [2 3]
 [4 5]
 [6 7]]
--------------------
[[ 28  34]
 [ 76  98]
 [124 162]]
++++++++++++++++++++
[[ 28  34]
 [ 76  98]
 [124 162]]

提示:
如果你在运算过程中遇到ValueError: shapes (3,4) and (3,2) not aligned: 4 (dim 1) != 3 (dim 0),则说明参与运算的两个矩阵不符合矩阵乘的运算规则:前一个矩阵的列必须等于后一个矩阵的行。

  • 和数值比较

和数值比较,形如arr1 > 3,会把数组中每个元素和该数值3进行比较,满足则为True,不满足则为False,最后会得到一个由True、False组成的数组。

import numpy as np


arr1 = np.array([[0, 2, 4],
                 [1, 3, 5]])
print(arr1 > 3)

运算结果:

[[0 2 4]
 [1 3 5]]

[[False False  True]
 [False False  True]]
  • 求和

numpy中求和提供了sum,可以计算一个数组中所有元素的和np.sum(arr),也可以指定计算某个轴上的和np.sum(arr,axis=0或1或2等)

如果是2维数组,axis=0表示计算列上的和;axis=1表示计算行上的和;

import numpy as np

arr_2d = np.arange(12).reshape((3, 4))
print(arr_2d)

# 计算所有元素的和
print(np.sum(arr_2d))
print("-" * 20)
# 计算指定轴上的元素的和
print(np.sum(arr_2d, axis=0))
print("-" * 20)
print(np.sum(arr_2d, axis=1))

运行结果:

[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
66
--------------------
[12 15 18 21]
--------------------
[ 6 22 38]

如果是3维数组,形如shape 为 (2, 3, 4)的,此时axis=0表示计算shape(3, 4)数组求和,计算后会得到一个(3, 4)数组。;axis=1表示计算列上的和,计算后会得到一个(2, 4)数组;axis=2表示计算行上的和,计算后会得到一个(2, 3)数组;

import numpy as np

arr_3d = np.arange(24).reshape((2, 3, 4))
print(arr_3d)

# 计算所有元素的和
print("所有元素的和:{}".format(np.sum(arr_3d)))

# 计算指定轴上的元素的和
print("axis=0,shape=(2, 3, 4),会得到(3, 4)的数组:")
print(np.sum(arr_3d, axis=0))

print("axis=1,shape=(2, 3, 4),会得到(2, 4)的数组:")
print(np.sum(arr_3d, axis=1))

print("axis=2,shape=(2, 3, 4),会得到(2, 3)的数组:")
print(np.sum(arr_3d, axis=2))

运行结果:

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

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]

所有元素的和:276

axis=0,shape=(2, 3, 4),会得到(3, 4)的数组:
[[12 14 16 18]
 [20 22 24 26]
 [28 30 32 34]]

axis=1,shape=(2, 3, 4),会得到(2, 4)的数组:
[[12 15 18 21]
 [48 51 54 57]]

axis=2,shape=(2, 3, 4),会得到(2, 3)的数组:
[[ 6 22 38]
 [54 70 86]]

如果是更高维数组,则依次类推。关键是区分轴序号代表的是什么。

  • 求最大值

numpy中求最大值提供了max,可以计算一个数组中所有元素中最大的元素np.max(arr),也可以指定计算某个轴上的最大的元素np.max(arr,axis=0或1或2等)

求最大值所在的索引,np.argmax(arr,axis=0或1或2等)

import numpy as np

arr_2d = np.array([[2, 4, 6],
                   [1, 3, 5]])
print(arr_2d)

# 数组中最大元素
print("数组中最大元素{}".format(np.max(arr_2d)))

print("数组中最大元素索引{}".format(np.argmax(arr_2d)))

# 2维的轴axis=0上的最大值,也即列上的最大值
print("列上的最大值{}".format(np.max(arr_2d, axis=0)))

运行结果:

[[2 4 6]
 [1 3 5]]
数组中最大元素:6
数组中最大元素索引:2
列上的最大值:[2 4 6]
  • 求最小值

numpy中求最小值提供了min,可以计算一个数组中所有元素最小元素值np.min(arr),也可以指定计算某个轴上的最小元素值np.min(arr,axis=0或1或2等)

求最小值所在的索引,np.argmin(arr,axis=0或1或2等)

import numpy as np

arr_2d = np.array([[2, 4, 6],
                   [1, 3, 5]])
print(arr_2d)

# 数组中最小元素
print("数组中最小元素:{}".format(np.min(arr_2d)))

print("数组中最小元素索引:{}".format(np.argmin(arr_2d)))

# 2维的轴axis=0上的最小值,也即列上的最小值
print("列上的最小值:{}".format(np.min(arr_2d, axis=0)))

运行结果:

[[2 4 6]
 [1 3 5]]
数组中最小元素:1
数组中最小元素索引:3
列上的最小值:[1 3 5]
  • 求平均数、中位数、加权平均数

numpy中求平均数、中位数、加权平均数,分别提供了mean(arr)media(arr)average(arr),也可以指定计算某个轴上的平均数、中位数、加权平均数。

import numpy as np

arr_2d = np.arange(12).reshape((3, 4))

# 权重,加权平均数时用到了
weights = np.array([[1, 1, 1, 1],
                    [1, 1, 1, 1],
                    [1, 1, 1, 2]])

print(arr_2d)
print(weights)

print("平均数{}".format(np.mean(arr_2d)))
print("中位数{}".format(np.median(arr_2d)))
print("加权平均数{}".format(np.average(arr_2d, weights=weights)))

运算结果:

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

[[1 1 1 1]
 [1 1 1 1]
 [1 1 1 2]]

平均数5.5
中位数5.5
加权平均数5.923076923076923
  • 累和

numpy中求累和提供了cumsum,可以计算一个数组中求累和np.cumsum(arr),也可以指定计算某个轴上求累和np.cumsum(arr,axis=0或1或2等)

import numpy as np

arr1 = np.arange(6)
print(arr1)

# 求累和
print(np.cumsum(arr1))

运算结果:

[0 1 2 3 4 5]
[ 0  1  3  6 10 15]

累和计算规则如图:


累和计算规则
  • 累差

numpy中求累和提供了diff,可以计算一个数组中求累和np.diff(arr),也可以指定计算某个轴上求累和np.diff(arr,axis=0或1或2等)

import numpy as np

arr1 = np.array([1, 3, 5, 2, 4, 6])
print(arr1)

# 求累差
print(np.diff(arr1))

运行结果:

[1 3 5 2 4 6]
[ 2  2 -3  2  2]
累差
  • 非零元素

numpy中找一个数组中非零元素提供了np.nonzero(arr),示例如下:

import numpy as np

arr_2d = np.arange(12).reshape((3, 4))
print(arr_2d)

print(np.nonzero(arr_2d))

运行结果:

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

(array([0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2], dtype=int64), 
 array([1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3], dtype=int64))

解析:调用非零元素方法得到了(array([0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2], dtype=int64), array([1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3], dtype=int64)),由于原数组是2维的,所以打印结果中这个包含两个数组,分别表示:非零元素所在的行的索引组成的数组,非零元素所在的列的索引组成的数组。

可以看到除了(0,0)处的元素外,其余都非零,所以有上面的打印结果。

  • 排序

numpy中排序提供了sort,可以指定某个轴上元素排序np.sort(arr,axis=0或1或2等),也可以指定排序使用的方法,kind数组排序时使用的方法。

a :所需排序的数组
axis:数组排序时的基准,axis=0,按行排列;axis=1,按列排列
kind:数组排序时使用的方法,其中: kind= ′ quicksort ′ 为快排;kind= ′ mergesort ′ 为混排;kind= ′ heapsort ′ 为堆排;
order:一个字符串或列表,可以设置按照某个属性进行排序。

import numpy as np

arr1 = np.array([[1, 13, 5, 12, 4, 6],
                [10, 11, 12, 7, 8, 9]])
print(arr1)

print("-" * 20)
print(np.sort(arr1))

print("-" * 20)
# axis=0 对每一列中的元素排序
print(np.sort(arr1, axis=0, kind="quicksort"))

print("-" * 20)

# axis=1 对每一行中的元素排序
print(np.sort(arr1, axis=1))

运行结果:

[[ 1 13  5 12  4  6]
 [10 11 12  7  8  9]]
--------------------
[[ 1  4  5  6 12 13]
 [ 7  8  9 10 11 12]]
--------------------
[[ 1 11  5  7  4  6]
 [10 13 12 12  8  9]]
--------------------
[[ 1  4  5  6 12 13]
 [ 7  8  9 10 11 12]]
  • 矩阵的转置

numpy对矩阵的转置提供了多种实现方式,最常用的arr.Tnp.transpose(arr)。需要注意的是,numpy提供了迭代行,并没有提供直接迭代列。若要迭代列,一般都是先转置一下再迭代行就行了。

import numpy as np

arr_2d = np.arange(12).reshape((3, 4))
print(arr_2d)

print("-" * 20)

# 矩阵的转置,方式1
print(arr_2d.T)

print("-" * 20)

# 矩阵的转置,方式2
print(np.transpose(arr_2d))

运行结果:

[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]
--------------------
[[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]]
--------------------
[[ 0  4  8]
 [ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]]
  • 数据裁剪处理

numpy对数组中的元素提供了裁剪处理的方法np.clip(arr, min, max), 对该函数的理解:小于最小值得按最小值处理;大于最大值的按最大值处理,处于最小值和最大值之间的保留原数据。示例如下:

import numpy as np

arr_2d = np.arange(12).reshape((3, 4))
print(arr_2d)

# 数据的裁剪
print(np.clip(arr_2d, 5, 8))

运行结果:

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

[[5 5 5 5]
 [5 5 6 7]
 [8 8 8 8]]
  • 展开铺平

numpy对数组中可以重新定义shape, 方法是reshape(shape),也提供了降维处理,直接展开铺平为一维arr.flatten()。示例如下:

import numpy as np

arr_2d = np.arange(12).reshape((3, 4))
print(arr_2d)

# 展开铺平操作
print(arr_2d.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]
2.array合并

数组的合并,分为在垂直方向合并np.vstack((arr1, arr2))和在水平方向合并np.hstack((arr1, arr2))

import numpy as np


arr1 = np.array([1, 1, 1])
arr2 = np.array([2, 2, 2])
print(arr1)
print("-" * 10)
print(arr2)

print("在列方向合并:")
print(np.vstack((arr1, arr2)))

print("在行方向合并:")
print(np.hstack((arr1, arr2)))

运行结果:

[1 1 1]
----------
[2 2 2]

在列方向合并:
[[1 1 1]
 [2 2 2]]

在行方向合并:
[1 1 1 2 2 2]

当然,也可以使用np.concatenate((arr1, arr2), axis=0或1或2等):

import numpy as np


arr1 = np.array([[1, 2],
                [3, 4]])
arr2 = np.array([[5, 6]])
print(arr1)
print("-" * 10)
print(arr2)

print("在垂直方向合并:")
print(np.concatenate((arr1, arr2), axis=0))

print("在水平方向合并:")
print(np.concatenate((arr1, arr2.T), axis=1))

运行结果:

[[1 2]
 [3 4]]
----------
[[5 6]]

在列方向合并:
[[1 2]
 [3 4]
 [5 6]]

在行方向合并:
[[1 2 5]
 [3 4 6]]
3.array分割

数组的拆分,分为在垂直方向拆分np.vsplit(arr1, 几等分)和在水平方向拆分np.hsplit(arr1, 几等分)

import numpy as np

arr_2d = np.arange(24).reshape((4, 6))
print(arr_2d)

# 在垂直方向上等分2份
print(np.vsplit(arr_2d, 2))

# 在水平方向上等分2份
print(np.hsplit(arr_2d, 2))

运行结果:

[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]

[array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11]]), 
array([[12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23]])]

[array([[ 0,  1,  2],
       [ 6,  7,  8],
       [12, 13, 14],
       [18, 19, 20]]), 
array([[ 3,  4,  5],
       [ 9, 10, 11],
       [15, 16, 17],
       [21, 22, 23]])]

当然,也可以使用np.split(arr1, axis=0或1或2等):

import numpy as np

arr_2d = np.arange(24).reshape((4, 6))
print(arr_2d)

# 在垂直方向上等分2份
print(np.split(arr_2d, 2, axis=0))

# 在水平方向上等分3份
print(np.split(arr_2d, 3, axis=1))

运行结果:

[[ 0  1  2  3  4  5]
 [ 6  7  8  9 10 11]
 [12 13 14 15 16 17]
 [18 19 20 21 22 23]]

[array([[ 0,  1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10, 11]]), 
array([[12, 13, 14, 15, 16, 17],
       [18, 19, 20, 21, 22, 23]])]

[array([[ 0,  1],
       [ 6,  7],
       [12, 13],
       [18, 19]]),
 array([[ 2,  3],
       [ 8,  9],
       [14, 15],
       [20, 21]]), 
array([[ 4,  5],
       [10, 11],
       [16, 17],
       [22, 23]])]
4.array的copy

numpy中数组的赋值操作,默认是不进行拷贝的。下面例子中,arr1 和arr2指向了内存中的同一内存地址,是不同变量指向了同一对象。

import numpy as np

# 创建数组arr1
arr1 = np.array([[1, 2, 3],
                 [4, 5, 6]])

# 把数组arr1赋值给数组arr2,
arr2 = arr1

print(arr1)
print(arr2)

# arr1和arr2是否同一对象
print(arr1 is arr2)

运行结果:

[[1 2 3]
 [4 5 6]]

[[1 2 3]
 [4 5 6]]

True

通过一个变量修改数组的值,由于两个数组变量指向同一对象,所以另一处的值也是被修改后的:

# 上接
arr1[1][1] = 15
print(arr1)
print(arr2)

运行结果:

[[ 1  2  3]
 [ 4 15  6]]

[[ 1  2  3]
 [ 4 15  6]]

上面例子中,之前一处两个变量指向的同一数组,数据发生了变化。是因为arr2 = arr1这句赋值操作默认采用的不拷贝。,如果,我想让arr1和arr2是独立的存在,当一处修改,另一处数据不变动。那么只需要赋值时采用copy复制一份即可。代码如下:

import numpy as np

# 创建数组arr1
arr1 = np.array([[1, 2, 3],
                 [4, 5, 6]])

# 把数组arr1赋值给数组arr2,
arr2 = arr1.copy()


print(arr1)
print(arr2)

# arr1和arr2是否同一对象
print("arr1和arr2是否同一对象:{}".format(arr1 is arr2))

# 修改arr1[1][1]的元素的值为15
arr1[1][1] = 15

print(arr1)
print(arr2)

运行结果:

[[1 2 3]
 [4 5 6]]

[[1 2 3]
 [4 5 6]]

arr1和arr2是否同一对象:False

[[ 1  2  3]
 [ 4 15  6]]

[[1 2 3]
 [4 5 6]]

说明:arr2 = arr1.copy()复制后,arr2arr1就相互独立,一个数据修改不再影响另一个数组中的数据了。

索引操作

numpy中数组是矩阵的基础,两种可以相互转化。数组操作中,索引的处理决定了操作哪些元素,因此索引操作变得至关重要。
一维数组,形如arr1=[0, 1, 2, 3, 4]arr1[1]拿到的是元素1;
一维数组,形如

[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]

此时arr1[1]拿到的是第1整行:[ 5 6 7 8 9];
arr1[1][1]拿到的是元素6;
arr1[:, 1]拿到的是第1整列:[ 1 6 11];
arr1[1, 1:3]拿到的是第1行第1~3列的元素:[ 6 7];

方差、标准差

numpy提供了计算方差、标准差的函数,在统计计算时非常有用:
计算数组的极差:np.pth(a)=max(a)-min(a)
计算方差(总体方差):np.var(a)
标准差:np.std(a)

import numpy as np

arr = np.arange(15).reshape((3, 5))
print(arr)
# 方差
print(np.var(arr))
# 标准差
print(np.std(arr))

运行结果:

[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]
18.666666666666668
4.320493798938574

多项式

多项式拟合:poly= np.polyfit(x,a,n),拟合点集a得到n级多项式,其中x为横轴长度,返回多项式的系数
多项式求导函数:np.polyder(poly),返回导函数的系数
得到多项式的n阶导函数:多项式.deriv(m = n)
多项式求根:np.roots(poly)
多项式在某点上的值:np.polyval(poly,x[n]),返回poly多项式在横轴点上x[n]上的值
两个多项式做差运算: np.polysub(a,b)

线性代数基础运算

估计线性模型中的系数:a=np.linalg.lstsq(x,b),有b=a*x
求方阵的逆矩阵:np.linalg.inv(A)
求广义逆矩阵:np.linalg.pinv(A)
求矩阵的行列式:np.linalg.det(A)
解形如AX=b的线性方程组:np.linalg.solve(A,b)
求矩阵的特征值:np.linalg.eigvals(A)
求特征值和特征向量:np.linalg.eig(A)
Svd分解:np.linalg.svd(A)

概率分布

产生二项分布的随机数:np.random.binomial(n,p,size=…),其中n,p,size分别是每轮试验次数、概率、轮数
产生超几何分布随机数:np.random.hypergeometric(n1,n2,n,size=…),其中参数意义分别是物件1总量、物件2总量、每次采样数、试验次数
产生N个正态分布的随机数:np.random.normal(均值,标准差,N)
产生N个对数正态分布的随机数:np.random.lognormal(mean,sigma,N)

小结

本文学习了numpy的常用用法,具体包括:如何安装及导入numpy、数组的重要属性、数组的多种创建方式、数组的常见操作、数组的合并、拆分;索引操作、多项式、方差、标准差、概率分布等知识。这一节知识是后面学习PandasTensorFlow的基础,务必掌握。

参考资料:NumPy官网教程(英文)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335