乐趣区

关于python:NumPy之NumPy简介教程

简介

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 ms
Wall time: 21.4 ms
CPU times: user 580 ms, sys: 172 ms, total: 752 ms
Wall 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]: x
Out[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))
ind
array([1, 2, 0])

下面的 lexsort 是先依照 surnames 排序,而后再依照 first_names 进行排序。

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

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

np.searchsorted([1,2,3,4,5], 3)
2
np.searchsorted([1,2,3,4,5], 3, side='right')
3
np.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.ndim
3

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

>>> array_example.size
24

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<5
Out[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]: b
Out[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]
>>> arr1
array([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)
>>> x
array([[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 + ones
array([2, 3])

其余的运算:

>>> data - ones
array([0, 1])
>>> data * data
array([1, 4])
>>> data / data
array([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]])
>>> data
array([[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 + ones
array([[2, 3],
       [4, 5]])

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

>>> data = np.array([[1, 2], [3, 4], [5, 6]])
>>> ones_row = np.array([[1, 1]])
>>> data + ones_row
array([[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))
>>> arr
array([[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/

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

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

退出移动版