机器学习中的数据被表示为数组。
在Python中,数据几乎被普遍表示为NumPy数组。
如果你是Python的新手,在访问数据时你可能会被一些python专有的方式困惑,例如负向索引和数组切片。
在本教程中,你将了解在NumPy数组中如何正确地操作和访问数据。
完成本教程后,你将知道:
让我们开始吧。
在Python机器学习中如何索引、切片和重塑NumPy数组
照片由BjörnSöderqvist,保留一些权利。
本教程分为4个部分; 他们是:
一般来说,我建议使用Pandas或NumPy函数从文件加载数据。
有关示例,请参阅帖子:
本节假定你已经通过其他方式加载或生成了你的数据,现在使用Python列表表示它们。
我们来看看如何将列表中的数据转换为NumPy数组。
你可以加载或生成你的数据,并将它看作一个列表来访问。
你可以通过调用NumPy的array()函数将一维数据从列表转换为数组。
# 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数组表示,你就可以使用索引来访问它。
我们来看一些通过索引访问数据的例子。
一般来说,索引的工作方式与你使用其他编程语言(如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
一个关键的区别是,你可以从数组末尾使用负向索引来检索偏移值。
例如,索引-1代表数组中的最后一项。索引-2代表倒数第二项,-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结束('to'索引的前一项)切片出数组的第一项。
# simple slicing
from numpy import array
# define array
data = array([11, 22, 33, 44, 55])
print(data[0:1])
运行该示例返回一个包含第一个元素的子数组。
[11]
我们也可以在切片中使用负向索引。例如,我们可以通过在-2(倒数第二项)处开始切片并且不指定'to'索引来切割列表中的最后两项;这就会一直切到维度末端。
# 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中的时间递归神经网络(LSTM),需要输入特定的包含样本、时间步骤和特征的三维数组。
了解如何重塑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)
你可以在形状维度中使用数组维度的大小,例如指定参数。
元组的元素可以像数组一样访问,第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()函数接受一个参数,该参数指定数组的新形状。将一维数组重塑为具有一列的二维数组,在这种情况下,该元组将作为第一维(data.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)
运行该示例,输出一维数组的形状,将该数组重塑为具有5行1列的新形状,并输出。
(5,)
(5, 1)
对于需要一个或多个时间步长和一个或多个特征的多个样本的算法,通常需要将每行代表一个序列的二维数据重塑为三维数组。
一个很好的例子就是Keras深度学习库中的LSTM递归神经网络模型。
重塑函数可以直接使用,指定出新的维度。每一列有多个时间步,每个时间步都有一个观察点(特征),这说的很明白。
我们可以使用数组的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)
运行该示例,先输出二维数组中每一维的大小,再重塑数组,然后得出新的三维数组的形状。
(3, 2)
(3, 2, 1)
在本教程中,你了解了如何使用Python访问和重塑NumPy数组中的数据。
具体来说,你了解到: