{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/dbamman/anlp25/blob/main/3.embeddings/WordEmbeddings.ipynb)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!wget --no-check-certificate https://raw.githubusercontent.com/dbamman/anlp25/main/data/wiki.10K.txt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This notebook explores word embeddings through the functionality of Gensim; we train new embeddings from a dataset of our own and compare with pre-trained Glove embeddings. **NOTE**: installing the Gensim library may cause Colab to prompt you to restart the session -- you should go ahead and do that when prompted, then continue executing the remaining cells (starting with the block of imports)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install gensim"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "from gensim.models import Word2Vec, KeyedVectors\n",
    "from gensim.scripts.glove2word2vec import glove2word2vec\n",
    "from gensim.test.utils import datapath"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, let's train a new word2vec model on our data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "sentences=[]\n",
    "filename=\"wiki.10K.txt\"\n",
    "with open(filename) as file:\n",
    "    for line in file:\n",
    "        words = line.rstrip().lower()\n",
    "        # this file is already tokenize, so we can split on whitespace\n",
    "        # but first let's replace any sequence of whitespace (space, tab, newline, etc.) with single space\n",
    "        words = re.sub(r\"\\s+\", \" \", words)\n",
    "        sentences.append(words.split(\" \"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = Word2Vec(\n",
    "    sentences,\n",
    "    vector_size=100,\n",
    "    window=5,\n",
    "    min_count=2,\n",
    "    workers=10\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_trained_vectors = model.wv\n",
    "# save vectors to file if you want to use them later\n",
    "my_trained_vectors.save_word2vec_format('embeddings.txt', binary=False)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_trained_vectors.most_similar(\"actor\", topn=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's load in vectors that have already been trained on a much bigger dataset. [Glove vectors](https://nlp.stanford.edu/projects/glove/) are trained using a different method than word2vec, but results in vectors that can be read in by Gensim.  Here we'll use a 100-dimensional model trained on 6B words (from Wikipedia and news), but bigger models are also available."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!wget --no-check-certificate https://raw.githubusercontent.com/dbamman/anlp25/main/data/glove.6B.100d.100K.txt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "glove = KeyedVectors.load_word2vec_format(\"glove.6B.100d.100K.txt\", binary=False, no_header=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "glove.most_similar(\"actor\", topn=10)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`most_similar` allows for vector arithmetic (as the average value of the input positive/negative vectors, where negative vectors are first multiplied by -1).  Play around with this function to discover other analogies that have been learned in this representation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# one + two = three + ?\n",
    "one=\"man\"\n",
    "two=\"king\"\n",
    "three=\"woman\"\n",
    "\n",
    "one=\"paris\"\n",
    "two=\"france\"\n",
    "three=\"berlin\"\n",
    "\n",
    "glove.most_similar(positive=[two, three], negative=[one], topn=5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also evaluate the quality of the learned vectors through an intrinsic evaluation comparing to human judgments in the wordsim 353 dataset."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "glove.evaluate_word_pairs(datapath('wordsim353.tsv'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "my_trained_vectors.evaluate_word_pairs(datapath('wordsim353.tsv'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
