简单整理了NumPy的一些特性,参考的是 《利用Python进行数据分析》( Wes McKinney 著),NumPy官方文档,菜鸟教程。
NumPy(Numerical Python的简称)是高性能科学计算和数据分析的基础包。而且NumPy会提供一个简单易用的C API,所以很容易把数据传递给由低级语言编写的外部库,外部库也能以NumPy数组的形式将数据返回给Python。
本文章的目录如下:
- ndarray对象
- NumPy数据类型
- 数组属性
- 切片和索引
- 运算——与标量之间 & 与数组之间(广播)
- 函数
- 数组操作
ndarray
NumPy的ndarray是一个n维数组对象,是一系列同类型数据的集合,以0为下标开始元素的索引。
可以利用这种对象对整块数据进行数学运算,语法跟标量之间的运算一样。
ndarray由以下内容组成:
- 一个指向数据的指针。
- 每个数组的
shape
属性表示各维度大小,是表示数组形状的元组。 -
dtype
属性说明数组类型的对象。 - 一个跨度元组
stride
,其中的整数指为了前进到当前维度下一个元素需要‘跨过’的字节数。
内部结构如下:
创建一个ndarray的方法是用NumPy中的array函数:
np.array(object, dtype = None, copy = True, order = None, subok = False, ndmin = 0)
参数参考这里。
它接收一切序列型的对象(包括其他数组),然后产生一个新的含有传入数据的NumPy数组。
嵌套序列将会被转换为一个多维数组。
还有一些函数可以新建数组,比如zeros
和ones
分别可以创建指定长度或形状的全0或全1数组。empty
函数会返回一些未初始化的垃圾值。
asarray
函数讲输入转换为ndarray。
ones_like
, zeros_like
, empty_like
以另一个数组为参数,并根据其形状和dtype创建一个全1数组/全0数组/empty数组。
eye
, identity
创建一个正方的N✖️N矩阵。(对角线为1,其余为0)
如果没有特别指定,数据类型基本都是float64(浮点数)。
np.zeros(10)
np.zeros((3,6))
np.empty((2,3,2))
arange
函数是python内置函数range的数组版,会生成相应的ndarray。
arr=np.arange(10)
arr
>array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
若要检查数组中的数据类型,可以用一个超类结合`np.issubdtype'函数来操作。
np.issubdtype(array1,np.integer)
np.issubdtype(array2,np.floating)
np.float64.mro() #查看所有的父类
NumPy数据类型
dtype(数据类型)是一类特殊的对象,它含有ndarray将一块内存解释为特定数据类型所需的信息。它是NumPy如此强大和灵活的原因之一。数值型dtype的命名方式相同:一个类型名+一个用于表示各元素位长的数字(如float64)。
NumPy支持的数据类型比Python内置的类型要多很多,基本上可以和C语言的数据类型对应上。
可以通过ndarray的astype
方法显式地转换其dtype:
float_arr = arr.astype(np.float64)
调用astype会创建出一个新的数组(原始数据的一份拷贝)。
数组属性
NumPy 数组的维数称为秩(rank),一维数组的秩为 1,二维数组的秩为 2,以此类推。
在 NumPy中,每一个线性的数组称为是一个轴(axis),也就是维度(dimensions)。比如说,二维数组相当于是两个一维数组,其中第一个一维数组中每个元素又是一个一维数组。所以一维数组就是 NumPy 中的轴(axis),第一个轴相当于是底层数组,第二个轴是底层数组里的数组。而轴的数量——秩,就是数组的维数。
很多时候可以声明 axis。axis=0
,表示沿着第 0 轴进行操作,即对每一列进行操作;axis=1
,表示沿着第1轴进行操作,即对每一行进行操作。
ndarray.ndim 用于返回数组的维数,等于秩。
a = np.arange(24)
print (a.ndim)
>1
ndarray.shape 表示数组的维度,返回一个元组,这个元组的长度就是维度的数目,即 ndim 属性(秩)。比如,一个二维数组,其维度表示"行数"和"列数"。ndarray.shape 也可以用于调整数组大小。
a = np.array([[1,2,3],[4,5,6]])
print (a.shape)
> (2, 3)
切片和索引
Numpy数组和python list的区别:数组切片是原始数据的视图!
这意味着数据不会被复制,视图上做任何修改都会直接反映到源数组上。
若要复制,则需要显式地进行copy操作:如arr[5:8].copy()
。
对于高维度数组,可以进行递归访问。如 arr[0][2]
or arr[0,2]
。
切片索引
ndarray的切片语法跟Python的列表语法差不多。
注意:使用两个参数,如 [2:7],那么则提取两个索引之间的项,不包括停止索引!
import numpy as np
a = np.arange(10)
b = a[2:7:2] # 从索引 2 开始到索引 7 停止,间隔为 2
print(b)
>[2 4 6]
高维度的对象花样更多,可以在一个或多个轴上进行切片,也可以跟整数索引混合使用。
arr2d [:2,1:] #沿着第一,第二个轴切片
arr2d [:,2] #只有冒号表示选取整个轴
布尔型索引
在NumPy当中,数组的比较运算也是矢量化的,所以数组与字符串的比较会产生一个布尔型数组。
布尔型数组可以直接用于数组索引,但是长度必须跟被索引的长度一致。也可以与其他切片方式混合使用。
可以通过!=
or -
来得到相反的值。
注意:
- 通过布尔型索引选取数组中的数据,将总是创建数据的副本!
- Python的关键字and和or在布尔型数组当中无效。如果需要组合多种运算条件,使用&,|等运算符。
花式索引(Fancy Indexing)
指的是利用整数数组进行索引。
花式索引根据索引数组的值作为目标数组的某个轴的下标来取值。对于使用一维整型数组作为索引,如果目标是一维数组,那么索引的结果就是对应位置的元素;如果目标是二维数组,那么就是对应下标的行。
花式索引跟切片不一样,它总是将数据复制到新数组中。
np.ix_
函数将证书数组转换为一个用于选取方形区域的索引器。
import numpy as np
# 一次传入多个索引数组会有点特别
x = np.array([[1, 2], [3, 4], [5, 6]])
y = x[[0,1,2], [0,1,0]] #以下实例获取数组中(0,0),(1,1)和(2,0)位置处的元素。
print (y)
> [1 4 5]
x=np.arange(32).reshape((8,4))
x
>array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23],
[24, 25, 26, 27],
[28, 29, 30, 31]])
print (x[np.ix_([1,5,7,2],[0,3,1,2])])
>[[ 4 7 5 6]
[20 23 21 22]
[28 31 29 30]
[ 8 11 9 10]]
运算——与标量之间 & 与数组之间(广播)
与标量之间:
数组与标量的算术运算会将那个标量值传播到各个元素。
与数组之间:
大小相等的数组之间的算术运算会将运算应用到元素级。
如果两个数组 a 和 b 形状相同,即满足 a.shape == b.shape,那么 a*b 的结果就是 a 与 b 数组对应位相乘。这要求维数相同,且各维度的长度相同。
不同大小的数组之间的运算叫做广播(Broadcast)。
import numpy as np
a = np.array([[ 0, 0, 0],
[10,10,10],
[20,20,20],
[30,30,30]])
b = np.array([1,2,3])
print(a + b)
>[[ 1 2 3]
[11 12 13]
[21 22 23]
[31 32 33]]
广播的规则:
让所有输入数组都向其中形状最长的数组看齐,形状中不足的部分都通过在前面加 1 补齐。
输出数组的形状是输入数组形状的各个维度上的最大值。
如果输入数组的某个维度和输出数组的对应维度的长度相同或者其长度为 1 时,这个数组能够用来计算,否则出错。
当输入数组的某个维度的长度为 1 时,沿着此维度运算时都用此维度上的第一组值。
简单理解:对两个数组,分别比较他们的每一个维度(若其中一个数组没有当前维度则忽略),满足:
数组拥有相同形状。
当前维度的值相等。
当前维度的值有一个是 1。
若条件不满足,抛出 "ValueError: frames are not aligned" 异常。
广播的原则:如果两个数组的trailing dimension(从末尾开始算起的维度)的轴长度相符或其中一方为1,则认为他们是广播兼容的。
函数
转置.T
属性返回源数据的视图。数组还有transpose
方法, swapaxes
方法。
通用函数是对ndarray中的数据执行元素级运算的函数。
- 算数函数:包含简单的加减乘除: add(),subtract(),multiply() 和 divide()。
- 数学函数:NumPy 包含大量的各种数学运算的函数,包括三角函数,算术运算的函数,复数处理函数等。
- 字符串函数:
这些函数在字符数组类(numpy.char)中定义。详见http://www.runoob.com/numpy/numpy-string-functions.html。 - 统计函数:
numpy.amin()
用于计算数组中的元素沿指定轴的最小值。
numpy.amax()
用于计算数组中的元素沿指定轴的最大值。
numpy.ptp()
函数计算数组中元素最大值与最小值的差(最大值 - 最小值)。
numpy.percentile()
百分位数是统计中使用的度量,表示小于这个值的观察值的百分比。
numpy.median()
函数用于计算数组 a 中元素的中位数(中值)
numpy.mean()
函数返回数组中元素的算术平均值。 如果提供了轴,则沿其计算。
numpy.average()
函数根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值。
标准差std
= sqrt(mean((x - x.mean())2)) 标准差是方差的算术平方根。
var
统计中的方差(样本方差)是每个样本值与全体样本值的平均数之差的平方值的平均数,即 mean((x - x.mean()) 2)。 - 排序/条件筛选函数:
numpy.sort() 函数返回输入数组的排序副本。函数格式如下:
numpy.sort(a, axis, kind, order)
a: 要排序的数组
axis: 沿着它排序数组的轴,如果没有数组会被展开,沿着最后的轴排序, axis=0 按列排序,axis=1 按行排序
kind: 默认为'quicksort'(快速排序)
order: 如果数组包含字段,则是要排序的字段
- 其他:
unique()
: 计算唯一元素并返回有序结果
union1d(x,y)
: 计算并集并返回有序结果
intersect1d(x,y)
: 计算公共元素并返回有序结果 - NumPy 还有一系列与线性代数相关的函数。
数组操作
可以用reshape
函数来修改数组的形状,传入一个表示新形状的元组就能实现该目的。其中,-1表示该维度的大小由数据本身推断而来。
将多维数组转换为一维数组的方法有flatten
(返回数据的副本,不影响原数组)ravel
(返回展开数组)。
默认情况下,NumPy数组是按行优先顺序创建的。
- 数组的链接和拆分:
numpy.condatenate
可以按指定轴将一个由数组组成的序列(如元组,列表等)连接到一起。还可以设置axis。
对于常见的连接操作,NumPy还提供了一些比较方便的方法,比如np.vstack
andnp.hstack
。
与此相反,split
用于将一个数组沿指定轴拆分成多个数组。 - 元素的重复操作
可以用repeat
函数来实现。
如果传入的是一个整数,则可以将各个元素重复一定次数。
若传入的是一组整数,每个元素重复的次数不同。
对于多维数组,还可以让它们沿指定轴重复。需要注意的是,如果没有设置轴向,数组会被扁平化。
arr=np.arange(3)
arr.repeat(3)
> array([0,0,0,1,1,1,2,2,2])
arr.repeat([2,3,4])
> array([0,0,1,1,1,2,2,2,2])
tile
函数的功能是沿指定轴堆叠数组的副本,像铺瓷砖一样。
第二个参数是瓷砖的数量,也可以是一个表示“铺设”布局的元组。
-
take
和put
是花式索引的等价函数,也可以获取和设置数组子集。