参考书籍:《Python数据科学手册》
NumPy库笔记精选
0.引言
不同类型间的数据存在明显的异构性,将所有数据简单地看作数字数组非常有助于我们理解和处理数据。 不管数据是何种形式,第一步都可将这些数据转换成数值数组形式的可分析数据。
正因如此,有效地存储和操作数值数组是数据科学中绝对的基础过程。而Python中专门用来处理这些数值数组的工具有:NumPy 包和 Pandas 包。
NumPy(Numerical Python 的简称)提供了高效存储和操作密集数据缓存的接口。在某些方面,NumPy 数组与 Python 内置的列表类型非常相似。但是随着数组在维度上变大,NumPy 数组提供了更加高效的存储和数据操作。NumPy 数组几乎是整个 Python 数据科学工具生态系统的核心。
1.Python中的数据类型
首先应了解Python 语言中数据数组是如何被处理的,并对比 NumPy 所做的改进,理解这个不同之处。
Python动态推断数据类型。Python 变量不仅是它们的值,还包括了关于值的类型的一些额外信息。
1.1 整型
标准的 Python 实现是用 C 语言编写的。这意味着每一个 Python 对象都是一个聪明的伪 C语言结构体。例如,定义 x = 1 时,x 是一个指针,指向一个 C 语言的复合结构体,结构体里包含了一些值。
C 语言整型本质上是对应某个内存位置的标签,里面存储的字节会编码
成整型。 而 Python 的整型其实是一个指针,指向包含这个 Python 对象所有信息的某个内存位置,其中包括可以转换成整型的字节。由于 Python 的整型结构体里面还包含了大量额外的信息,所以 Python 可以自由、动态地编码。 但是,Python 类型中的这些额外信息也会成为负担,在多个对象组合的结构体中尤其明显。
1.2 列表
为了获得灵活的类型,Python列表中的每一项必须包含各自的类型信息、引用计数和其他信息;也就是说,每一项都是一个完整的Python 对象。 一个特殊的例子,如果列表中的所有变量都是同一类型的,那么很多信息都会显得多余——将数据存储在固定类型(NumPy 式)的数组中应该会更高效。
Python 列表包含一个指向指针块的指针,这其中的每一个指针对应一个完整的 Python 对象。固定类型的 NumPy 式数组缺乏这种灵活性,但是能更有效地存储和操作数据。
1.3 Python中的固定类型数组
可通过array(内置模块)、numpy库实现,更实用的是 NumPy 包中的 ndarray 对象。
1.4 从Python列表创建数组
不同于 Python 列表,NumPy 要求数组必须包含同一类型的数据。 如果类型不匹配,NumPy 将会向上转换(如果可行)。此外,NumPy 数组可以被指定为多维。
1.5 从头创建数组(很多方法需要了解)
面对大型数组的时候,用 NumPy 内置的方法从头创建数组是一种更高效的方法。
如:zeros、arange、linspace、random.normal、empty……
1.6 NumPy标准数据类型
2.NumPy数组基础
基本的数组操作:属性、索引、切分、变形、拼接分裂。
2.1 属性
.ndim维度,.shape每个维度的大小,.size数组的总大小(维度相乘), itemsize每个数组元素字节大小的,nbytes数组总字节大小。
2.2 索引
如 name[2, -1] 或 name[2][-1] 索引多维。
当试图将一个浮点值插入一个整型数组时,浮点值会被截短成整型。并且这种截短是自动完成的,不会给你提示或警告。
2.3 切片
NumPy 切片语法和 Python 列表的标准切片语法相似。x[start:stop:step]。(步长可为负)
多维用逗号分开维度
数组切片返回的是数组数据的视图,而不是数值数据的副本。 这一点也是 NumPy 数组切片和 Python 列表切片的不同之处:在Python 列表中,切片是值的副本。 NumPy中,如果修改子数组,将会看到原始数组也被修改。
这种默认的处理方式实际上非常有用:它意味着在处理非常大的数据集时,可以获取或处理这些数据集的片段,而不用复制底层的数据缓存。
当然,也可以很简单地通过 copy() 方法创建数组的副本。
2.4 数组的变形
数组变形最灵活的实现方式是通过 reshape() 函数来实现。
如果希望该方法可行,那么原始数组的大小必须和变形后数组的大小一致。如果满足这个条件,reshape 方法将会用到原始数组的一个非副本视图。但实际情况是,在非连续的数据缓存的情况下,返回非副本视图往往不可能实现。
将一个一维数组转变为二维的行或列的矩阵,可以通过reshape 方法来实现,或者更简单地在一个切片操作中利用newaxis 关键字。
2.5 数组拼接和分裂(多个数组)
拼接:np.concatenate、np.vstack(垂直栈) 和 np.hstack(水平栈)。
分裂:np.split、np.hsplit 和 np.vsplit。(np.dsplit 将数组沿着第三个维度分裂。)
可以向以上函数传递一个索引列表作为参数,索引列表记录的是分裂点位置。
3.NumPy数组的计算:通用函数
3.1 缓慢的loop
Python 的默认实现(被称作 CPython)处理起某些操作时非常慢,一部分原因是该语言的动态性和解释性——数据类型灵活的特性决定了序列操作不能像 C 语言和 Fortran 语言一样被编译成有效的机器码。