在机器学习中,数据被表示为数组。
具体在 Python 中,数据几乎被都被表示为 NumPy 数组。
如果你刚从小伙伴那里了解到 Python,可能会对一些访问数据的方式困惑,例如负数索引和数组切片等等一些pythonic的操作。
在本教程中,你将了解如何正确地操作和访问NumPy数组中的数据。
完成本教程后,你获得以下这些技能:
现在就让我们开始吧。
本教程分为 4 个部分:
一般来说,我建议使用 Pandas 甚至使用 NumPy 的函数从文件加载数据。
有关示例,请参阅笔者以前的文章:
本节假定你已经通过不同于上述两种的其他方式加载或生成了你的数据,现在正使用 Python 列表来存储这些数据。
我们来看看如何将这些列表中的数据转换为 NumPy 数组。
你可以通过一个列表来加载或者生成,存储并操作你的数据。
本节中,你可以通过调用 array( )这个 NumPy 函数将一维数据列表转换为数组。如下所示:
# one dimensional example
from numpy import array
# list of data
data = [11, 22, 33, 44, 55]
# array of data
data = array(data)
print(data)
print(type(data))
运行该示例将一维列表转换为 NumPy 数组。
[11 22 33 44 55]
<class 'numpy.ndarray'>
在机器学习中,更有可能产生或需要二维数据。
假设有一个数据表,其中每一行代表一个观察点,每一列代表一个不同属性。
也许你生成了这些数据,或者使用自己的代码加载了这个数据表,现在你有一个二维列表(列表中的每一项是一个列表)。每个列表代表一个新的观察点。
还是可以通过调用 array( )函数将二维列表转换为NumPy数组。
# two dimensional example
from numpy import array
# list of data
data = [[11, 22],
[33, 44],
[55, 66]]
# array of data
data = array(data)
print(data)
print(type(data))
运行示例显示成功转换的数据。
[[11 22]
[33 44]
[55 66]]
<class 'numpy.ndarray'>
一旦你的数据使用 NumPy 数组进行表示,就可以使用索引访问其中的数据。
我们来看一些通过索引访问数据的例子。
一般来说,NumPy 中索引的工作方式与使用其他编程语言(如 Java,C# 和 C ++)时的经验类似。
例如,可以使用括号运算符[]指定要检索的数据序号(从零开始的偏移量)来访问元素。
# simple indexing
from numpy import array
# define array
data = array([11, 22, 33, 44, 55])
# index data
print(data[0])
print(data[4])
运行示例打印数组中的第一个和最后一个值。
11
55
指定过大的,超出数组边界的整数将导致数组越界错误。
# simple indexing
from numpy import array
# define array
data = array([11, 22, 33, 44, 55])
# index data
print(data[5])
运行该示例将输出以下错误:
IndexError: index 5 is out of bounds for axis 0 with size 5
但 Python 的索引同其他编程语言有一个关键的区别是,你可以使用负索引来从数组尾部检索值。
例如,索引 -1 代表数组中的最后一项。索引 -2 代表数组中的倒数第二项,示例中的 -5 索引代表数组中的第一个值(因为数组中只有 5 个数)。
# simple indexing
from numpy import array
# define array
data = array([11, 22, 33, 44, 55])
# index data
print(data[-1])
print(data[-5])
运行该示例将打印数组中的最后一项和第一项。
55
11
二维数组的索引与一维数组类似,区别在于用逗号分隔各个维度的索引。
data[0,0]
这与基于C语言的编程语言不同,其每个维度使用单独的中括号运算符。
data[0][0]
例如,我们通过以下程序可以访问数组的第一行中的第一列,如下所示:
# 2d indexing
from numpy import array
# define array
data = array([[11, 22], [33, 44], [55, 66]])
# index data
print(data[0,0])
运行该示例将打印数据集中的第一个数字。
11
如果我们对第一行中的所有项感兴趣,可以将第二维索引留空,例如:
# 2d indexing
from numpy import array
# define array
data = array([[11, 22], [33, 44], [55, 66]])
# index data
print(data[0,])
这将打印第一行的数据。
[11 22]
文章到现在为止似乎还挺容易; 创建数组和建立索引感觉很熟悉。
现在我们来到数组切片的部分,这部分往往是初学者面对 Python 和 NumPy 时经常产生疑问的地方。
列表和 NumPy 数组等数据结构可以进行切片操作。意味着这些数据结构的子序列可以通过切片被索引和获取。
在指定输入,输出变量,或从测试集所在行中提取训练数据行,这些机器学习经常用到的操作时,切片无疑是非常好用的。
切片使用冒号运算符':' 冒号之前之后的索引值分别代表“ from ”和“ to ”。切片从“from”索引开始,并在“to”索引之前结束。(切片操作的范围包含起始项,但不包含结束项)
data[from:to]
让我们通过一些例子来说明切片的用法。
可以通过将索引留空,使用“:”来访问数组该维度中的所有数据。
# simple slicing
from numpy import array
# define array
data = array([11, 22, 33, 44, 55])
print(data[:])
运行该示例将打印数组中的所有元素。
[11 22 33 44 55]
数组的第一项可以通过指定从索引 0 开始到索引 1 结束的切片(即在‘ 1 ’之前结束)来获取。
# simple slicing
from numpy import array
# define array
data = array([11, 22, 33, 44, 55])
print(data[0:1])
运行该示例返回一个包含第一个元素的子数组。
[11]
我们也可以在切片中使用负数索引。例如,我们可以通过切片获得列表中的最后两项,将切片的起始位设为 -2 ,将结束位留空。这样,切片就从列表的倒数第二项开始,到列表最后结束。
# simple slicing
from numpy import array
# define array
data = array([11, 22, 33, 44, 55])
print(data[-2:])
运行该示例返回仅包括最后两项的子数组。
[44 55]
我们来看看你最有可能在机器学习中使用的两个二维切片的例子。
将加载的数据分解为输入变量(X)和输出变量(y)在机器学习中是很常见的操作。
我们可以通过切片得到不包括最后一列的所有数据行,然后单独索引最后一列来实现输入输出变量的分离。
具体来说,对于输入数据,我们可以通过在行索引中使用':',列索引中指定 ‘:-1’来选取不包括最后一列的所有数据行。
X = [:, :-1]
对于代表输出的最后一列,我们可以在行索引中使用':'再次选择所有行,并通过在列索引中指定‘-1’索引来选取所有数据行的最后一列。
y = [:, -1]
将两项操作整合,我们可以把列数为 3 的二维数据集分离成输入和输出数据,如下:
# split input and output
from numpy import array
# define array
data = array([[11, 22, 33],
[44, 55, 66],
[77, 88, 99]])
# separate data
X, y = data[:, :-1], data[:, -1]
print(X)
print(y)
运行该示例打印分离的X和Y元素。请注意,X是二维数组,y是一维数组。
[[11 22]
[44 55]
[77 88]]
[33 66 99]
将加载的数据集分成单独的训练集和测试集也是很常见的操作。
这是一个行切片操作,数据中一部分用于训练模型,其余部分将用于估计训练模型的效果。
操作涉及通过在列索引中指定“:”来获取所有列。训练数据集包括从开始一直到分隔行的所有数据行(不包含分隔行)。
dataset
train = data[:split, :]
测试数据集将是从分隔行开始到结束的所有行。
test = data[split:, :]
通过上述两项操作,我们可以在设置的分隔行,将数据集分为两部分。
# split train and test
from numpy import array
# define array
data = array([[11, 22, 33],
[44, 55, 66],
[77, 88, 99]])
# separate data
split = 2
train,test = data[:split,:],data[split:,:]
print(train)
print(test)
运行示例将前两行选为训练集,最后一行作为测试集。
[[11 22 33]
[44 55 66]]
[[77 88 99]]
对数据切片之后,你可能还需要对现有的数据进行维度变形。
例如,一些库(如 scikit-learn)可能需要将输出变量(y)的一维数组变形为二维数组,在每列的基础上增加该列的结果。
一些算法,如 Keras 中的长短期记忆递归神经网络,将输入数据指定为由采样值,时间步长和特征组成的三维数组。
明白如何变形 NumPy 数组,以便数据满足特定 Python 库的输入需求,是非常重要的。我们来看看以下两个例子。
NumPy 数组有一个 shape 属性,它返回一个包含数组每个维度中数据数量的元组。
例如:
# array shape
from numpy import array
# define array
data = array([11, 22, 33, 44, 55])
print(data.shape)
运行该示例将打印一个一维元组。
(5,)
二维数组的返回值将是一个二维元组。
# array shape
from numpy import array
# list of data
data = [[11, 22],
[33, 44],
[55, 66]]
# array of data
data = array(data)
print(data.shape)
运行该示例将返回一个包括数组行数和列数的元组。
(3, 2)
可以通过访问这个元组得到数组维度的大小,例如访问元组的第 n 个索引。
元组的元素可以像数组一样被访问,上述元组中,第 0 个索引对应数组的行数,第 1 个索引对应列数。例如
# array shape
from numpy import array
# list of data
data = [[11, 22],
[33, 44],
[55, 66]]
# array of data
data = array(data)
print('Rows: %d' % data.shape[0])
print('Cols: %d' % data.shape[1])
运行示例将得到每个维度的数据个数。
Rows: 3
Cols: 2
将一维数组调整为多行一列的二维数组是很常见的操作。
NumPy 为 NumPy 数组对象提供 reshape()函数,可用于调整维数。
reshape()函数接受一个指定数组新形状的参数。在将一维数组重新整形为具有多行一列的二维数组的情况下,作为参数的元组,从 shape[0] 属性中获取行数,并将列数设定为1。
data = data.reshape((data.shape[0], 1))
同其他代码整合后,我们得到以下的例子。
# reshape 1D array
from numpy import array
from numpy import reshape
# define array
data = array([11, 22, 33, 44, 55])
print(data.shape)
# reshape
data = data.reshape((data.shape[0], 1))
print(data.shape)
运行该示例将打印一维数组的形状,将数组重新整形为具有1列5行的数组,然后打印出新的维数。
(5,)
(5, 1)
对于需要一个或多个时间步长以及特征的多样本的算法,通常需要将每行代表序列的二维数组调整为三维数组。
一个很好的例子就是 Keras 深度学习库中的 LSTM 递归神经网络模型。
reshape( ) 函数可以直接使用,指定新的维度。以下是一个清楚的例子,其中每个序列拥有多个步长,每个步长对应其相应的观察结果。
我们可以使用数组的 shape 属性中的维数大小来指定样本(行)和列(时间步长)的数量,并将观察结果的数量固定为1。
data.reshape((data.shape[0], data.shape[1], 1))
同其他代码整合后,我们得到以下的例子。
# reshape 2D array
from numpy import array
# list of data
data = [[11, 22],
[33, 44],
[55, 66]]
# array of data
data = array(data)
print(data.shape)
# reshape
data = data.reshape((data.shape[0], data.shape[1], 1))
print(data.shape)
首先运行示例,打印 2 维数组中每个维度的大小,重新调整数组,然后打印新的 3 维数组的形状。
(3, 2)
(3, 2, 1)
这部分提供有关本文主题的更多内容,如果有兴趣的话可以参阅.
在本教程中,你了解了如何使用 Python 访问 NumPy 数组中的数据,以及如何调整数组的维数。
具体来说,你了解到: