写点什么

NumPy 之:NumPy 简介教程

发布于: 2021 年 04 月 21 日

简介

NumPy 是一个开源的 Python 库,主要用在数据分析和科学计算,基本上可以把 NumPy 看做是 Python 数据计算的基础,因为很多非常优秀的数据分析和机器学习框架底层使用的都是 NumPy。比如:Pandas, SciPy, Matplotlib, scikit-learn, scikit-image 等。

NumPy 库主要包含多维数组和矩阵数据结构。 它为 ndarray(一个 n 维数组对象)提供了对其进行有效操作的方法。 NumPy 可以用于对数组执行各种数学运算。 并且提供了可在这些数组和矩阵上运行的庞大的高级数学函数库。

安装 NumPy

有很多方式可以按照 NumPy:

pip install numpy
复制代码

如果你使用的是 conda,那么可以:

conda install numpy
复制代码

或者直接使用 Anaconda. 它是一系列数据分析包的集合。

Array 和 List

Python 中有一个数据类型叫做 List,list 中可以存储不同种类的对象。在应用程序中这样做没有什么问题,但是如果是在科学计算中,我们希望一个数组中的元素类型必须是一致的,所以有了 NumPy 中的 Array。

NumPy 可以快速的创建 Array,并且对其中的数据进行操作。

NumPy 中的 Array 要比 Python 中的 List 要快得多,并且占用更少的内存空间。

看下两者之间的性能差异:

In [1]: import numpy as np   ...: my_arr = np.arange(1000000)   ...: my_list = list(range(1000000))   ...: %time for _ in range(10): my_arr2 = my_arr * 2   ...: %time for _ in range(10): my_list2 = [x * 2 for x in my_list]   ...:CPU times: user 12.3 ms, sys: 7.88 ms, total: 20.2 msWall time: 21.4 msCPU times: user 580 ms, sys: 172 ms, total: 752 msWall time: 780 ms
复制代码

上面的例子对一个包含一百万的数据进行乘 2 操作,可以看到,使用 NumPy 的效率是 Python 的几十倍,如果在大型数据项目中这个效率会造成非常大的性能影响。

创建 Array

上面的例子中,我们已经创建了一个 array,使用的是 np.arange 方法。

我们还可以通过 List 来创建 Array,List 可以是一维列表,也可以是多维列表:

>>> a = np.array([1, 2, 3, 4, 5, 6])
>>> a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
复制代码

和 List 一样,Array 也可以通过 index 来访问:

>>> print(a[0])[1 2 3 4]
复制代码

接下来我们介绍几个常用的名词:

  • vector — 表示的是一维数组

  • matrix — 表示的是二维数组

  • tensor — 表示的是三维或者更高维度的数组

在 NumPy 中维度也被称之为 axes 。

下面我们来看下其他几种创建 Array 的方法:

最简单的就是 np.array,之前的例子中我们已经提到过了。

如果要快速的创建都是 0 的数组,我们可以使用 zeros:

>>> np.zeros(2)array([0., 0.])
复制代码

或者都填充为 1:

>>> np.ones(2)array([1., 1.])
复制代码

还可以创建空的数组:

In [2]: np.empty(2)Out[2]: array([0.        , 2.00389455])
复制代码

注意,empty 方法中的内容并不一定是空的,而是随机填充数据,所以我们在使用 empty 创建数组之后,一定要记得覆盖其中的内容。使用 empty 的好处就是创建的速度比较快。

还可以在 range 范围内填充数组:

In [3]: np.arange(10)Out[3]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
复制代码

可以指定间隔:

In [4]: np.arange(1,10,2)Out[4]: array([1, 3, 5, 7, 9])
复制代码

使用 linspace 可以创建等分的数组:

In [5]: np.linspace(0, 10, num=5)Out[5]: array([ 0. ,  2.5,  5. ,  7.5, 10. ])
复制代码

默认情况下创建的数组内容类型是 np.float64,我们还可以将其切换成整数:np.int64

In [6]: x = np.ones(2, dtype=np.int64)
In [7]: xOut[7]: array([1, 1])
复制代码

Array 操作

sort

我们可以使用 sort 对数组进行排序:

In [8]: arr = np.array([2, 1, 5, 3, 7, 4, 6, 8])
In [10]: np.sort(arr)Out[10]: array([1, 2, 3, 4, 5, 6, 7, 8])
复制代码

sort 是对 Array 中的元素进行排序, 除了 sort 之外还有其他的一些排序的方法。

还可以使用 argsort,argsort 是一种间接排序的方法,他返回的是排序好的原数组的 index:

In [11]: x = np.array([10, 5, 6])
In [12]: np.argsort(x)Out[12]: array([1, 2, 0])
复制代码

上面我们对 array 进行 argsort,排序之后应该返回,5,6,10。 5 的 index 是 1,6 的 index 是 2,10 的 index 是 0,所以返回 1,2,0。

lexsort 和 argsort 一样都是间接排序法,返回的都是排序过后的 index,不同是 lexsort 可以进行多 key 的排序。

surnames =    ('Hertz',    'Galilei', 'Hertz')first_names = ('Heinrich', 'Galileo', 'Gustav')ind = np.lexsort((first_names, surnames))indarray([1, 2, 0])
复制代码

上面的 lexsort 是先按照 surnames 排序,然后再按照 first_names 进行排序。

lexsort 的排序顺序是从后到前。也就是最后一个传入的 key 最先排序。

searchsorted 用来查找要插入元素的 index 值,举个例子:

np.searchsorted([1,2,3,4,5], 3)2np.searchsorted([1,2,3,4,5], 3, side='right')3np.searchsorted([1,2,3,4,5], [-10, 10, 2, 3])array([0, 5, 1, 2])
复制代码

partition 是对要排序的数据进行分割,举个例子:

a = np.array([3, 4, 2, 1])np.partition(a, 3)array([2, 1, 3, 4])
复制代码

第一个参数是一个 Array,第二个参数是要分隔的基准元素,这个基准元素的位置和排序过后的位置是一样的,其他的元素比基准元素小的放在前面,比基准元素大的放在后面。

还可以按照多个元素进行分割:

np.partition(a, (1, 3))array([1, 2, 3, 4])
复制代码

concatenate

concatenate 用来连接多个数组。

>>> a = np.array([1, 2, 3, 4])>>> b = np.array([5, 6, 7, 8])
>>> np.concatenate((a, b))array([1, 2, 3, 4, 5, 6, 7, 8])
复制代码

还可以连接多维数组:

>>> x = np.array([[1, 2], [3, 4]])>>> y = np.array([[5, 6]])>>> np.concatenate((x, y), axis=0)array([[1, 2],       [3, 4],       [5, 6]])
复制代码

统计信息

ndarray.ndim 用来统计数组的维数:

>>> array_example = np.array([[[0, 1, 2, 3],...                            [4, 5, 6, 7]],......                           [[0, 1, 2, 3],...                            [4, 5, 6, 7]],......                           [[0 ,1 ,2, 3],...                            [4, 5, 6, 7]]])
复制代码


>>> array_example.ndim3
复制代码

ndarray.size 用来统计数组中的元素个数:

>>> array_example.size24
复制代码

ndarray.shape 输出数组的形状:

>>> array_example.shape(3, 2, 4)
复制代码

说明上面的数组是一个 3 * 2 * 4 的数组。

reshape

使用 reshape 可以重新构造一个数组。

>>> a = np.arange(6)>>> print(a)[0 1 2 3 4 5]
>>> b = a.reshape(3, 2)>>> print(b)[[0 1] [2 3] [4 5]]
复制代码

上面我们将一个一维的数组转成了一个 3* 2 的数组。

reshape 还可以接受多个参数:

>>> numpy.reshape(a, newshape=(1, 6), order='C')array([[0, 1, 2, 3, 4, 5]])
复制代码

第一个参数是要重构的数组,第二个参数新的 shape,order 可以取三个值,C,F 或者 A。

C 表示按照 C 的 index 方式进行排序,F 表示按照 Fortran 的 index 方式进行排序。A 表示自动选择。

在 Fortran 中,当移动存储在内存中的二维数组的元素时,第一个索引是变化最快的索引。 当第一个索引更改时移动到下一行时,矩阵一次存储一列。另一方面,在 C 中,最后一个索引变化最快。

增加维度

np.newaxis 可以给现有的数组增加一个维度:

>>> a = np.array([1, 2, 3, 4, 5, 6])>>> a.shape(6,)
>>> a2 = a[np.newaxis, :]>>> a2.shape(1, 6)
>>> col_vector = a[:, np.newaxis]>>> col_vector.shape(6, 1)
复制代码

还可以使用 expand_dims 来指定 axis 的位置:

>>> b = np.expand_dims(a, axis=1)>>> b.shape(6, 1)
>>> c = np.expand_dims(a, axis=0)>>> c.shape(1, 6)

复制代码

index 和切片

数组的 index 和切片跟 Python 中的 list 是类似的:

>>> data = np.array([1, 2, 3])
>>> data[1]2>>> data[0:2]array([1, 2])>>> data[1:]array([2, 3])>>> data[-2:]array([2, 3])
复制代码

除此之外,数组还支持更多更强大的 index 操作:

>>> a = np.array([[1 , 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
>>> print(a[a < 5])[1 2 3 4]
复制代码

上面我们找出了 a 中所有元素小于 5 的值。

In [20]: a<5Out[20]:array([[ True,  True,  True,  True],       [False, False, False, False],       [False, False, False, False]])
复制代码

可以看到 a< 5 其实返回的也是一个数组,这个数组的元素 shape 和原数组是一样的,只不过里面的值是 true 和 false,表示是否应该被选择出来。

同样的,我们可以挑出所有大于 5 的元素:

>>> five_up = (a >= 5)>>> print(a[five_up])[ 5  6  7  8  9 10 11 12]
复制代码

选出所有可以被 2 整除的数:

>>> divisible_by_2 = a[a%2==0]>>> print(divisible_by_2)[ 2  4  6  8 10 12]
复制代码

还可以使用 & 和 | 运算符:

>>> c = a[(a > 2) & (a < 11)]>>> print(c)[ 3  4  5  6  7  8  9 10]
复制代码

还可以使用 nonzero 来打印出满足条件的 index 信息:

In [23]: a = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
In [24]: b = np.nonzero(a < 5)
In [25]: bOut[25]: (array([0, 0, 0, 0]), array([0, 1, 2, 3]))
>>> print(a[b])[1 2 3 4]
复制代码

上面返回的元组中,第一个值表示的是行号,第二个值表示的是列。

从现有数据中创建 Array

我们可以使用 slicing , indexing,np.vstack(),np.hstack(),np.hsplit(),.view(),copy() 来从现有数据中创建 Array。

前面的例子中,我们看到可以使用 List 和切片来创建新的数组:

>>> a = np.array([1,  2,  3,  4,  5,  6,  7,  8,  9, 10])>>> arr1 = a[3:8]>>> arr1array([4, 5, 6, 7, 8])
复制代码

两个现有的数组可以进行垂直或者水平堆叠:

>>> a1 = np.array([[1, 1],...                [2, 2]])
>>> a2 = np.array([[3, 3],... [4, 4]])
>>> np.vstack((a1, a2))array([[1, 1], [2, 2], [3, 3], [4, 4]])
>>> np.hstack((a1, a2))array([[1, 1, 3, 3], [2, 2, 4, 4]])
复制代码

使用 hsplit 可以将大的数组分割成为几个小的数组:

>>> x = np.arange(1, 25).reshape(2, 12)>>> xarray([[ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12],       [13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]])
>>> np.hsplit(x, 3)[array([[1, 2, 3, 4], [13, 14, 15, 16]]), array([[ 5, 6, 7, 8], [17, 18, 19, 20]]), array([[ 9, 10, 11, 12], [21, 22, 23, 24]])]

复制代码

算数运算

array 的加法:

>>> data = np.array([1, 2])>>> ones = np.ones(2, dtype=int)>>> data + onesarray([2, 3])
复制代码

其他的运算:

>>> data - onesarray([0, 1])>>> data * dataarray([1, 4])>>> data / dataarray([1., 1.])
复制代码

array 求和:

>>> a = np.array([1, 2, 3, 4])
>>> a.sum()10
复制代码

如果是求和多维数组的话,需要指定维度:

>>> b = np.array([[1, 1], [2, 2]])>>> b.sum(axis=0)array([3, 3])
>>> b.sum(axis=1)array([2, 4])
复制代码

其他有用操作

这里列出了其他的有用操作:

>>> data.max()2.0>>> data.min()1.0>>> data.sum()3.0
复制代码

对于二维数组来说,sum 默认会求和所有的元素,min 也会从所有元素中查找最小的:

>>> a = np.array([[0.45053314, 0.17296777, 0.34376245, 0.5510652],...               [0.54627315, 0.05093587, 0.40067661, 0.55645993],...               [0.12697628, 0.82485143, 0.26590556, 0.56917101]])
>>> a.sum()4.8595784
>>> a.min()0.05093587
复制代码

我们还可以指定维度:

>>> a.min(axis=0)array([0.12697628, 0.05093587, 0.26590556, 0.5510652 ])
复制代码

矩阵

矩阵就是 2 * 2 的数组:

>>> data = np.array([[1, 2], [3, 4]])>>> dataarray([[1, 2],       [3, 4]])
复制代码

矩阵同样可以进行统计操作:

>>> data.max()4>>> data.min()1>>> data.sum()10
复制代码

默认情况是累加所有的元素,我们也可以指定特定的累加维度:

>>> data.max(axis=0)array([3, 4])>>> data.max(axis=1)array([2, 4])
复制代码

矩阵的运算:

>>> data = np.array([[1, 2], [3, 4]])>>> ones = np.array([[1, 1], [1, 1]])>>> data + onesarray([[2, 3],       [4, 5]])
复制代码

如果是多维的和低维的进行运算,那么将会使用内置的 broadcast 机制,将低维的进行广播:

>>> data = np.array([[1, 2], [3, 4], [5, 6]])>>> ones_row = np.array([[1, 1]])>>> data + ones_rowarray([[2, 3],       [4, 5],       [6, 7]])
复制代码

生成随机数

在机器学习中,生成随机数是一个非常重要的功能。我们看下如何在 Numpy 中生成随机数。

>>> rng = np.random.default_rng(0)>>> rng.random(3)array([0.63696169, 0.26978671, 0.04097352])
>>> rng.random((3, 2))array([[0.01652764, 0.81327024], [0.91275558, 0.60663578], [0.72949656, 0.54362499]]) # may vary
>>> rng.integers(5, size=(2, 4))array([[2, 1, 1, 0], [0, 0, 0, 4]]) # may vary
复制代码

unique

np.unique可以统计数组的唯一值:

>>> a = np.array([11, 11, 12, 13, 14, 15, 16, 17, 12, 13, 11, 14, 18, 19, 20])
>>> unique_values = np.unique(a)>>> print(unique_values)[11 12 13 14 15 16 17 18 19 20]
复制代码

还可以返回 index 或者 count:

>>> unique_values, indices_list = np.unique(a, return_index=True)>>> print(indices_list)[ 0  2  3  4  5  6  7 12 13 14]
复制代码


>>> unique_values, occurrence_count = np.unique(a, return_counts=True)>>> print(occurrence_count)[3 2 2 2 1 1 1 1 1 1]
复制代码

对矩阵也适用:

>>> a_2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [1, 2, 3, 4]])
>>> unique_values = np.unique(a_2d)>>> print(unique_values)[ 1 2 3 4 5 6 7 8 9 10 11 12]
复制代码

如果想得到唯一的行或者列,可以传入 axis 参数:

>>> unique_rows = np.unique(a_2d, axis=0)>>> print(unique_rows)[[ 1  2  3  4] [ 5  6  7  8] [ 9 10 11 12]]
复制代码

矩阵变换

我们可以使用 transpose 来把矩阵的行和列进行调换:

>>> arr = np.arange(6).reshape((2, 3))>>> arrarray([[0, 1, 2],       [3, 4, 5]])
>>> arr.transpose()array([[0, 3], [1, 4], [2, 5]])
复制代码

反转数组

使用 flip 可以反转数组:

>>> arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])>>> reversed_arr = np.flip(arr)>>> print('Reversed Array: ', reversed_arr)Reversed Array:  [8 7 6 5 4 3 2 1]
复制代码

如果是 2 维的数组:

>>> arr_2d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
>>> reversed_arr = np.flip(arr_2d)>>> print(reversed_arr)[[12 11 10 9] [ 8 7 6 5] [ 4 3 2 1]]
复制代码

默认会反转行和列,我们也可以只反转行或者列:

>>> reversed_arr_rows = np.flip(arr_2d, axis=0)>>> print(reversed_arr_rows)[[ 9 10 11 12] [ 5  6  7  8] [ 1  2  3  4]]
>>> reversed_arr_columns = np.flip(arr_2d, axis=1)>>> print(reversed_arr_columns)[[ 4 3 2 1] [ 8 7 6 5] [12 11 10 9]]
复制代码

还可以只反转一行或者一列:

>>> arr_2d[1] = np.flip(arr_2d[1])>>> print(arr_2d)[[ 1  2  3  4] [ 8  7  6  5] [ 9 10 11 12]]
>>> arr_2d[:,1] = np.flip(arr_2d[:,1])>>> print(arr_2d)[[ 1 10 3 4] [ 8 7 6 5] [ 9 2 11 12]]
复制代码

flatten 和 ravel

flatten 可以将数组变成一维的:

>>> x = np.array([[1 , 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
>>> x.flatten()array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
复制代码

flatten 之后的数组和原数组是无关的,我们修改 flatten 之后的数组不会改变之前的数组内容:

>>> a1 = x.flatten()>>> a1[0] = 99>>> print(x)  # Original array[[ 1  2  3  4] [ 5  6  7  8] [ 9 10 11 12]]>>> print(a1)  # New array[99  2  3  4  5  6  7  8  9 10 11 12]
复制代码

但是如果使用 ravel,对新数组的修改同样也会改变原始数组:

>>> a2 = x.ravel()>>> a2[0] = 98>>> print(x)  # Original array[[98  2  3  4] [ 5  6  7  8] [ 9 10 11 12]]>>> print(a2)  # New array[98  2  3  4  5  6  7  8  9 10 11 12]
复制代码

save 和 load

NumPy 的对象可以通过 save 和 load 存放到文件和从文件中加载:

>>> a = np.array([1, 2, 3, 4, 5, 6])
>>> np.save('filename', a)
>>> b = np.load('filename.npy')
复制代码

如果想以文本的方式来存储,那么可以使用 np.savetxt:

>>> csv_arr = np.array([1, 2, 3, 4, 5, 6, 7, 8])
>>> np.savetxt('new_file.csv', csv_arr)
>>> np.loadtxt('new_file.csv')array([1., 2., 3., 4., 5., 6., 7., 8.])
复制代码

CSV

NumPy 有专门的方法来对 CSV 文件进行操作:

>>> import pandas as pd
>>> # If all of your columns are the same type:>>> x = pd.read_csv('music.csv', header=0).values>>> print(x)[['Billie Holiday' 'Jazz' 1300000 27000000] ['Jimmie Hendrix' 'Rock' 2700000 70000000] ['Miles Davis' 'Jazz' 1500000 48000000] ['SIA' 'Pop' 2000000 74000000]]
>>> # You can also simply select the columns you need:>>> x = pd.read_csv('music.csv', usecols=['Artist', 'Plays']).values>>> print(x)[['Billie Holiday' 27000000] ['Jimmie Hendrix' 70000000] ['Miles Davis' 48000000] ['SIA' 74000000]]
复制代码

本文已收录于 http://www.flydean.com/01-python-numpy-basic/

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

发布于: 2021 年 04 月 21 日阅读数: 18
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
NumPy之:NumPy简介教程