阅读 330

python 科学计算的基石 numpy(一)

1. 简单介绍

行业常说的“数据分析三剑客”或者“机器学习三剑客”,指的就是 numpy(计算), matplotlib(可视化), pandas(分析) 这三个 python 库。如果拿自然科学学科类比,matplotlib 相当于“物理学”,pandas 相当于“化学”,而 numpy 就是“数学”, 是其他学科赖以立足的“基石”。

numpy 之所以是基石,是因为 numpy 为 matplotlib 和 pandas 等提供了底层数据结构和计算支持。而 numpy 核心数据结构就是多维数组(ndarray: N-dimensional array)。

2. 准备工作

这个小节过渡有点突兀,但是为了下一步顺利运行代码,不得不强行插播这条“准备工作”。

2.1 安装

2.1.1 检查是否安装

conda list | grep numpy
复制代码

或:

pip freeze | grep numpy
复制代码

2.1.2 安装

已安装,请跳过。

conda install numpy
复制代码

或:

pip install numpy
复制代码

2.1.3 更新

已安装,可选择更新。

conda update numpy
复制代码

或:

pip install --upgrade numpy
复制代码

2.2 导入

np 为行业惯例缩写。

import numpy as np
复制代码

3. 多维数组(numpy.ndarray: N-dimensional array)

如果熟悉 matlab (矩阵实验室),我们知道 matlab 科学计算建立在“矩阵”之上。而,numpy 的多维数组有异曲同工之妙。

3.1 创建

3.1.1 使用 np.array() 创建

以下通过一个二维列表创建一个 numpy 多维数组(numpy.ndarray) 。在 numpy 中,维度这个概念也叫 ,英文叫Axes ,因此,这里创建的二维数组,我们也可以称之为为 2 的多维数组,它包含了 2 个轴(Axis)。数组的 shape 属性是一个元组,对应多维数组每个 轴(Axis) 长度;size 属性是多维数组所有元素个数,它等于 shape 所有元素的乘积。

说起来很复杂,但是实际很简单,通过下面的打印输出,我们可以很直观的理解,各个属性之间的关系。

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

print(
    """
    对象类型:\t{}\n
    形状:\t{}\n
    维度(秩):\t{}\n
    元素个数:\t{}\n
    元素类型:\t{}\n
    """
    .format(type(na), na.shape, na.ndim, na.size, na.dtype))

na
复制代码
    对象类型:	<class 'numpy.ndarray'>

    形状:	(2, 3)

    维度(秩):	2

    元素个数:	6

    元素类型:	int64

    





array([[1, 2, 3],
       [4, 5, 6]])
复制代码

3.1.2 使用 np.zeros() 创建

如果不是事先就知道各元素的数值,使用 np.array() 的方式,难免有些繁琐,相比之下,只是先初始化一个全为 0 的多维数组,np.zeros() 无疑是更适合的选择。使用 np.zeros() 只需提供 shape 参数,也是第一个位置参数,就可以创建指定 shape 的多维数组,并将数组所有元素填充为 0 。

na = np.zeros((2, 3))

print("dtype: ", na.dtype)

na
复制代码
dtype:  float64





array([[0., 0., 0.],
       [0., 0., 0.]])
复制代码

从上面打印的 dtype 属性可以看到,默认元素的数据类型是 float64 。当然,如果不想使用默认类型,可以通过 dtype 参数来设置。

na = np.zeros((2, 3), dtype="uint8")

print("dtype: ", na.dtype)

na
复制代码
dtype:  uint8





array([[0, 0, 0],
       [0, 0, 0]], dtype=uint8)
复制代码

3.1.3 使用 np.ones() 创建

np.ones() 和 np.zeros 除了填充的不是 0,而是 1,其他都一样。

np.ones((2, 3), dtype="float")
复制代码
array([[1., 1., 1.],
       [1., 1., 1.]])
复制代码

3.1.4 np.arange()

range() 的 numpy 版本实现。传入 start, end, step 参数创建一个1维 numpy 数组。

np.arange(2, 10, 2)
复制代码
array([2, 4, 6, 8])
复制代码

虽然 np.arange() 方法只能创建 1 维数组,但是借助 numpy 数组的 reshape() 方法可以在 size 不变的情况下,改变 shape 。注意,reshape() 方法是 numpy 数组实例的方法,因此,它适用于任何想要“重塑”shape场景,包括下面介绍的 np.linsapce() 使用场景。

np.arange(2, 13, 2).reshape(2, 3)
复制代码
array([[ 2,  4,  6],
       [ 8, 10, 12]])
复制代码

除了 reshape() 方法可以改变 shape 外,还有一个方法 resize() 也有相同的功能,区别是,reshape() 不会改变原来的数组,而 resize 会改变。

a = np.arange(2, 13, 2)
b = a.reshape(2, 3)

print("after call a.reshape():")
print("a.shape", a.shape)
print("b.shape", b.shape)
a.resize(2, 3)
print("after call a.resize():")
print("a.shape", a.shape)
复制代码
after call a.reshape():
a.shape (6,)
b.shape (2, 3)
after call a.resize():
a.shape (2, 3)
复制代码

3.1.5 np.linspace()

和 np.arange() 很像,也是创建一个 start 到 end 区间的1维 numpy 数组。但有两点不同:

  1. linsapce 第3个参数不是步长,而是区间内的多少个点
  2. 结果包含 end ,而 np.arange() 不包含 end
np.linspace(2, 10, 5)
复制代码
array([ 2.,  4.,  6.,  8., 10.])
复制代码

3.1.6 np.random.random()

指定 shape 生成随机数填充。

np.random.random((2, 3))
复制代码
array([[0.22031976, 0.91591833, 0.63773627],
       [0.92104449, 0.69246379, 0.82988843]])
复制代码

3.1.7 np.random.normal(mu, sigma, len)

创建均值为 mu , 标准差为 sigma, 长度为 len 标准正态分布的一维数组。

import matplotlib.pyplot as plt
%matplotlib inline

mu = 2
sigma = 0.5
v = np.random.normal(mu, sigma, 10000)

plt.hist(v, bins=50, density=1)
plt.show()
复制代码

3.2 读取

3.2.1 元组索引

元组长度等于数组维度(Axes 秩),也就是多维数组的每个轴(Axis)都有个索引,元组括号可省略。

na = np.random.random((2, 3))

print(na[(1, 2)])
print(na[1, 2])
复制代码
0.7547734386512726
0.7547734386512726
复制代码

3.2.2 普通多维列表方式

na[1][2]
复制代码
0.7547734386512726
复制代码

3.3 统计运算

3.3.1 求最大值

v = np.random.normal(10, 1, 10000)

v.max()
复制代码
13.949035793082137
复制代码

3.3.2 求最小值

v.min()
复制代码
6.31475048427698
复制代码

3.3.3 求和

v.sum()
复制代码
100051.11447780298
复制代码

3.3.4 求均值

v.mean()
复制代码
10.005111447780298
复制代码

3.3.5 求标准差

v.std()
复制代码
0.996315432751019
复制代码

3.3.6 求中位数

np.median(v)
复制代码
10.005551763169866
复制代码

3.4 为什么要使用 numpy 多维数组

到此,你可能会有疑问,感觉 numpy 多维数组也不过如此,和列表差不多啊。对,从结构和使用方式上,的确 numpy 多维数组和列表有诸多相似的地方。在大数据分析,机器学习上尤其是深度学习,等需要对大量数据进行计算的场景,它的性能将远超普通列表。

下面计算一个长度为 300,000,000 (3亿)的数组的均值,分布使用列表和 numpy 数组计算。前者用了 15 秒,后者只用不到 2 毫秒。为什么会有这么大的差距,原因在于,numpy 底层运算是用 C 语言实现的,而 C 语言的性能相比于 python 是不言而喻的。

from time import time

a = list(range(300000000))
na = np.array(na)

start_time = time()
sum(a) / len(a)
print("calculate mean by list cost time {} s".format(time() - start_time))

start_time = time()
na.mean()
print("calculate mean by numpy.ndarray cost time {} s".format(time() - start_time))
复制代码
calculate mean by list cost time 20.95879817008972 s
calculate mean by numpy.ndarray cost time 0.0011792182922363281 s
复制代码

猜你喜欢


坚持写专栏不易,如果觉得本文对你有帮助,记得点个赞。感谢支持!


微信扫描二维码 获取最新技术原创

关注下面的标签,发现更多相似文章
评论