{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# NLP-LAB Exercise 01 by jonas weinz\n", "----" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "%matplotlib inline \n", "#inline for publishing on github. For jupyter lab set ipympl here\n", "\n", "import nltk\n", "import pprint\n", "#from sklearn.tree import DecisionTreeClassifier\n", "from sklearn.neural_network import MLPClassifier\n", "from sklearn.feature_extraction import DictVectorizer\n", "from sklearn.pipeline import Pipeline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* download data" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[nltk_data] Downloading package treebank to /home/jonas/nltk_data...\n", "[nltk_data] Package treebank is already up-to-date!\n", "[nltk_data] Downloading package brown to /home/jonas/nltk_data...\n", "[nltk_data] Package brown is already up-to-date!\n", "[nltk_data] Downloading package punkt to /home/jonas/nltk_data...\n", "[nltk_data] Package punkt is already up-to-date!\n", "[nltk_data] Downloading package averaged_perceptron_tagger to\n", "[nltk_data] /home/jonas/nltk_data...\n", "[nltk_data] Package averaged_perceptron_tagger is already up-to-\n", "[nltk_data] date!\n", "[nltk_data] Downloading package tagsets to /home/jonas/nltk_data...\n", "[nltk_data] Package tagsets is already up-to-date!\n" ] }, { "data": { "text/plain": [ "True" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nltk.download('treebank')\n", "nltk.download('brown')\n", "nltk.download('punkt')\n", "nltk.download('averaged_perceptron_tagger')\n", "nltk.download('tagsets')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## implementing own classifiers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* writing an own feature funtion" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def features(sentence, index):\n", " word = sentence[index]\n", " is_punctuation_mark = word == \"!\" or word == \".\" or word == \",\" or word == \"?\"\n", " sentence_length = len(sentence)\n", " relative_third = (index * 3) // sentence_length \n", " vowels = word.count('a') + word.count('e') + word.count('i') + word.count('o') + word.count('u')\n", " return {\n", " 'word': word,\n", " 'is_capitalized': sentence[index][0].upper() == sentence[index][0],\n", " 'prefix-1': sentence[index][0],\n", " 'suffix-1': sentence[index][-1],\n", " 'prefix-2': sentence[index][1] if len(word) > 1 else '',\n", " 'suffix-2': sentence[index][-2] if len(word) > 1 else '',\n", " 'prev_word': '' if index == 0 else sentence[index - 1],\n", " 'next_word': '' if index == len(sentence) - 1 else sentence[index + 1],\n", " 'length': len(word),\n", " 'index' : index,\n", " 'rev_index': len(sentence) - index,\n", " 'sentence_length_': len(sentence),\n", " 'relative_third': relative_third,\n", " 'numerical': word.isnumeric(),\n", " 'is_punctuation_mark': is_punctuation_mark,\n", " ',': word == \",\",\n", " '.': word == \".\",\n", " '!': word == \"!\",\n", " '?': word == \"?\",\n", " 'vowels' : vowels\n", " }" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "#test_sentence = ['The','cake','is','a','lie','!']\n", "#for i in range(len(test_sentence)):\n", "# pprint.pprint(features(test_sentence, i))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* function for creating training sets" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def untag(tagged_sentence):\n", " return [w for w,t in tagged_sentence]\n", "\n", "def transform_to_dataset(tagged_sentences):\n", " X,y = [], []\n", " \n", " for s in tagged_sentences:\n", " for i in range(len(s)):\n", " X.append(features(untag(s),i))\n", " y.append(s[i][1])\n", " return X,y\n", "\n", "def create_training_and_test_set(annotated_sentences, relative_cutoff):\n", " cutoff = int(relative_cutoff * len(annotated_sentences))\n", " training_sentences = annotated_sentences[:cutoff]\n", " test_sentences = annotated_sentences[cutoff:]\n", " \n", " X,y = transform_to_dataset(training_sentences)\n", " tX, ty = transform_to_dataset(test_sentences)\n", " \n", " return X,y,tX,ty" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Train classifier" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def train_classifier(X,y,classifier,max_size=10000):\n", " clf = Pipeline([\n", " ('vectorizer', DictVectorizer(sparse=False)),\n", " ('classifier', classifier)\n", " ])\n", " \n", " print(\"start training…\")\n", " \n", " clf.fit(\n", " X if len(X) < max_size else X[:max_size],\n", " y if len(y) < max_size else y[:max_size]\n", " )\n", " \n", " print(\"training done\")\n", " \n", " return clf" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* classifier evaluater" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "def test_classifier(clf, tX, ty):\n", " accuracy = clf.score(tX, ty)\n", " print(\"Accuracy: \", accuracy)\n", " # TODO: more analytics\n", " return accuracy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Task 01:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Performance 1\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Model 01\n", "* train and testing english custom POS tagger model:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "def model_01(X,y,tX,ty, max_size=10000):\n", " #classifier = DecisionTreeClassifier(criterion='entropy')\n", " model01_clf = train_classifier(X,y,MLPClassifier(hidden_layer_sizes=(100,), learning_rate='adaptive'),max_size=max_size)\n", " return test_classifier(clf=model01_clf, tX=tX, ty=ty)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Model 02" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def model_02(tX,ty):\n", " m2_y = nltk.pos_tag([w['word'] for w in tX])\n", " # compare results\n", " n_correct = sum((1 if m2_y[i][1] == ty[i] else 0) for i in range(len(ty)))\n", " return n_correct / len(ty)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Model 03" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "def model_03(corpus_tagged, corpus_sents, cut=0.8):\n", " \n", " patterns = [(r'.*ing$', 'VBG'), (r'.*ed$', 'VBD'), (r'.*es$', 'VBZ'), (r'.*ould$', 'MD'), (r'.*\\'s$', 'NN$'), \n", " (r'.*s$', 'NNS'), (r'^-?[0-9]+(.[0-9]+)?$', 'CD'), (r'.*', 'NN')]\n", " \n", " s = int(len(corpus_tagged) * cut)\n", " train_sents = corpus_tagged[:s]\n", " test_sents = corpus_tagged[s:]\n", " \n", " models = {\n", " 'def_model': nltk.DefaultTagger('NN'),\n", " 'regexp_model': nltk.RegexpTagger(patterns),\n", " 'uni_model': nltk.UnigramTagger(train_sents),\n", " 'bi_model': nltk.BigramTagger(train_sents),\n", " 'tri_model': nltk.TrigramTagger(train_sents)\n", " }\n", " \n", " performance = {}\n", " for name,model in models.items():\n", " performance[name] = model.evaluate(test_sents)\n", " \n", " return performance\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Applying models on Datasets" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "P1.1\n", "start training…\n", "training done\n", "Accuracy: 0.9156644543140875\n", "P1.2\n", "P1.3\n", "P1.4\n", "start training…\n", "training done\n", "Accuracy: 0.8418517269617997\n", "P1.5\n", "P1.6\n", "\n", "All Performances:\n", "{'P1.1': 0.9156644543140875,\n", " 'P1.2': 0.8936074654423873,\n", " 'P1.3 -- bi_model': 0.1132791057437996,\n", " 'P1.3 -- def_model': 0.1447677029791906,\n", " 'P1.3 -- regexp_model': 0.24232746145017217,\n", " 'P1.3 -- tri_model': 0.06736863116922003,\n", " 'P1.3 -- uni_model': 0.8608213982733669,\n", " 'P1.4': 0.8418517269617997,\n", " 'P1.5': 0.615540247603449,\n", " 'P1.6 -- bi_model': 0.09186376993111421,\n", " 'P1.6 -- def_model': 0.1209595837949805,\n", " 'P1.6 -- regexp_model': 0.19683029047641987,\n", " 'P1.6 -- tri_model': 0.05867334650031312,\n", " 'P1.6 -- uni_model': 0.8026879907509996}\n" ] } ], "source": [ "# dictionary containing all performances\n", "performances = {}\n", "\n", "treebank_tagged = nltk.corpus.treebank.tagged_sents()\n", "treebank_sents = nltk.corpus.treebank.sents()\n", "\n", "brown_tagged = nltk.corpus.brown.tagged_sents(categories='news')\n", "brown_sents = nltk.corpus.brown.sents(categories='news')\n", "\n", "#display(treebank_tagged[0])\n", "\n", "X1,y1,tX1,ty1 = create_training_and_test_set(annotated_sentences=treebank_tagged, \n", " relative_cutoff=0.8)\n", "\n", "X2,y2,tX2,ty2 = create_training_and_test_set(annotated_sentences=brown_tagged, \n", " relative_cutoff=0.8)\n", "\n", "\n", "# running performances 1.1 - 1.6\n", "\n", "print(\"P1.1\")\n", "performances['P1.1'] = model_01(X1,y1,tX1,ty1)\n", "\n", "print(\"P1.2\")\n", "performances['P1.2'] = model_02(tX1,ty1)\n", "\n", "print(\"P1.3\")\n", "p3 = model_03(treebank_tagged, treebank_sents)\n", "for k,v in p3.items():\n", " performances[\"P1.3 -- \" + k] = v\n", "\n", "print(\"P1.4\")\n", "performances['P1.4'] = model_01(X2,y2,tX2,ty2)\n", "\n", "print(\"P1.5\")\n", "performances['P1.5'] = model_02(tX2,ty2)\n", "\n", "print(\"P1.6\")\n", "p6 = model_03(brown_tagged, brown_sents)\n", "for k,v in p6.items():\n", " performances[\"P1.6 -- \" + k] = v\n", "\n", " \n", "print(\"\\nAll Performances:\")\n", "pprint.pprint(performances)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plotting Data" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "#weights = clf.named_steps['classifier'].feature_importances_\n", "#labels = clf.named_steps['vectorizer'].get_feature_names()\n", "\n", "#sort\n", "#weights, labels = (list(t) for t in zip(*sorted(zip(weights, labels))))\n", "\n", "fig_1, ax_1 = plt.subplots()\n", "plt.bar(np.arange(len(performances)), performances.values())\n", "plt.xticks(np.arange(len(performances)), performances.keys(), rotation=30, ha='right')\n", "plt.ylabel(\"performance\")\n", "plt.tight_layout()\n", "plt.show()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----\n", "## Task 2\n", "\n", "* the file `ru_syntagrus-ud-train-uncommented.conllu` is generated from the file `ru_syntagrus-ud-train.conllu` located here: https://github.com/UniversalDependencies/UD_Russian-SynTagRus. Changes to the original file:\n", " * removed commentaries (lines with leading `#`)\n", " * removed spaces in in long numbers (eg: `100 000` → `100000`)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "WORDS = 'words' #: column type for words\n", "POS = 'pos' #: column type for part-of-speech tags\n", "TREE = 'tree' #: column type for parse trees\n", "CHUNK = 'chunk' #: column type for chunk structures\n", "NE = 'ne' #: column type for named entities\n", "SRL = 'srl' #: column type for semantic role labels\n", "IGNORE = 'ignore' #: column type for column that should be ignored\n", "ru_corp = nltk.corpus.ConllCorpusReader(root=\"./\", \n", " fileids=[\"ru_syntagrus-ud-train-uncommented.conllu\"],\n", " columntypes=[IGNORE, WORDS, IGNORE, POS],\n", " encoding='utf-8')\n" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "ru_tagged = ru_corp.tagged_sents()\n", "\n", "\n", "\n", "X3,y3,tX3,ty3 = create_training_and_test_set(annotated_sentences=ru_tagged, \n", " relative_cutoff=0.8)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Model 04, Performance 2.1" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "P2.1\n", "start training…\n", "training done\n", "Accuracy: 0.7951261788284127\n", "0.7951261788284127\n" ] } ], "source": [ "print(\"P2.1\")\n", "performances2 = {}\n", "performances2['P2.1'] = model_01(X3,y3,tX3,ty3, max_size=5000) # 10000 here consumes too much memory on my laptop\n", "print(performances2['P2.1'])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Model 05, Performance 2.2" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "# write russian text out to file:\n", "f = open(\"ru_text.txt\", 'w')\n", "for word_features in tX3:\n", " f.write(word_features['word'] + \" \")\n", " if word_features['word'] == '.': \n", " f.write(\"\\n\") #new sentence → new line\n", "f.close()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* download the python 3 fork of the rdrpos-tagger: https://github.com/jacopofar/RDRPOSTagger-python-3\n", " ```\n", " mkdir -p ~/src\n", " cd ~/src\n", " git clone https://github.com/jacopofar/RDRPOSTagger-python-3.git\n", " ```\n", "* adjust `RDRPOS_TAGGER_PATH` to match with the download location" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "import sys, os\n", "\n", "# remember current working directory\n", "cwd = os.getcwd()" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['Node', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'tabStr']\n", "('\\nOutput file:', 'ru_text.txt.TAGGED')\n" ] } ], "source": [ "RDRPOS_TAGGER_PATH = os.environ['HOME'] + \"/src/RDRPOSTagger-python-3/pSCRDRtagger/\"\n", "\n", "sys.path.insert(0, RDRPOS_TAGGER_PATH)\n", "\n", "# change current working directory to RDRPOSTagger repo\n", "os.chdir(RDRPOS_TAGGER_PATH)\n", "\n", "import RDRPOSTagger as model05_tagger \n", "\n", "# train tagger (copied from RDRPOSTagger.py):\n", "r = model05_tagger.RDRPOSTagger()\n", "r.constructSCRDRtreeFromRDRfile(\"../Models/UniPOS/UD_Russian-SynTagRus/train.UniPOS.RDR\")\n", "DICT = model05_tagger.readDictionary(\"../Models/UniPOS/UD_Russian-SynTagRus/train.UniPOS.DICT\")\n", "\n", "# change back to our cwd\n", "os.chdir(cwd)\n", "\n", "# run trained tagger\n", "r.tagRawCorpus(DICT, \"ru_text.txt\")" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "tagged_words = []\n", "f = open(\"ru_text.txt.TAGGED\", 'r')\n", "for line in f:\n", " for splits in line.split():\n", " w,t = splits.rsplit('/',1) # use last occurence of '/' to split.\n", " tagged_words.append((w,t))\n" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "score_2_2 = sum((1 if tagged_words[i][1] == ty3[i] else 0)for i in range(len(tagged_words))) / len(tagged_words)\n", "performances2['P2.2'] = score_2_2\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Results of performance 2" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'P2.1': 0.7951261788284127, 'P2.2': 0.8884973715119793}\n" ] } ], "source": [ "pprint.pprint(performances2)" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAagAAAEYCAYAAAAJeGK1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMS4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvNQv5yAAAENVJREFUeJzt3X+w5XVdx/Hni12REsLJXSpZdHFc0B1DxRviYIYhM4vmbqU1YE46EehMlEo6rf0gXaf8OTqjUrmOplmGYGVrLlLpUoZIexHTWEOXH8qixkIKCsrPd3+cL87xust+98f33s+55/mYuXPP93s+99zXzH7vvPbzPZ/z/aaqkCSpNQctdABJknbFgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1aelCB9hby5Ytq5UrVy50DEnSPrryyitvqarlexo3cQW1cuVKZmdnFzqGJGkfJflKn3Ge4pMkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDVp4q4kIam/les/ttARtMjc8IbnzNvvcgYlSWqSBSVJapIFJUlqkgUlSWqSBSVJapIFJUlqkgUlSWqSBSVJapIFJUlqkgUlSWqSBSVJapIFJUlqkgUlSWqSBSVJapIFJUlqkgUlSWqSBSVJapIFJUlq0qAFlWRNkmuSbE+yfhfPPyrJliRXJfl8kmcPmUeSNDkGK6gkS4DzgdOA1cAZSVbPGfaHwIVV9WTgdODPhsojSZosQ86gTgC2V9V1VXU3cAGwbs6YAn6se3w48LUB80iSJsjSAV/7SODGse0dwFPnjHkN8M9Jfht4GPCsAfNIkibIQi+SOAN4X1WtAJ4NfCDJD2VKcnaS2SSzO3funPeQkqT5N+QM6ibgqLHtFd2+cWcCawCq6vIkhwDLgJvHB1XVRmAjwMzMTO1vsJXrP7a/LyH9gBve8JyFjiAtOkPOoLYCq5IcneRgRosgNs0Z81XgFIAkjwcOAZwiSZKGK6iquhc4B7gE+CKj1XpXJ9mQZG037HeBs5L8F/C3wIurar9nSJKkyTfkKT6qajOwec6+88YebwNOGjKDJGkyLfQiCUmSdsmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ1yYKSJDVp0IJKsibJNUm2J1m/mzG/mmRbkquTfHDIPJKkybF0qBdOsgQ4HzgV2AFsTbKpqraNjVkFvBo4qaq+meSIofJIkibLkDOoE4DtVXVdVd0NXACsmzPmLOD8qvomQFXdPGAeSdIEGbKgjgRuHNve0e0bdwxwTJLLknwmyZpdvVCSs5PMJpnduXPnQHElSS1Z6EUSS4FVwMnAGcC7kzx87qCq2lhVM1U1s3z58nmOKElaCEMW1E3AUWPbK7p943YAm6rqnqq6HvgSo8KSJE25IQtqK7AqydFJDgZOBzbNGfMRRrMnkixjdMrvugEzSZImxGAFVVX3AucAlwBfBC6sqquTbEiytht2CXBrkm3AFuBVVXXrUJkkSZOj9zLzJE8HVlXVXyZZDhzanZbbraraDGyes++8sccFnNt9SZL0fb1mUEn+GPg9Rp9ZAngI8NdDhZIkqe8pvl8C1gJ3AFTV14DDhgolSVLfgrq7Ox1XAEkeNlwkSZL6F9SFSd4FPDzJWcC/Au8eLpYkadr1WiRRVW9JcipwO3AscF5V/cugySRJU61XQSU5GvjUA6WU5EeSrKyqG4YMJ0maXn1P8V0E3D+2fV+3T5KkQfQtqKXdFckB6B4fPEwkSZL6F9TOsas/kGQdcMswkSRJ6n8liZcCf5PknUAY3Ubj1wdLJUmaen1X8V0LnJjk0G77O4OmkiRNvb6r+B4KPA9YCSxNAkBVbRgsmSRpqvU9xfePwG3AlcBdw8WRJGmkb0GtqKpd3o5dkqQh9F3F9+kkPz1oEkmSxvSdQT0deHGS6xmd4guj2zkdN1gySdJU61tQpw2aQpKkOfouM/8KQJIjgEMGTSRJEv3vqLs2yZeB64F/A24ALh4wlyRpyvVdJPE64ETgS1V1NHAK8JnBUkmSpl7fgrqnqm4FDkpyUFVtAWYGzCVJmnJ9F0l8q7vM0b8zuibfzcAdw8WSJE27vjOodcB3gVcAHweuBZ47VChJkvqu4rsDIMmPAR8dNJEkSfS/WOxLgNcC32N0Z90ABTxmuGiSpGnW9z2oVwJPqCpvUihJmhd934O6FrhzyCCSJI3rO4N6NaMLxl7B2O02qup3BkklSZp6fQvqXcAngS8weg9KkqRB9S2oh1TVuYMmkSRpTN/3oC5OcnaSn0ry4w98DZpMkjTV+s6gzui+v3psn8vMJUmD2WNBJTkIeGFVXTYPeSRJAnqc4quq+4F3zkMWSZK+r+97UJ9I8rwkGTSNJEmdvgX1EuAi4O4ktyf5dpLbB8wlSZpyfS8We9jQQSRJGtd3FR9J1gLP6DYvrap/GiaSJEk9T/EleQPwMmBb9/WyJK8fMpgkabr1nUE9G3hSt6KPJO8HruIHPxclSdIB03eRBMDDxx4ffqCDSJI0ru8M6vXAVUm2MLpZ4TOA9YOlkiRNvQedQSU5qXv498CJ3fe/A55WVR/a04snWZPkmiTbk+y20LrPWFWSmb3ILklaxPY0g3o78BTg8qo6HtjU94WTLAHOB04FdgBbk2yqqm1zxh3GaAHGFXsTXJK0uO2poO5JshFYkeTtc5/cww0LTwC2V9V1AEkuANYxWgU47nXAG4FX9U4tSVr09rRI4hcY3ajwu8CVu/h6MEcCN45t7+j2fV+S44GjqupjD/ZC3a0+ZpPM7ty5cw+/VpK0GDzoDKqqbklyEfDIqnr/gfzF3VXS3wq8eE9jq2ojsBFgZmamDmQOSVKb+lzN/D7g9H147ZuAo8a2V3T7HnAY8ATg0iQ3MFqEscmFEpIk6L/M/LIk7wQ+BNzxwM6q+uyD/MxWYFWSoxkV0+nAC8Z+9jZg2QPbSS4FXllVs73TS5IWrb4F9aTu+4axfQX8/O5+oKruTXIOcAmwBHhvVV2dZAMwW1W9VwRKkqZP36uZP3NfXryqNgOb5+w7bzdjT96X3yFJWpz6Xiz2J5K8J8nF3fbqJGcOG02SNM36XovvfYxO1T2y2/4S8PIhAkmSBP0LallVXQjcD6P3l4D7BkslSZp6fQvqjiSPYLQwgiQnArcNlkqSNPX6ruI7l9F1+B6T5DJgOfD8wVJJkqZe34LaBvwDcCfwbeAjjN6HkiRpEH1P8f0V8DjgT4F3AMcAHxgqlCRJfWdQT6iq1WPbW5LMvSq5JEkHTN8Z1Ge7hREAJHkq4CWJJEmD6TuDegrw6SRf7bYfBVyT5AtAVdVxg6STJE2tvgW1ZtAUkiTN0fdafF8ZOogkSeP6vgclSdK8sqAkSU2yoCRJTbKgJElNsqAkSU2yoCRJTbKgJElNsqAkSU2yoCRJTbKgJElNsqAkSU2yoCRJTbKgJElNsqAkSU2yoCRJTbKgJElNsqAkSU2yoCRJTbKgJElNsqAkSU2yoCRJTbKgJElNsqAkSU2yoCRJTbKgJElNsqAkSU2yoCRJTbKgJElNsqAkSU0atKCSrElyTZLtSdbv4vlzk2xL8vkkn0jy6CHzSJImx2AFlWQJcD5wGrAaOCPJ6jnDrgJmquo44MPAm4bKI0maLEPOoE4AtlfVdVV1N3ABsG58QFVtqao7u83PACsGzCNJmiBDFtSRwI1j2zu6fbtzJnDxrp5IcnaS2SSzO3fuPIARJUmtamKRRJIXAjPAm3f1fFVtrKqZqppZvnz5/IaTJC2IpQO+9k3AUWPbK7p9PyDJs4A/AH6uqu4aMI8kaYIMOYPaCqxKcnSSg4HTgU3jA5I8GXgXsLaqbh4wiyRpwgxWUFV1L3AOcAnwReDCqro6yYYka7thbwYOBS5K8rkkm3bzcpKkKTPkKT6qajOwec6+88YeP2vI3y9JmlxNLJKQJGkuC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUJAtKktQkC0qS1CQLSpLUpEELKsmaJNck2Z5k/S6ef2iSD3XPX5Fk5ZB5JEmTY7CCSrIEOB84DVgNnJFk9ZxhZwLfrKrHAm8D3jhUHknSZBlyBnUCsL2qrququ4ELgHVzxqwD3t89/jBwSpIMmEmSNCGWDvjaRwI3jm3vAJ66uzFVdW+S24BHALeMD0pyNnB2t/mdJNcMkli7sow5/x76YXHuvxh4rPdwgI71R/cZNGRBHTBVtRHYuNA5plGS2aqaWegc0tA81tsz5Cm+m4CjxrZXdPt2OSbJUuBw4NYBM0mSJsSQBbUVWJXk6CQHA6cDm+aM2QS8qHv8fOCTVVUDZpIkTYjBTvF17ymdA1wCLAHeW1VXJ9kAzFbVJuA9wAeSbAf+j1GJqS2eWtW08FhvTJywSJJa5JUkJElNsqAkSU2yoCRJTbKgply3vF9a1JIc2q0m1gSxoKZYktcAG5M8vtv2MlNadJK8ErgcePuuLlqtdllQUygjZwFnMDoGTk6yxM+gaTHpZk1vBU4CfgX4C+BlSY5d2GTqy4KaQl0RfZzRH+5m4FjgaQsaSjrwvgd8EnheVf1PVX2O0UWpn7iwsdSXBTW9vl5VtzD6A74DeHqSw8FTfVocqupeYEtV3Q+Q5CHAk4EvL2gw9WZBLXJJjk9yxNz93R8vXUldxujK8id3+zzVp4nyIMf5Hd3zYXTlnG8D185zPO0jC2qRSnJKkiuAPwE+kmTmQWZGlwLbgWOTvDTJb8xXTml/9D3Ou/90Hdk9vj3JaUl+eZ7jai9ZUItQkscBfwS8papOA7YAv1ZVleSgOWNTVXcC3wBeAawHbp/vzNLe2pvjvPNMYGmSPwc2AHfNX1rtC6/Ft0gkWQK8gNHpum8Bh1fV9d1zRwL/ATyxqn6ofJIs737ug1X1mnkLLe2l/TzONzC68ekbq+pt85da+8oPaS4CSc4EfhP4DvCLwBVV9abuuSWMTm1cCdzZzZiqe+4pwNeq6utJntTNpKQm7cdx/jPAfwMfBd5aVd9aiPzae57im3DdG8PvBl5UVacCFwCrkxwHUFX3MfrDvbWq7h37o30scCJwTzfOclKzDsBx/qNVtdVymiwW1ISrqpsZ3Vfr1G7XLPCTjE5/POBngU8kOSTJW5KcUFXbq+r8bhWf1LT9PM7fUVXeqXsCWVCLw8uB1yY5BHguo1nRnd0VIw4CHs3o1MingLur6j8XLqq0zzzOp4wFtQh0n/VYz+gDt8cAv1VVt9TI/cBjgNuAtVX1+wsYVdpnHufTx1V8i0T32Y8dwPFV9b9JHlpVd3X/szyiqr6xwBGl/eZxPl2cQS0S3ZvCzwc2ddt3dd/v949Wi4XH+XSxoBaRqrocuO+BlU3SYuRxPj08xbfIdLfNuG+hc0hD8jifDhaUJKlJnuKTJDXJgpIkNcmCkiQ1yYKSJDXJgpIkNcmCkiQ16f8BbcWS5a9DbRgAAAAASUVORK5CYII=\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "fig_2, ax_2 = plt.subplots()\n", "plt.bar(np.arange(len(performances2)), performances2.values())\n", "plt.xticks(np.arange(len(performances2)), performances2.keys(), rotation=30, ha='right')\n", "plt.ylabel(\"performance\")\n", "plt.tight_layout()\n", "plt.show()\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.6.5" } }, "nbformat": 4, "nbformat_minor": 2 }