赞
踩
目录
对于多数的数据分析应用,理解和使用NumPy数组以及基于数组的计算,将使我们更好的应对数据分析中的问题。我所有的代码都是基于Jupyter Notebook运行的。当然,你也可以使用其他编辑器可能代码的输出部分需要变动。
Numpy(Numerical Python)是目前Python数值计算中最为重要的基础包。大多数计算包都提供了基于Numpy的科学函数功能,将Numpy的数组对象作为数据交换的通用语。
通过下面这个例子,直观的感受一下numpy的高效性:
我们通过两种方式创建相同序列:
- # 导入numpy
- import numpy as np
-
- my_arr = np.arange(10000) # 方式一
-
- my_list = list(range(10000)) # 方式二
我们对每个序列进行平方操作,看一下它操作的时间:
%time for _ in range(10): my_arr2 = my_arr ** 2
CPU times: total: 31.2 ms Wall time: 998 µs
%time for _ in range(10): my_list2 = [x ** 2 for x in my_list]
CPU times: total: 31.2 ms Wall time: 23 ms
N-维数组对象(也就是ndarray)是NumPy的核心特征之一。它是Python中一个快速、灵活的大兴数据集容器。你可以使用类似于标量的操作语法在整块数据上进行数组的数学计算。
对于ndarray这个多维同类数据容器,我们要记住每一个数组都有以下两个属性:
创建数组最简单方式是使用array函数。
- # array函数接收任意的序列型对象,生成一个新的包含传递数据的NumPy数组
- data = [1,2,5,6,7]
- arr = np.array(data1)
- arr
output:array([1, 2, 5, 6, 7])
接下来验证上述提到的shape和dtype两个属性:
- # 查看数组的维度
- arr.shape
output:(5,)
- # 数组中的数据类型
- arr.dtype
output:dtype('int32')
arange函数是Python内建函数range的数组版,返回的是一维数组。与reshape函数配合是最常用的创建数组方式。(在5.1.2中会将怎么配合,很简单,一行代码)
- # 创建从0~9的数组
- np.arange(10)
output:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
numpy.arange(start,stop,step)
参数 | 说明 |
start(可选参数) | 表示生成数组的起始值。如果未提供此参数,默认为 0。 |
stop(必选参数) | 表示生成数组的结束值(不包含在数组中)。该值不会出现在生成的数组中。 |
step(可选参数) | 表示生成数组中元素之间的步长。如果未提供此参数,默认为 1。可以为正值或负值,表示递增或递减的方向。 |
数据类型是一个特殊的对象,也是我们前面提到的dtype返回的类型。
在构建数组是可以通过dtype参数进行定义:
- arr1 = np.array([1,3,5], dtype=np.float64)
- arr2 = np.array([1,3,5], dtype=np.int32)
再通过dtype属性进行查看:
arr1.dtype
output:dtype('float64')
arr2.dtype
output:dtype('int32')
tips:对于结果我们最主要的是分辨出它是属于哪个类(浮点类、整数、布尔值、字符串或某个Python对象)的,其他的可以不做过多的关注。
对于数值我们可以使用astype显示的转换数据类型:
- arr3 = arr2.astype(np.float64,copy=True) # 转换后需要接收返回对象
- arr3.dtype
output:dtype('float64')
tips:把浮点数转换成整数时,小数点后的部分将被消除。
Numpys数组算术
数组之所以重要是因为它允许你进行批量操作而无须任何for循环,这是NumPy的特性---向量化。
不同尺寸的数组间的操作,将会用到广播特性,后面我会讲。
一维数组比较简单,看起来和 Python 的列表很类似。
- # 构建一个一维的数组
- arr = np.arange(10)
- arr
output:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
如果你传入一个数值给数组的切片,例如arr[3:5] = 12,数值被传递给了整个切片。而如果你对Python列表进行操作,纳闷它们之间的区别就在于,数组的切片是原数组的视图,数据并不是被复制了,而是在原数组上的修改。之所以会这样是因为,NumPy是为了处理非常大的数组而设计,如果持续对
首先,我们需要知道二维数组的索引方式:
axis=0 表示行索引。
axis=1 表示列索引。
在二维数组中,每个索引值对应的元素不在是一个值,而是一个一维的数组。
- arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
- arr2d
output:array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
获取单个元素,你可以通过这两种方式,第一个值表示行,第二个值表示列。
- arr2d[0][2] # 方式一
- arr2d[0,2] # 方式二
这里我们讲一下arange函数和reshape函数配合,生成你想要的二维数组,当然也可以生成其他维度的:
arange_reshape = np.arange(32).reshape((8,4))
output: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]])
三维数组的索引方式:
axis=0,axis=1,axis=2
我们首先创建一个2×2×3的数组:
- arr3d = np.array([[[1,2,3],[4,5,6],[7,8,9],[10,11,12]]])
- arr3d
output:array([[[ 1, 2, 3], [ 4, 5, 6], [ 7, 8, 9], [10, 11, 12]]])
这里你最主要的是注意冒号的使用。
对于一维数组:
- arr = np.arange(10)
- print(arr)
-
- print(arr[1:6]) # 切片时,冒号左边是起点索引,右边是终点索引,终点索引上的值不取
output:[0 1 2 3 4 5 6 7 8 9] [1 2 3 4 5]
对于二维数组:
你可以根据自己的需求,切出你想要的维度,下面你自己体会吧。
- # 创建一个二维数组
- arr2d = np.array([[1,2,3],[4,5,6],[7,8,9]])
- arr2d
output:array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
- # 沿着轴0进项切片
- arr2d[:2] # 切出前两行
output:array([[1, 2, 3], [4, 5, 6]])
- # 沿着轴0、轴1进行切片
- arr2d[:2,1:] # 切出前两行,后两列
output:array([[2, 3], [5, 6]])
tip:单独一个冒号表示选择整个轴上的数组。
我们通过下面例子,学习一下:
1.先生成一个人名的数组与数据
- names = np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
- data = np.random.randn(7,4) # 生成随机正态分布的数据
2.根据判别条件选取行
data[names == 'Bob'] # 返回结果为True的索引
output:array([[-1.43440288, 0.62977132, 1.01758918, -1.62918178], [ 1.42773548, 0.04519063, -0.4189345 , -1.36128861]])
tips:布尔值数组的长度必须和数组轴索引的长度一致
3.当然你也可以选取列索引
data[names == 'Bob', 2:] # 返回结果为True的索引
output:array([[ 1.01758918, -1.62918178], [-0.4189345 , -1.36128861]])
4.常用的运算符
通用函数也称为ufunc,是一种在ndarray数据中进行逐元素操作的函数。通用函数就是对简单函数(接收一个或多个标量数值,并产生一个或多个标量结果)的向量化封装。我们可以分为一元通用函数和二元通用函数。
一元通用函数:
函数名 | 描述 |
abs | 逐元素地计算整数、浮点数或复数的绝对值 |
sqrt | 计算每个元素的平方根 |
square | 计算每个元素的平方 |
exp | 计算每个元素的自然指数 |
log | 计算每个元素的自然对数 |
sign | 计算每个元素的符号值:1(正数)、0(0)、-1(负数) |
ceil | 计算每个元素的最高整数(即大于等于给定元素的最小整数) |
floor | 计算每个元素的最小整数(即小于等于给定元素的最大整数) |
rint | 将元素保留到整数位,并保持dtype |
modf | 分别将数组的小数部分和整数部分以数组形式返回 |
isnan | 返回数组中的元素是否是一个NaN(不是一个数值),形式是布尔值数组 |
二元通用函数:
函数名 | 描述 |
add | 将数组的对应元素相加 |
subtract | 在第二个数组中,将第一个数组中包含的元素去除 |
multiply | 将数组的对应元素相乘 |
divide | 除 |
power | 将第二个数组的元素作为第一个数组对应元素的幂次方 |
maximum,fmax | 逐元素计算最大值,fmax忽略NaN |
minimum,fmin | 逐元素计算最小值,fmin忽略NaN |
mod | 按元素的求模计算 |
copysign | 将第一个数组的符号值改为第二个数组的符号值 |
greater, greater_equal | 进行逐个元素的比较,返回布尔值数组 |
还有一些常用的基础数组统计方法:
方法 | 描述 |
sum | 沿着轴向计算所有元素的累和。 |
mean | 数学平均,0长度的数组平均值为NaN |
std, var | 标准差和方差,可以选择自由度调整 |
argmin, argmax | 最小值和最大值 |
cumsum | 从0开始元素累积和 |
sumprod | 从1开始元素累积和 |
由于使用十分简单,所以这里对上述的通用函数不做演示。
和Python的内建列表类型相似,Numpy数组可以使用sort方法按位置排序。该sort函数返回的俄是已排序好的数组拷贝,而不是对原数组按位置排序。
一维:
- arr = np.random.randn(6)
- arr
output:array([-0.18684178, -1.99985154, 0.38174724, 2.24376134, -0.86325609, -0.32549102])
- # 进行排序
- arr.sort()
- arr
output:array([-1.99985154, -0.86325609, -0.32549102, -0.18684178, 0.38174724, 2.24376134])
二维:
- arr = np.random.randn(5,3)
- arr
output:array([[-0.30129876, 0.44718011, 1.63863724], [-0.30518024, 1.62056823, -0.22688705], [-0.89441761, -0.9150414 , 0.11978649], [-0.72888871, -0.06956741, 0.61102637], [ 0.50414316, -1.03651731, -0.7561867 ]])
- # 进行排序
- # 二维以上你需要根据传递的axis值,沿着轴向对每个一维数据段进行排序
- arr.sort(axis=1)
- arr
output:array([[-0.30129876, 0.44718011, 1.63863724], [-0.30518024, -0.22688705, 1.62056823], [-0.9150414 , -0.89441761, 0.11978649], [-0.72888871, -0.06956741, 0.61102637], [-1.03651731, -0.7561867 , 0.50414316]])
NumPy包含一些针对一维ndarray的基础集合操作。
方法 | 描述 |
unique(x) | 计算 x 的唯一值,并排序 |
intersect1d(x,y) | 计算 x 和 y 的交集,并排序 |
union1d(x,y) | 计算 x 和 y 的并集,并排序 |
in1d(x,y) | 计算 x 中的元素是否包含在 y 中,返回一个布尔值数组 |
setdiff1d(x,y) | 差集,在 x 中但不在 y 中的 x 的元素 |
setxor1d(x,y) | 异或集,在 x 或 y 中,但不属于 x、y 交集的元素 |
这里我们演示一下unique函数和in1d函数:
unique函数:
- # 含有重复值的array
- names = np.array(['Bob','Joe','Will','Bob','Will','Joe','Joe'])
- np.unique(names)
output:array(['Bob', 'Joe', 'Will'], dtype='<U4')
in1d函数:
- values = np.array([6, 0, 0, 3, 2, 5, 6])
- np.in1d(values, [2,3,6])
output:array([ True, False, False, True, True, False, True])
广播是指NumPy在算术运算期间处理不同形状的数组的能力。
如果满足以下规则,可以进行广播:
- arr1 = np.array([[0,0,0],[1,1,1],[2,2,2],[3,3,3]])
- arr2 = np.array([1,2,3])
- arr1 + arr2
output:array([[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]])
上述代码的原理示意图:
下图是三维数组上沿0轴向加上一个二维数组的示意图:
我认为学习NumPy最主要的就是学习它的一些数组的思想,为什么要选用NumPy?怎么创建数组?怎么查看数组的数据类型?怎么很好的应用索引及切片?以及广播特性是什么?至于一些函数的调用,能做到即用即查就好。
[2] Numpy详细教程
[3] 书籍:利用Python进行数据分析,Wes McKinney(著),徐敬一(译)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。