{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "# Frequenties\n",
    "\n",
    "## Samenvatting\n",
    "\n",
    "In dit deeltje spreken we over frequenties. Het berekenen van frequenties is dikwijls een van de eerste stappen die men onderneemt na het verzamelen en opkuisen van ruwe gegevens.\n",
    "\n",
    "## De ruwe gegevens\n",
    "\n",
    "We zullen in dit deel vertrekken van een voorbeeld. Stel dat we inzicht willen krijgen in de laptops die gebruikt worden in een bedrijf. Er zijn 857 werknemers in dit bedrijf met een laptop. Van iedere laptop noteren we volgende gegevens: CPU-generatie en type, RAM-geheugen (in GB), geformatteerde harde schijfruimte (in GB) en het merk.\n",
    "\n",
    "We lezen de tabel in als volgt. Dat leidt tot volgende tabel (met `head()` tonen we enkel de eerste 5 lijnen):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>cpuGeneration</th>\n",
       "      <th>cpuType</th>\n",
       "      <th>RAM</th>\n",
       "      <th>diskspace</th>\n",
       "      <th>brand</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Kabylake</td>\n",
       "      <td>i7</td>\n",
       "      <td>4.0</td>\n",
       "      <td>232.5</td>\n",
       "      <td>Toshiba</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Kabylake</td>\n",
       "      <td>i5</td>\n",
       "      <td>2.0</td>\n",
       "      <td>992.5</td>\n",
       "      <td>Acer</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Haswell</td>\n",
       "      <td>i7</td>\n",
       "      <td>16.0</td>\n",
       "      <td>495.6</td>\n",
       "      <td>Dell</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Skylake</td>\n",
       "      <td>i7</td>\n",
       "      <td>4.0</td>\n",
       "      <td>217.2</td>\n",
       "      <td>Toshiba</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Broadwell</td>\n",
       "      <td>i5</td>\n",
       "      <td>4.0</td>\n",
       "      <td>245.8</td>\n",
       "      <td>Acer</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  cpuGeneration cpuType   RAM  diskspace    brand\n",
       "0      Kabylake      i7   4.0      232.5  Toshiba\n",
       "1      Kabylake      i5   2.0      992.5     Acer\n",
       "2       Haswell      i7  16.0      495.6     Dell\n",
       "3       Skylake      i7   4.0      217.2  Toshiba\n",
       "4     Broadwell      i5   4.0      245.8     Acer"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "laptops = pd.read_csv('datasets/laptops.csv', sep=';', decimal=',')\n",
    "laptops.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "In deze ruwe data zijn er 5 variabelen. Als eerste stap, bepalen we de meetniveau's. Deze zijn als volgt:\n",
    "\n",
    "- cpuGeneration: ordinaal\n",
    "- cpuType: ordinaal\n",
    "- RAM: ratio\n",
    "- diskspace: ratio, continu\n",
    "- brand: nominaal\n",
    "\n",
    "Voor de ordinale gegevens, moeten we de categorieën in de juiste volgorde zetten. We doen dit als volgt:\n",
    "\n",
    "De tabel met ruwe data is heel erg lang en het is dus ook heel moeilijk om uit deze tabel direct conclusies te trekken. Daarom dat we de data verder gaan verwerken. We controleren even of de datatypes in orde zijn:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "# ordinaal niveau maken\n",
    "cpuGenerationLevels = ['SandyBridge', 'IvyBridge', 'Haswell', 'Broadwell', 'Skylake', 'Kabylake']\n",
    "laptops.cpuGeneration = pd.Categorical(laptops.cpuGeneration, ordered=True, categories=cpuGenerationLevels)\n",
    "\n",
    "# ordinaal niveau maken\n",
    "cpuTypeLevels = ['i3', 'i5', 'i7']\n",
    "laptops.cpuType = pd.Categorical(laptops.cpuType, ordered=True, categories=cpuTypeLevels)\n",
    "\n",
    "# optioneel: nominaal niveau maken (bespaart geheugen)\n",
    "laptops.brand = pd.Categorical(laptops.brand)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "De tabel met ruwe data is heel erg lang en het is dus ook heel moeilijk om uit deze tabel direct conclusies te trekken. Daarom dat we de data verder gaan verwerken. We controleren even of de datatypes in orde zijn:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "pd.DataFrame(laptops.dtypes, columns=['dtype'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Absolute frequenties\n",
    "\n",
    "Een heel eenvoudige techniek kan al iets meer informatie opleveren: voor iedere variabele tel je hoeveel maal elke waarde voorkomt. Dit noemt men de (absolute) frequentie. Je kan dit in Python heel gemakkelijk berekenen met de functie `value_counts()`. Hier zie je hoe dat werkt (voor de kolom cpuType):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "i5    556\n",
       "i3    213\n",
       "i7     84\n",
       "Name: cpuType, dtype: int64"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "laptops.cpuType.value_counts()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "We berekenden hier de absolute frequenties van de variabele \"cpuType\". Het type\n",
    "\n",
    "* `i5` komt 556 keer voor,\n",
    "* `i3` komt 213 keer voor en\n",
    "* `i7` komt 84 keer voor.\n",
    "\n",
    "Je kan op dezelfde manier de frequenties berekenen van de andere variabelen. Het verkregen resultaat is een pandas Series. Als je bijvoorbeeld een lijst wil met alle mogelijke waarden, zonder frequenties, dan kan je dit als volgt doen:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['i7', 'i5', 'i3', NaN]\n",
       "Categories (3, object): ['i3' < 'i5' < 'i7']"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "laptops.cpuType.unique()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Als je nu de som berekent van alle frequenties, dan vind je 853. Dat komt niet overeen met het aantal lijnen in de tabel (857)! Dit komt omdat `value_counts()` de ontbrekende waarden (NaN) niet meetelt. Dat is jammer, want soms zijn er ontbrekende waarden die je niet snel ziet (omdat er bijvoorbeeld heel veel waarden zijn). Daarom dat het dikwijls beter is om die wel mee te tellen. Hier zie je hoe dat gaat:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "i5     556\n",
       "i3     213\n",
       "i7      84\n",
       "NaN      4\n",
       "Name: cpuType, dtype: int64"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "laptops.cpuType.value_counts(dropna=False)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "In dit geval zijn er dus vier ontbrekende-waarden.\n",
    "\n",
    "Standaard zal Python de waarden sorteren volgens hun frequentie. Als je dat niet wil, dan kan je dit oplossen met `sort_index()`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "i3    213\n",
       "i5    556\n",
       "i7     84\n",
       "Name: cpuType, dtype: int64"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "laptops.cpuType.value_counts().sort_index()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "In dit geval worden de waarden gesorteerd volgens de volgorde die we zelf opgaven. Dit is vooral handig voor variabelen die minstens ordinaal meetniveau hebben."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Klassen\n",
    "\n",
    "Merk op dat je absolute frequenties kan berekenen vanaf nominaal meetniveau. Je kan ze met andere woorden altijd berekenen. Er is echter een probleem bij continue variabelen of variabelen met heel veel mogelijke waarden. Om dat duidelijk te maken, bekijken we de kolom diskspace. Deze laat zien hoeveel vrije diskruimte er op de schijf was nadat deze geformatteerd werd. Als we nu gaan tellen hoeveel iedere waarde voorkomt, krijgen we het volgende:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "510.6     5\n",
       "488.9     4\n",
       "482.9     4\n",
       "494.1     4\n",
       "231.3     4\n",
       "         ..\n",
       "493.6     1\n",
       "996.7     1\n",
       "482.6     1\n",
       "1003.6    1\n",
       "234.0     1\n",
       "Name: diskspace, Length: 592, dtype: int64"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "laptops.diskspace.value_counts()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Op het eerste zicht is er niet veel aan de hand, maar de lijst is enorm lang (592 lijnen!) en de meeste frequenties zijn 1 of 2. Het resultaat is dus helemaal niet interessant en geeft zeker niet veel informatie over de data.\n",
    "\n",
    "Een oplossing bestaat erin om waarden bij elkaar te nemen in zogenaamde \"klassen\" en dan de frequentie per klasse te bepalen. In Python kan je klassen maken met het `cut()`-commando:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0       (200.0, 300.0]\n",
       "1      (900.0, 1000.0]\n",
       "2       (400.0, 500.0]\n",
       "3       (200.0, 300.0]\n",
       "4       (200.0, 300.0]\n",
       "            ...       \n",
       "852                NaN\n",
       "853     (200.0, 300.0]\n",
       "854     (200.0, 300.0]\n",
       "855     (200.0, 300.0]\n",
       "856     (200.0, 300.0]\n",
       "Name: diskspace, Length: 857, dtype: category\n",
       "Categories (11, interval[int64, right]): [(0, 100] < (100, 200] < (200, 300] < (300, 400] ... (700, 800] < (800, 900] < (900, 1000] < (1000, 1100]]"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cutpoints = range(0, 1200, 100)\n",
    "klassen = pd.cut(laptops.diskspace, bins=cutpoints)\n",
    "klassen"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "We kunnen nu de absolute frequenties van de **klassen** berekenen:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(0, 100]         29\n",
       "(100, 200]       52\n",
       "(200, 300]      407\n",
       "(300, 400]        0\n",
       "(400, 500]      227\n",
       "(500, 600]       96\n",
       "(600, 700]        0\n",
       "(700, 800]        0\n",
       "(800, 900]        0\n",
       "(900, 1000]      19\n",
       "(1000, 1100]     21\n",
       "Name: diskspace, dtype: int64"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "klassen.value_counts().sort_index()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Eerst bepaal je de grenzen van de klassen (in dit voorbeeld in de variabele \"cutpoints\"). Het commando `pd.cut()` zal dan iedere waarde vervangen door een string die het interval voorstelt waarbinnen de waarde valt. De variabele wordt dus omgezet van interval meetniveau naar ordinaal meetniveau! De intervallen beginnen in dit geval altijd met een rond haakje en ze eindigen met een recht haakje. Dit geeft aan dat de linkergrens niet inbegrepen is. De schijfruimte 200 zal dus niet in $(200,300]$ zitten, maar wel in $(100,200]$. Als je dit andersom wil doen, dan kan dat als volgt:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[0, 100)         29\n",
       "[100, 200)       52\n",
       "[200, 300)      407\n",
       "[300, 400)        0\n",
       "[400, 500)      227\n",
       "[500, 600)       96\n",
       "[600, 700)        0\n",
       "[700, 800)        0\n",
       "[800, 900)        0\n",
       "[900, 1000)      19\n",
       "[1000, 1100)     21\n",
       "Name: diskspace, dtype: int64"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "klassen = pd.cut(laptops.diskspace, bins=cutpoints, right=False)\n",
    "klassen.value_counts().sort_index()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "In dit geval geeft dit dezelfde frequenties omdat de randgevallen nooit voorkomen. Als dat wel zo is, dan kunnen beide commando's verschillende resultaten geven.\n",
    "\n",
    "Opdelen in klassen lijkt het probleem op te lossen, maar er blijft nog 1 vraag over: hoeveel klassen moet je maken? Als je te veel klassen maakt, dan krijg je het oorspronkelijke probleem weer. Maar als je te weinig klassen maakt, gaat er veel informatie verloren. Er zijn een aantal manieren om het aantal klassen (m) te bepalen:\n",
    "\n",
    "-   Sturges: $m=\\lceil1+log_{2}(n)\\rceil$\n",
    "-   Scott: $b=3.5\\cdot \\frac{s_{X}}{\\sqrt[3]{n}}$, $m=\\lceil\\frac{(\\max(X)-\\min(X))}{b}\\rceil$\n",
    "-   MS Excel: $m=\\lceil\\sqrt{n}\\rceil$\n",
    "\n",
    "Hierbij is $\\lceil x\\rceil$ het kleinste geheel getal dat groter is dan $x$ (je rondt $x$ dus gewoon af naar boven). Deze functie komt overeen met de math.ceil() functie in Python. Het getal $n$ is het aantal waarden (de lengte) van de variabele $x$ en $s_{X}$ is de standaardafwijking van de variabele (zie het deeltje over spreidingsmaten). Het aantal klassen is $m$. De regel van Scott berekent eerst de klassenbreedte $b$ en aan de hand daarvan het aantal klassen $m$.\n",
    "\n",
    "In Python kan je deze waarden als volgt berekenen (we gebruiken variabelen `n` en `diskspace` en verwijderen eerst de NaN-waarden):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "diskspace = laptops.diskspace.dropna()\n",
    "n = len(diskspace)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "m = 11\n"
     ]
    }
   ],
   "source": [
    "import math\n",
    "\n",
    "# Sturges\n",
    "m = math.ceil(1 + math.log2(n))\n",
    "print(f'm = {m}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "m = 13\n"
     ]
    }
   ],
   "source": [
    "from statistics import stdev\n",
    "\n",
    "# Scott\n",
    "b = 3.5 * stdev(diskspace) / (n ** (1 / 3))\n",
    "m = math.ceil((diskspace.max() - diskspace.min()) / b)\n",
    "print(f'm = {m}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "m = 30\n"
     ]
    }
   ],
   "source": [
    "# Excel\n",
    "m = math.ceil(math.sqrt(n))\n",
    "print(f'm = {m}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Het lijkt hier dus aangewezen om 11 tot 13 klassen te maken (30 is echt wel teveel). Je kan handmatig natuurlijk ook een ander aantal klassen maken, afhankelijk van je doel. Algemeen wordt wel aangenomen dat het aantal klassen steeds tussen 5 en 20 moet liggen om een duidelijk beeld te kunnen geven.\n",
    "\n",
    "Als je weet hoeveel klassen je wil maken, kan je de frequenties ook heel snel als volgt berekenen (we maken hier 11 klassen):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(87.363, 173.345]      81\n",
       "(173.345, 258.391]    407\n",
       "(258.391, 343.436]      0\n",
       "(343.436, 428.482]      0\n",
       "(428.482, 513.527]    323\n",
       "(513.527, 598.573]      0\n",
       "(598.573, 683.618]      0\n",
       "(683.618, 768.664]      0\n",
       "(768.664, 853.709]      0\n",
       "(853.709, 938.755]      0\n",
       "(938.755, 1023.8]      40\n",
       "Name: diskspace, dtype: int64"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "diskspace.value_counts(bins=11).sort_index()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Relatieve frequenties\n",
    "\n",
    "Absolute frequenties tellen hoeveel keer een bepaalde waarde voorkomt. Maar deze waarde heeft eigenlijk niet zo veel betekenis. Als je veel metingen doet, zullen de absolute frequenties ook groter zijn. We zijn dikwijls meer geïnteresseerd hoeveel een waarde voorkomt ten opzichte van het totaal. Dan kunnen we dit ook in procenten uitdrukken en het geeft ineens ook een mogelijkheid om dit te vergelijken met andere studies waarin het aantal metingen verschillend is. We zoeken dus hoeveel procent van de waarden gelijk is aan een bepaalde waarde.\n",
    "\n",
    "Dit noemen we relatieve frequenties. In Python bereken je ze als volgt:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "HP         0.227804\n",
       "Dell       0.188084\n",
       "Toshiba    0.151869\n",
       "Acer       0.151869\n",
       "Lenovo     0.091121\n",
       "Asus       0.075935\n",
       "Apple      0.075935\n",
       "Medion     0.037383\n",
       "Name: brand, dtype: float64"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "laptops.brand.value_counts(normalize=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Als je dit in procenten wil zien, dan vermenigvuldig je deze cijfers met 100:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "HP         22.8\n",
       "Dell       18.8\n",
       "Toshiba    15.2\n",
       "Acer       15.2\n",
       "Lenovo      9.1\n",
       "Asus        7.6\n",
       "Apple       7.6\n",
       "Medion      3.7\n",
       "Name: brand, dtype: float64"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(laptops.brand.value_counts(normalize=True) * 100).round(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "De functie `round()` wordt hier enkel gebruikt om de output iets leesbaarder te maken. Je kan deze ook weg laten. Van de onderzochte laptops is dus bijvoorbeeld 15.2% van het merk **Acer**."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Cumulatieve frequenties\n",
    "\n",
    "Wanneer een variabele ordinaal meetniveau heeft, kunnen we nog andere frequenties bepalen. Neem bijvoorbeeld de generatie van de processor die er in de laptop aanwezig is (cpuGeneration). Deze variabele is ordinaal want de processoren worden steeds beter in de volgende volgorde: Sandy Bridge, Ivy Bridge, Haswell, Broadwell, Skylake, Kabylake. Men nummert deze generaties ook dikwijls van 2 tot en met 7.\n",
    "\n",
    "We kunnen ons nu afvragen: hoeveel laptops hebben een Haswell processor? Dit kunnen we doen door alle absolute frequenties van Sandy Bridge, Ivy Bridge en Haswell op te tellen. Op dezelfde manier kunnen we tellen hoeveel laptops van een andere generatie zijn of minder. We moeten dus telkens de absolute frequenties optellen. Dit noemt men de cumulatieve som.\n",
    "\n",
    "In Python kan je deze berekenen met de functie `cumsum()`. Deze functie levert een lijst van waarden waarvan de eerste waarde gelijk is aan die van de oorspronkelijke lijst. De tweede waarde is gelijk aan de eerste twee waarden opgeteld, de derde waarde is gelijk aan de eerste drie waarden opgeteld, enzovoort.\n",
    "\n",
    "Hier zie je een voorbeeldje om de werking duidelijk te maken:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>getallen</th>\n",
       "      <th>cumsum</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>3</td>\n",
       "      <td>6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>4</td>\n",
       "      <td>10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>5</td>\n",
       "      <td>15</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   getallen  cumsum\n",
       "0         1       1\n",
       "1         2       3\n",
       "2         3       6\n",
       "3         4      10\n",
       "4         5      15"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "getallen = pd.Series(range(1, 6), name='getallen')\n",
    "cumulatieve_som = pd.Series(getallen.cumsum(), name='cumsum')\n",
    "pd.concat([getallen, cumulatieve_som], axis=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Hier zie je hoe je de cumulatieve frequenties in Python kan berekenen:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Broadwell       218\n",
       "Haswell         384\n",
       "Ivy Bridge      491\n",
       "Kabylake        634\n",
       "Sandy Bridge    697\n",
       "Skylake         852\n",
       "Name: cpuGeneration, dtype: int64"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "laptops.cpuGeneration.value_counts().sort_index().cumsum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Er zijn dus 336 laptops die een Haswell processor hebben of minder. Bemerk dat de laatste cumulatieve frequentie altijd gelijk moet zijn aan $n$. We hebben de `NaN` waarden weggelaten. Het heeft toch geen zin om te weten hoeveel computers `NaN` of minder hebben als processor. Wat ook belangrijk is, is dat we de waarden uitdrukkelijk niet sorteren volgens frequentie, maar wel volgens de volgorde die we zelf bepaalden (`sort_index()`). Dit is zeer belangrijk omdat de volgorde nu bepaalt hoe we de frequenties optellen."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "## Cumulatieve percentages\n",
    "\n",
    "De cumulatieve frequenties hebben weer niet zoveel zin op zich. Het is handiger om ze uit te drukken als percentages. Dit doe je als volgt:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Broadwell        25.6\n",
       "Haswell          45.1\n",
       "Ivy Bridge       57.6\n",
       "Kabylake         74.4\n",
       "Sandy Bridge     81.8\n",
       "Skylake         100.0\n",
       "Name: cpuGeneration, dtype: float64"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(laptops.cpuGeneration.value_counts(normalize=True).sort_index().cumsum() * 100).round(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Dit noemt men **cumulatieve percentages**. De functie `round()` dient weer gewoon om de getallen leesbaarder te maken. We zien dus bijvoorbeeld dat 83,2% van de laptops een Skylake processor heeft of minder (waarbij we de `NaN` waarden dus niet meegeteld hebben).\n",
    "\n",
    "Men noemt de cumulatieve percentages ook wel *percentielscores*. Dat gebeurt meestal in een context waarin de mogelijke waarden scores zijn. Een voorbeeldje moet dit duidelijk maken. Stel dat je behaalde punten op een examen in een variabele 'scores' hebt. Deze scores zijn gehele waarden tussen 0 en 10. Als je de percentielscores berekent, vind je bijvoorbeeld volgende waarden:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%%\n"
    },
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>percentiel score</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1.1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>10.3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>11.4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>33.6</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>55.4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>65.1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>84.2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>98.1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>100.0</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    percentiel score\n",
       "0                1.1\n",
       "1               10.3\n",
       "2               11.4\n",
       "3               33.6\n",
       "4               55.4\n",
       "5               65.1\n",
       "6               84.2\n",
       "7               98.1\n",
       "8              100.0\n",
       "9              100.0\n",
       "10             100.0"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# NO CODE\n",
    "pd.DataFrame([[1.1], [10.3], [11.4], [33.6], [55.4], [65.1], [84.2], [98.1], [100.0], [100.0], [100.0]],\n",
    "             index=range(11), columns=['percentiel score'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false,
    "pycharm": {
     "name": "#%% md\n"
    }
   },
   "source": [
    "Hier zie je dus dat 84,2 procent van de studenten 6 of minder haalde. Dat wil dus zeggen dat de toets heel moeilijk was. 55,4 procent was ook gebuisd (4/10 of minder). Om te compenseren voor deze moeilijke test, zou je dus de percentielscore kunnen gebruiken in plaats van de oorspronkelijke score. Je krijgt dan een score ten opzichte van de groep. In dit geval zou iemand met 4/10 dan geslaagd zijn. Het nadeel van deze aanpak is dat je dan op voorhand weet dat 50 procent van de deelnemers zal slagen, ongeacht het kennisniveau.\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}