数据分析之Numpy

目录

0. 引言

1. 什么是Numpy?

2. Numpy的优势

3. 数组的创建

4. ndarray的数据类型

5. 索引与切片

6. 数组通用函数

7. 排序

8. 唯一值与其他集合逻辑

9. 广播

结束语

参考


0. 引言

        对于多数的数据分析应用,理解和使用NumPy数组以及基于数组的计算,将使我们更好的应对数据分析中的问题。我所有的代码都是基于Jupyter Notebook运行的。当然,你也可以使用其他编辑器可能代码的输出部分需要变动。

1. 什么是Numpy?

        Numpy(Numerical Python)是目前Python数值计算中最为重要的基础包。大多数计算包都提供了基于Numpy的科学函数功能,将Numpy的数组对象作为数据交换的通用语。

2. Numpy的优势

  • 对于含有大量数组的数据操作非常有效;
  • Numpy在内部将数据存储在连续的内存块上,这与其他Python内建函数结构是不同的;
  • Numpy可以针对全量数组进行复杂计算而不需要写Python循环。

通过下面这个例子,直观的感受一下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

3. 数组的创建

        N-维数组对象(也就是ndarray)是NumPy的核心特征之一。它是Python中一个快速、灵活的大兴数据集容器。你可以使用类似于标量的操作语法在整块数据上进行数组的数学计算。

对于ndarray这个多维同类数据容器,我们要记住每一个数组都有以下两个属性:

  • shape 属性:用于表征数组每一维度的数量;
  • dtype 属性:用来描述数组的数据类型。

3.1 array函数创建数组

创建数组最简单方式是使用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')

3.2 arange函数创建数组

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。可以为正值或负值,表示递增或递减的方向。

3.3 其他方式创建数组

  • zeros函数:可以一次性创造全 0 数组。
  • ones函数:可以一次性创造全 1 数组。
  • empty函数:可以创建一个没有初始化数值的数组。
  • eye函数:创建一个对角线为 1,其余为 0 的N*N的矩阵。

4. ndarray的数据类型

数据类型是一个特殊的对象,也是我们前面提到的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的特性---向量化

        不同尺寸的数组间的操作,将会用到广播特性,后面我会讲。

5. 索引与切片

5.1 常用的数组维度

5.1.1 一维数组

一维数组比较简单,看起来和 Python 的列表很类似。

# 构建一个一维的数组
arr = np.arange(10)
arr
output:array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

        如果你传入一个数值给数组的切片,例如arr[3:5] = 12,数值被传递给了整个切片。而如果你对Python列表进行操作,纳闷它们之间的区别就在于,数组的切片是原数组的视图,数据并不是被复制了,而是在原数组上的修改。之所以会这样是因为,NumPy是为了处理非常大的数组而设计,如果持续对

5.1.2 二维数组

首先,我们需要知道二维数组的索引方式:

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]])

5.1.3 三维数组

三维数组的索引方式:

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]]])

5.2 数组的切片索引

这里你最主要的是注意冒号的使用。

对于一维数组

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:单独一个冒号表示选择整个轴上的数组。

5.3 布尔索引

我们通过下面例子,学习一下:

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.常用的运算符

  • == :判断左右两边相等,返回True
  • !=:判断左右两边不相等,返回True
  • ~:表示取反操作
  • &(and):并运算
  • |(or):或运算

6. 数组通用函数

        通用函数也称为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开始元素累积和

由于使用十分简单,所以这里对上述的通用函数不做演示。

7. 排序

        和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]])

8. 唯一值与其他集合逻辑

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])

9. 广播

广播是指NumPy在算术运算期间处理不同形状的数组的能力。

如果满足以下规则,可以进行广播:

  • ndim较小的数组会在前面追加一个长度为1的维度。
  • 输出数组的每个为度的大小是输入数组该维度大小的最大值。
  • 如果输入在每个维度中的大小于输出大小匹配,或其值正好为 1,则在计算中广播。
  • 如果输入的某个维度大小为1,则该维度中的第一个数据元素将用于该维度所有的计算。
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?怎么创建数组?怎么查看数组的数据类型?怎么很好的应用索引及切片?以及广播特性是什么?至于一些函数的调用,能做到即用即查就好。

参考

[1]【python学习】最全Numpy教程

[2] Numpy详细教程

[3] 书籍:利用Python进行数据分析,Wes McKinney(著),徐敬一(译)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值