100天搞定机器学习(100-Days-Of-ML)(七)Numpy数组基础

第七天

Numpy的学习(一)数组基础

Python中的数据操作几乎等同于Numpy数据操作,甚至Pandas工具也是构建在Numpy数组的基础之上的。

一、从Python列表创建数组

1.首先,可以用np.array从Python列表创建数组:

import numpy as np
np.array([1, 4, 2, 5, 3])

Numpy创建数组要求必须包含同一类型的数据。如果类型不匹配,Numpy将会向上转型(如果可行)。下面的整型被转换为浮点型。

np.array([3.14, 4, 2, 3])

如果明确设置数组的数据类型,可以用dtype关键字:

np.array([1, 2, 3, 4], dtype = 'float32')

另外,Numpy数组可以被指定为多为的。以下是用列表的列表初始化多为数组的一种方法:

np.array([range(i, i + 3) for i in [2, 4, 6]])

2.从头创建数组

面对大型数组的时候,用Numpy内置的方法从头创建数组是一种更高效的方法。以下是几个具体的例子:

创建一个长度为10的数组,数组的值都是0:

np.zeros(10, dtype=int)

创建一个3x5的浮点型数组,数组的值都是1:

np.ones((3, 5), dtype=float)

创建一个3x5的浮点型数组,数组的值都是3.14

np.full((3, 5), 3.14)

创建一个数组,从0开始到20结束,步长是2:

np.arange(0, 20, 2)

创建一个5个元素的数组,这5个数均匀地分配到0-1:

np.linespace(0, 1, 5)

创建一个3x3的,在0~1均匀分布的随机数组成的数组:

np.random.random((3, 3))

创建一个3x3的,均值为0、方差为1的数组:

np.random.normal(0, 1, (3, 3))

创建一个3x3的,[0, 10)区间的随机整型数组:

np.random.randint(0, 10, (3, 3))

创建一个3x3的单位矩阵:

np.eyes(3)

二、数组的属性

首先我们将用Numpy的随机数生成器设置一组种子值,以确保每次程序执行的时候都可以生成同样的随机数组。下面我们定义三个随机的数组:一个一维的、一个二维的和一个三维数组。

np.random.seed(0) # 设置随机数种子
x1 = np.random.randint(10, size=6) 
x2 = np.random.randint(10, size=(3, 4))
x3 = np.random.randint(10, size=(3, 4, 5))

每个数组都有ndim(数组的维度)、shape(数组每个维度的大小)和size(数组的大小)等属性。

print("x3 ndim: ", x3.ndim) # 3
print("x3 ndim: ", x3.shape) # (3, 4, 5)
print("x3 ndim: ", x3.size) # 60
----------------------------------
另外一个有用的属性是dtype,它是数组的数据类型。
print("x3 dtype: ", x3.dtype) # int32

三、数组的索引

和Python列表一样,在一维数组中,你也可以通过中括号指定索引获取第i个值(从0开始计数)。

x1
array([8, 1, 1, 7, 3, 9])
x1[0] # 8
x1[4] # 3

为了获取数组的末尾的索引,可以用负值索引:

x1[-1] # 9
x1[-2] # 3

在多维数组中,可以用逗号分隔的索引元组获取元素:

x2
array([[3, 6, 7],
       [2, 0, 3]
       [5, 9, 4]])
------------------
x2[0, 0] # 3
x2[2, 0] # 5

当然也可以用上述索引方式修改元素值,x2[0, 0] = 5

值得注意的是和Python列表不同,Numpy数组是固定类型的。这意味着当你试图将一个浮点型值插入一个整型数组时,浮点值会被截短成整型。并且这种截短是自动完成的,不会给你提示或者警告,所以需要特别注意这一点。

四、数组的切分

前面用中括号获取单个数组元素,我们也可以用切片(slice)符号来获取子数组,切片符号用冒号(:)表示。Numpy切片语法和Python列表的标准切片语法相同。为了获取数组x的一个切片,可以用以下的方式:

x[start:stop:step]

如果以上三个参数都未指定,那么它们会被分别设置为默认值start=0、stop=维度的大小和step=1。

1.一维数组

x = np.narray(10)
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
x[:5] # 前五个元素 [0, 1, 2, 3, 4]
x[5:] # 索引五之后的元素 [5, 6, 7, 8, 9]
x[4:7] # 中间索引4到7的数组,但不包括7 [4, 5, 6]
x[::2] # 每隔一个元素
x[1::2] # 每隔一个元素,从索引1开始
-------------------------------
当步长为负的时候,start和stop的参数默认是被交换的。
x[::-1] # 所有的元素, 逆序 [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

2.多维数组

多维切片也用同样的方式处理,用冒号分割。

x2
array([[3, 6, 7],
       [2, 0, 3]
       [5, 9, 4]])
-------------------
x2[:2, :3] # [[3, 6, 7], [2, 0, 3]]

3.获取数组的行和列

一种常见的需求是获取数组的单行和单列。可以将索引与切片组合起来实现这个功能,用一个冒号(:)表示空切片。

print(x2[:, 0]) # [12 7 1] 获取x2的第一列
print(x2[0, :]) # [3 6 7] 获取x2的第一行
当然获取行的时候,处于语法的简介考虑,可以省略空的切片
print(x2[0]) # 等于x2[0, :]

4.非副本视图的子数组

有关数组切片有一点很重要也非常有用,那就是数组切片返回的是数组数据的视图,而不是数组数据的副本。也就是说当你改变数组的切片子数组的时候,原始数组的值也会被改变。这种默认的处理方式实际上非常有用:它意味着处理非常大的数据集时,可以获取或处理这些数据集的片段,而不是复制底层的数据缓存。

尽管数组视图有一些非常好的特性,但是在有些时候明确地复制数组里的数据或子数组也是非常有用的。可以简单通过copy()方法实现:

x2_sub_copy = x2[:2, :2].copy()
如果修改这个子数组的时候,原始数组不会被改变。

五、数组的变形

另一个有用的操作类型是数组的变形。数组变形最灵活的实现方式是通过reshape()函数来实现。列入,如果你希望将数字1~9放入一个3X3的矩阵中,可以采用如下方法:

grid = np.arange(1, 10).reshape((3, 3))
print(grid)

值得注意,如果希望该方法可行,那么原始数组的大小必须和变形后数组的大小一致。如果满足这个条件,reshape方法将会用到原始数组的一个非副本视图。但实际情况是,在非连续的数据缓存的情况下,返回非副本视图往往不可能实现。

六、数组的拼接和分裂

以上所有的操作都是针对单一数组的,但有时也需要将多个数组合并为一个数组,或将一个数组分裂成多个。

1.数组的拼接

拼接或连接Numpy中的两个数组主要由np.concatenate、np.vstack、np.hstack实现。

np.concatenate将数组元数组或数组列表作为第一个参数,如下:

x = np.array([1, 2, 3])
y = np.array([4, 5, 6])
np.concatenate([x, y])
# array([1, 2, 3, 4, 5, 6])
当然也可以一次拼接两个以上数组。
而且也可以用于二维数组的拼接。
grid = np.array([[1, 2, 3],
                 [4, 5, 6]])
沿着第一个轴拼接
np.concatenate([grid, grid])
# array([[1, 2, 3],
         [4, 5, 6],
         [1, 2, 3],
         [4, 5, 6]])
沿着第二个轴拼接
np.concatenate([grid, grid], axis=1)
# array([[1, 2, 3, 1, 2, 3],
         [4, 5, 6, 4, 5, 6]])

沿着固定维度处理数组时,使用np.vstack(垂直栈)和np.hstack(水平栈)函数会更简洁:

x = np.array([1, 2, 3])
grid = np.array([[9, 8, 7],
                 [6, 5, 4]])
# 垂直栈数组
np.vstack([x, grid])
# array([[1, 2, 3],
         [9, 8, 7],
         [6, 5, 4]]])
# 水平栈数组
y = np.array([[99],
              [11]])
np.hstack([grid, y])
# array([[9, 8, 7, 99],
         [6, 5, 4, 11]])

2.数组的分裂

与拼接相反的过程是分裂。分裂可以通过np.split、np.hsplit和np.vstack函数来实现。

可以向以上函数传递一个索引列表作为参数,索引列表记录的是分裂点的位置。

x = [1, 2, 3, 99, 99, 3, 2, 1]
x1, x2, x3 = np.split(x, [3, 5])
print(x1, x2, x3)
# [1 2 3] [99 99] [3 2 1]

值得注意的是,N分裂点会得到N+1个子数组。相关的np.hsplit和np.vstack也是类似。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值