240 NumPy 数值计算更高效的案列
Python 已经提供了很多丰富的内置包,我们为什么还要学习 NumPy 呢?
先看一个例子,找寻学习 NumPy 的必要性和重要性。
打开 IPython
,创建 Python 的列表 a
对象。然后,使用列表生成式,创建一个元素都为原来两倍的新列表 a2
,并统计这一行的用时为 95.7 ms
.
In [76]: a = list(range(1000000))
In [77]: %time a2 = [i*2 for i in a]
Wall time: 95.7 ms
使用 NumPy,创建同样大小和取值的数组 na
。然后,对每个元素乘以 2,返回一个新数组 na2
,用时为 2 ms
。
In [78]: import numpy as np
In [79]: na = np.array(range(1000000))
In [80]: %time na2 = na * 2
Wall time: 2 ms
完成同样的都对元素乘以 2 的操作,NumPy 比 Python 快了 45 倍之多。
这就是我们要学好 NumPy 的一个重要理由,它在处理更大数据量时,处理效率明显快于 Python ;并且内置的向量化运算和广播机制,使得使用 NumPy 更加简洁,会少写很多嵌套的 for 循环,因此代码的可读性大大增强。
252 NumPy 计算为什么如此快?
有多个原因:
- Python的 list 是一个通用结构。它能包括任意类型的对象,并且是动态类型。
- NumPy 的 ndarray 是静态、同质的类型,当 ndarray 对象被创建时,元素的类型就确定。由于是静态类型,所以 ndarray 间的加、减、乘、除用 C 和 Fortran 实现才成为可能,所以运行起来就会更快。根据官当介绍,底层代码用
C
语言和Fortran
语言实现,实现性能无限接近 C 的处理效率。
由此可见,NumPy 就非常适合做大规模的数值计算和数据分析。
今天,我们一起学习 NumPy 的基本使用,借助实际的 iris
数据集,使用例子帮助大家最快掌握 NumPy 那些最高频使用的函数。
241 创建 NumPy 数组五种常用方法
创建一个 ndarray
数组对象,有很多种方法。array
函数能创建新的数组;arange
, linspace
等方法;从文件中读入数据返回一个 ndarray
对象;多个 ndarray
对象又能构造生成一个新的 ndarray
对象。
- 通过构造函数
array
创建一维array
:
import numpy as np
In [2]: v = np.array([1,2,3,4])
In [3]: v
Out[3]: array([1, 2, 3, 4])
- 创建二维
array
:
In [4]: m = array([[1,2],[3,4]])
In [5]: m
Out[5]:
array([[1, 2],
[3, 4]])
v 和 m 的类型都是 ndarray
,NumPy 中最主要的数据结构。
In [6]: type(v),type(m)
Out[6]: (numpy.ndarray, numpy.ndarray)
-
arange
数组
In [94]: ara = np.arange(1,10)
In [95]: ara
Out[95]: array([1, 2, 3, 4, 5, 6, 7, 8, 9])
-
linspace
数组,15 个元素:
In [97]: np.linspace(1,10,15)
Out[97]:
array([ 1. , 1.64285714, 2.28571429, 2.92857143, 3.57142857,
4.21428571, 4.85714286, 5.5 , 6.14285714, 6.78571429,
7.42857143, 8.07142857, 8.71428571, 9.35714286, 10. ])
- 组合
ndarray
对象:
如下创建一个 ndarray
对象 a
:
In [98]: a = np.arange(10).reshape(2,-1)
In [99]: a
Out[99]:
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
找出 a
中大于 3 的元素索引,使用 where
方法,返回一个元组,带有 2 个 ndarray
对象,分别表示大于 3 的元素第一维、第二维度中的位置:
In [100]: np.where(a>3)
Out[100]:
(array([0, 1, 1, 1, 1, 1], dtype=int64),
array([4, 0, 1, 2, 3, 4], dtype=int64))
where
方法返回值可读性不强,我们把它拼接为一个 ndarray
对象:
In [101]: np.array(np.where(a>3))
Out[101]:
array([[0, 1, 1, 1, 1, 1],
[4, 0, 1, 2, 3, 4]], dtype=int64)
然后,再转置,使用 np.transpose
方法:
tuple_to_array = np.array(np.where(a>3))
np.transpose(tuple_to_array)
结果,这回一看就明白了,[0,4]
表示在原 ndarray
对象 a
上的索引:
Out[102]:
array([[0, 4],
[1, 0],
[1, 1],
[1, 2],
[1, 3],
[1, 4]], dtype=int64)