1. 简介
Python作为一门高级编程语言,不仅可以进行一般的编程任务,还拥有很多扩展库,如 NumPy库,它是Python科学计算的基础包,提供了高效的多维数组对象以及用于数组计算的函数。NumPy是Python数据分析最重要的库之一,它不仅能够处理各种数据类型,而且能够进行各种数学运算。
2. NumPy库简介
NumPy是Numerical Python的缩写,是一个开源的Python库。它的主要运用领域是:线性代数、傅立叶变换、随机数生成等。最重要的是,NumPy是Python进行科学计算必不可少的库。
下面来简单介绍一下NumPy中最重要的一个对象——数组对象ndarray。它主要有以下特点:
2.1 数组对象ndarray
元素类型相同:同一个数组对象中只能存放相同类型的元素,这一点也为它带来了非常高效的存储和计算。
维数:ndarray是多维数组,可具有一维到多维不等的不同维度。
数组对象的形状:ndarray可以使用shape属性来确定数组对象的形状。
广播功能:NumPy可以将不同形状的数组对象进行计算,而不用重复元素,这一点也极大的简化了代码。
NumPy库提供了丰富的API,可以完成数组对象的创建、函数计算、数据排序、IO等一系列操作。这里介绍其中的一个函数——stack()。
3. numpy.stack() 函数
numpy.stack()函数用于将sequence类型的相同形状的数组对象,并排堆叠起来,产生新的数组对象。
stack()函数语法如下所示:
numpy.stack(arrays, axis=0)
arrays :需要堆叠的相同形状的数组序列。
axis :堆叠的方式,该值为0时,则是向下增加一个维度。
4. numpy.stack() 简单示例
import numpy as np
a = np.array([[1, 2],
[3, 4]])
b = np.array([[5, 6],
[7, 8]])
c = np.stack((a, b), axis=0) # 数组堆叠
print(c)
以上代码将两个相同形状的数组对象进行了堆叠。其中,参数axis为0时,表示在行的方向上增加一维,输出结果如下:
[[[1 2]
[3 4]]
[[5 6]
[7 8]]]
我们发现增加了一维,而其他部分没有变化。
5. 案例分析:使用stack实现矢量化语言模型
这里我们使用根据前文所述的stack()函数,实现矢量化的语言模型。
5.1 矢量化语言模型原理
这里我们介绍一种常用的语言模型——N-gram模型。该模型中的N的取值范围一般是1到5,通过遍历训练集然后记录下来统计每一种相邻的两个或几个元素,这样可以获得一个词典和统计结果的数组。
因为我们需要对一段新的文本进行语言模型的计算,也就是对模型进行测试,我们需要将新的文本切分成相邻的N个词组,在这个过程中,根据训练集获得的元素也需要进行相同的切分操作,然后计算出各个元素的累计概率,最终得出语言模型的概率结果。
我们假设:P(word|context) 表示在给定context条件下生成word的概率; while N=2时,context和word之间是相邻的两个词。
比如:对于下面的文本序列:
['today', 'is', 'a', 'good', 'day']
可以把它切分为:
['', 'today'], ['today', 'is'], ['is', 'a'], ['a', 'good'], ['good', 'day'], ['day', ' ']
其中
我们将它们表现为两个数组,一个记录上文context,一个记录下文word,数组元素的顺序与文本的顺序一一对应。
5.2 编写代码实现
首先,定义一个 N-gram 模型的类:
class NgramModel:
def __init__(self, n=2):
self.n = n
def build(self, sent_list):
self.word_list = []
self.context_list = []
self.vocab = set()
for sent in sent_list:
# 创建context和word的切片列表并增加到数组中
words = ['']*(self.n-1) + sent + ['']
for i in range(self.n-1, len(words)):
context = words[i-self.n+1:i]
word = words[i]
self.word_list.append(word)
self.context_list.append(context)
#增加词库
self.vocab.add(word)
self.vocab = sorted(self.vocab)
self.vocab_size = len(self.vocab)
#生成context和word对应的ID
self.word2id = {w:i for (i, w) in enumerate(self.vocab)}
self.id2word = {i:w for (i, w) in enumerate(self.vocab)}
def get_matrix(self, temperature=0.6):
# 矩阵初始化
mat = np.zeros((self.vocab_size, self.vocab_size))
# 对语言模型中的两个统计数组进行for循环
for word, context in zip(self.word_list, self.context_list):
# 获得word和context对应的ID
word_id = self.word2id[word]
context_id = [self.word2id[x] for x in context]
# 填充矩阵
mat[context_id, word_id] += 1
# 使用softmax函数调整概率值
mat = mat / temperature
mat = np.exp(mat)
mat = mat / np.sum(mat, axis=1, keepdims=True)
return mat
在这个代码段中,我们定义了一个 NgramModel 的类并且实现了两个主要的函数—— build() 和 get_matrix()。
其中, NgramModel类是一个类模板,在其初始化 Function 中,我们将 Ngram 模型的维数赋值给成员变量self.n,然后使用 build()函数构建语言模型。在返回词汇表书时,我们可以使用 self.word2id 来查找单词的索引或使用反向字典self.id2word查找单词:
ngram_model = NgramModel(n=2)
sent_list = [['today', 'is', 'a', 'good', 'day']]
ngram_model.build(sent_list)
print("词库大小: ", ngram_model.vocab_size)
print("单词列表: ", ngram_model.vocab)
word_ids = [ngram_model.word2id[w] for w in ngram_model.vocab]
print("单词ID列表: ", word_ids)
id_words = [ngram_model.id2word[i] for i in range(ngram_model.vocab_size)]
print("ID单词列表: ", id_words)
上述代码中,我们对建立好的语言模型查询“词库大小”、“单词列表”、“单词ID列表”以及“ID单词列表”,结果如下:
词库大小: 7
单词列表: ['
', ' ', 'a', 'day', 'good', 'is', 'today'] 单词ID列表: [0, 1, 2, 3, 4, 5, 6]
ID单词列表: ['
', ' ', 'a', 'day', 'good', 'is', 'today']
接下来,get_matrix()函数实现了矩阵的自动化填充,并使用softmax函数对其进行整合:
mat = ngram_model.get_matrix()
print("矩阵形状: ", mat.shape)
print("as 计算矩阵温度:", 0.6)
print("矩阵: ", mat)
上述代码会调用 get_matrix()函数来获得填充好的矩阵。由于我们使用了numpy的stack函数,使得我们可以将多个数组对象进行堆叠,因此我们可以随时增加多个语料库,并将新的语料库堆叠到原有矩阵的底部,以扩充语言模型:
sent_list = [['today', 'is', 'a', 'good', 'day'],
['happy', 'day'],
['all', 'good', 'things', 'come', 'to', 'an', 'end']]
ngram_model.build(sent_list)
mat = np.vstack([mat, ngram_model.get_matrix()]) #堆叠
print(mat.shape)
当我们增加了两个新的语料库之后,矩阵的维度增加为:
(3, 7, 7)
这代表有 3 个语言模型矩阵,每个矩阵都包含 7 行和 7 列。对于每个矩阵,行代表上文context (2-gram),列代表下文word,矩阵中的每个单元代表将context映射到word的相对概率。
6. 结论
NumPy库是 Python 进行科学计算必不可少的库之一,但是它并不完全适用于机器学习中的所有方法。本文介绍了 stack() 函数的简单用法,然后基于它实现了一个矢量化的语言模型,并在处理多个数据集时进行了多维数组堆叠。这些例子有利于初学者学习NumPy库并加深对其用法的理解。