cs224n作业_Assignment 1: Exploring Word Vectors Part 1

最近速成cs224n这门课程,看完了课程和笔记尝试写一下课后作业。

我跟着B站上的cs224n2021,感觉讲的很好,就是跟我下载的笔记不太一样,不是很好对照。

本人英语渣,尽量翻译成英文。

首先导入必要的包:

# All Import Statements Defined Here
# Note: Do not add to this list.
# ----------------

import sys
assert sys.version_info[0]==3
assert sys.version_info[1] >= 5

from gensim.models import KeyedVectors
from gensim.test.utils import datapath
import pprint
import matplotlib.pyplot as plt
plt.rcParams['figure.figsize'] = [10, 5]
import nltk
nltk.download('reuters')
from nltk.corpus import reuters
import numpy as np
import random
import scipy as sp
from sklearn.decomposition import TruncatedSVD
from sklearn.decomposition import PCA

START_TOKEN = '<START>'
END_TOKEN = '<END>'

np.random.seed(0)
random.seed(0)
# ----------------

因为在斯坦福课程官网看课程资料导致我一直挂着梯子,所以最开始下载包一直失败,这时候关掉梯子就行了。

略过绘制共现词嵌入,代码如下:

def read_corpus(category="crude"):
    """ Read files from the specified Reuter's category.
        Params:
            category (string): category name
        Return:
            list of lists, with words from each of the processed files
    """
    files = reuters.fileids(category)
    return [[START_TOKEN] + [w.lower() for w in list(reuters.words(f))] + [END_TOKEN] for f in files]

reuters_corpus = read_corpus()
pprint.pprint(reuters_corpus[:3], compact=True, width=100)

首先看第一题,

实现distinct_words:

编写一个方法来计算语料库中出现的不同单词(单词类型)。您可以使用for循环来执行此操作,但使用 Python 列表推导式执行此操作效率更高。特别是,可能对展平列表列表很有用。如果您不熟悉 Python 列表推导式,这里有更多信息

您返回的数据corpus_words应该已排序。您可以使用 python 的sorted函数来实现这一点。

您可能会发现使用Python 集删除重复的单词很有用。

这里就是直接遍历输入的字符串列表,题目提示我们可以用py的列表推导式

def distinct_words(corpus):
    """ 确定语料库的不同单词列表。
        参数:
            corpus(字符串列表列表):文档语料库
        返回:
            corpus_words(字符串列表):语料库中不同单词的排序列表
            num_corpus_words(整数):语料库中不同单词的数量
    """
    corpus_words = []
    num_corpus_words = -1

    # ------------------
    # Write your implementation here.
    #第一个word是遍历到的单词,构成所有单词的列表
    #for sublist in corpus遍历传入列表的子列表
    #for word in sublist遍历子列表的每个word
    all_words = [word for sublist in corpus for word in sublist]

    #使用collections包的Counter函数直接计数,保存每个单词和次数
    word_counts = Counter(all_words)

    #获取键值即单词,并排序
    corpus_words = sorted(word_counts.keys())

    #计数
    num_corpus_words = len(corpus_words)

    # ------------------

    return corpus_words, num_corpus_words

第二题,

实现compute_co_occurrence_matrix:

编写一个方法,为特定的窗口大小构建一个共现矩阵n𝑛(默认值为 4),考虑单词n𝑛之前和n𝑛在窗口中心的单词后面。在这里,我们开始使用来表示向量、矩阵和张量。如果您不熟悉 NumPy,本 cs231n Python NumPy 教程numpy (np)的后半部分有一个 NumPy 教程。

先初始化数组和映射表,遍历文档每个单词,同时计算窗口大小,如果找到相同单词却在不同位置,则给矩阵M相应位置加1.

def compute_co_occurrence_matrix(corpus, window_size=4):
    """
    计算给定语料库和窗口大小(默认为4)下的共现矩阵。

    注意:文档中的每个单词都应位于一个窗口的中心。靠近边缘的单词将有较少的共现单词。

    例如,如果我们取文档"<START> All that glitters is not gold <END>"和窗口大小为4,
    那么"Al l"将与"<START>","that","glitters","is"和"not"共现。

    参数:
        corpus(字符串列表的列表):文档的语料库
        window_size(整数):上下文窗口的大小

    返回:
        M(一个形状为(语料库中唯一单词数量,语料库中唯一单词数量)的对称numpy矩阵):
            单词计数的共现矩阵。
            行和列中单词的顺序应该与distinct_words函数给出的单词顺序相同。
        word2ind(字典):将单词映射到索引(即矩阵M的行/列号)的字典。
    """
    words, num_words = distinct_words(corpus)
    M = None
    word2ind = {}

    # ------------------
    # Write your implementation here.
    #初始化矩阵
    M = np.zeros((num_words, num_words))
    # 创建单词到索引的映射
    word2ind = {word: idx for idx, word in enumerate(words)}

    # 遍历语料库中的每个文档
    for doc in corpus:
        # 对于每个文档,遍历其中的每个单词
        for i, word in enumerate(doc):
            # 获取当前单词的索引
            central_word_idx = word2ind[word]
            # 确定窗口的起始和结束位置
            start = max(i - window_size, 0)
            end = min(i + window_size + 1, len(doc))
            # 更新共现矩阵
            for j in range(start, end):
                if i != j:
                    # 获取共现单词的索引
                    context_word_idx = word2ind[doc[j]]
                    # 增加共现计数
                    M[central_word_idx, context_word_idx] += 1
    # ------------------

    return M, word2ind

第三题,

实现reduce_to_k_dim:

构建一种对矩阵进行降维以生成 k 维嵌入的方法。使用 SVD 取前 k 个分量并生成一个新的 k 维嵌入矩阵。

注意:sklearn numpy、scipy、scikit-learn( )都提供了 SVD 的一些实现,但只有 scipy 和 sklearn 提供了 Truncated SVD 的实现,只有 sklearn 提供了高效的随机化算法来计算大规模 Truncated SVD。因此请使用sklearn.decomposition.TruncatedSVD

这题已经提示使用sklearn库了,因此直接用

def reduce_to_k_dim(M, k=2):
    """
使用Scikit-Learn库中的以下截断SVD函数,将维度为(语料库中唯一单词数量,语料库中唯一单词数量)的共现计数矩阵减少到维度为(语料库中唯一单词数量,k)的矩阵:
    - http://scikit-learn.org/stable/modules/generated/sklearn.decomposition.TruncatedSVD.html

参数:
    M(形状为(语料库中唯一单词数量,语料库中唯一单词数量)的NumPy矩阵):单词计数的共现矩阵
    k(整数):降维后每个单词的嵌入大小

返回:
    M_reduced(形状为(语料库单词数量,k)的NumPy矩阵):k维单词嵌入矩阵。
            就数学课上的SVD而言,实际上返回的是U * S的乘积。
    """
    # Use this parameter in your call to `TruncatedSVD`
    M_reduced = None
    print("Running Truncated SVD over %i words..." % (M.shape[0]))

    # ------------------
    # Write your implementation here.
    # 初始化TruncatedSVD对象,设置目标维度为k
    svd = TruncatedSVD(n_components=k)

    # 拟合并转换数据,得到降维后的矩阵
    M_reduced = svd.fit_transform(M)
    # ------------------

    print("Done.")
    return M_reduced

第四题,

实现plot_embeddings:

在这里,您将编写一个函数来在二维空间中绘制一组二维向量。对于图形,我们将使用 Matplotlib ( plt)。

对于此示例,您可能会发现调整此代码很有用。将来,制作图表的一个好方法是查看Matplotlib 图库,找到一个看起来有点像您想要的图表,然后调整它们提供的代码。

def plot_embeddings(M_reduced, word2ind, words):
    """
    在散点图中绘制列表“words”中指定单词的嵌入表示。
    注意:不要绘制M_reduced / word2ind中列出的所有单词。
    在每个点旁边包含一个标签。

    参数:
        M_reduced(形状为(语料库中唯一单词数量,2)的NumPy矩阵):2维单词嵌入矩阵
        word2ind(字典):将单词映射到矩阵M的索引的字典
        words(字符串列表):我们想要可视化其嵌入的单词列表
    """

    # ------------------
    # 提取需要可视化的单词的嵌入坐标
    coordinates = [M_reduced[word2ind[word]] for word in words]
    # 解包坐标列表为x和y坐标
    x_coords, y_coords = zip(*coordinates)
    # 创建散点图
    plt.figure(figsize=(10, 10))
    plt.scatter(x_coords, y_coords, marker='x', color='red')
    # 在每个点旁边添加标签
    for label, x, y in zip(words, x_coords, y_coords):
        plt.annotate(label, xy=(x, y), xytext=(0, 0), textcoords='offset points')


    plt.show()
    # ------------------

第五题,

共现情节分析:

现在我们将您编写的所有部分放在一起!我们将在路透社“原油”(石油)语料库上计算固定窗口为 4(默认窗口大小)的共现矩阵。然后我们将使用 TruncatedSVD 计算每个单词的二维嵌入。TruncatedSVD 返回 U*S,因此我们需要对返回的向量进行规范化,以便所有向量都出现在单位圆周围(因此接近度是方向接近度)。注意:下面执行规范化的代码行使用了 NumPy 的广播概念。如果您不了解广播,请查看 Jake VanderPlas 的“数组上的计算:广播”

运行下面的单元格以生成图表。运行可能需要几秒钟。在二维嵌入空间中,哪些东西会聚集在一起?哪些东西你认为应该聚集在一起,但却没有聚集在一起? 注意: “bpd”代表“桶/天”,是原油主题文章中常用的缩写。

# -----------------------------
# Run This Cell to Produce Your Plot
# ------------------------------
reuters_corpus = read_corpus()
M_co_occurrence, word2ind_co_occurrence = compute_co_occurrence_matrix(reuters_corpus)
M_reduced_co_occurrence = reduce_to_k_dim(M_co_occurrence, k=2)

# Rescale (normalize) the rows to make them each of unit-length
M_lengths = np.linalg.norm(M_reduced_co_occurrence, axis=1)
M_normalized = M_reduced_co_occurrence / M_lengths[:, np.newaxis] # broadcasting

words = ['barrels', 'bpd', 'ecuador', 'energy', 'industry', 'kuwait', 'oil', 'output', 'petroleum', 'iraq']

plot_embeddings(M_normalized, word2ind_co_occurrence, words)

最后运行,结果如下:

希望每个人学有所成。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值