2.3. Kolommen#

In dit hoofdstukje behandelen we een paar operaties die op de kolommen van een DataFrame van toepassing zijn.

2.3.1. Typen kolommen#

Bij het aanmaken van een DataFrame zelf, of een nieuwe kolom in een bestaand DataFrame, probeert pandas al te kijken welk type variabele er in een kolom staat. Als we ons eerste voorbeeld bekijken:

import pandas as pd

# We schrijven een 'dict' met alle informatie:
invoer = {'Naam': ['Pietje', 'Greetje', 'Daan'], 'Leeftijd': [23, 22, 25]}

# Vervolgens converteren we deze 'dict' naar een DataFrame object:
data = pd.DataFrame(invoer)


print(data['Naam'])
print(data['Leeftijd'])
0     Pietje
1    Greetje
2       Daan
Name: Naam, dtype: object
0    23
1    22
2    25
Name: Leeftijd, dtype: int64

dan kunnen we al zien dat pandas al wel herkend heeft dat de leeftijds-kolom alleen getallen bevat: het datatype (dtype) is een soort int. Maar van de kolom die de namen bevat, is het datatype geen str, maar blijkbaar object. Met zo’n object kunnen we wat trucjes uitvoeren. De belangrijkste daarvan is, dat we kunnen opvragen of er een specifieke tekst in de dataset zit:

filter_greetje = data['Naam'].str.contains('Greetje')
print(filter_greetje)
0    False
1     True
2    False
Name: Naam, dtype: bool

Dit is handig als we data willen filteren, met als voorwaarde dat er een bepaalde tekst in een kolom staat.

Voor de kolommen met een getal erin heb je al eerder gezien dat we direct een wiskundige operatie op de hele kolom kunnen toepassen. Daarover lees je meer in het volgende blokje.

2.3.2. Een nieuwe kolom maken#

Je kunt eenvoudig een nieuwe kolom aanmaken door een stukje code als hieronder. Merk op dat we meteen een wiskundige operatie op de hele kolom kunnen toepassen (delen door twee, kwadraat en keer \(\pi\)), zonder dat we iets als een for-loop nodig hebben.

De syntax om een nieuwe kolom aan te maken is vergelijkbaar als het opvragen van een bestaande kolom, alleen nu staat er data['nieuwe_kolom'] links van het = -teken.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

naam = ['M4', 'M6', 'M8', 'M10', 'M12']
diameter = [4, 6, 8, 10, 12]
invoer = {'Naam': naam, 'Diameter': diameter}

data = pd.DataFrame(invoer)

# Maak een nieuwe kolom aan, waarbij we het 
# oppervlak van een dwarsdoorsnede berekenen.

data['Oppervlak'] = (data['Diameter'] / 2) ** 2 * np.pi

print(data)

plt.plot(data['Naam'], data['Oppervlak'])
plt.grid()
plt.xlabel('Soort boutje')
plt.ylabel('Oppervlakte dwarsdoorsnede (mm²)')

plt.show()
  Naam  Diameter   Oppervlak
0   M4         4   12.566371
1   M6         6   28.274334
2   M8         8   50.265482
3  M10        10   78.539816
4  M12        12  113.097336
_images/05_b_kolommen_5_1.png

Let er wel op dat je nieuwe kolom evenveel rijen bevat als het originele DataFrame. De foutmelding is niet heel vriendelijk, maar als het goed is kun je onderaan nog lezen dat we niet genoeg waarden meegeven aan de nieuwe kolom.

naam = ['M6', 'M8', 'M10', 'M12']
diameter = [6, 8, 10, 12]
invoer = {'Naam': naam, 'Diameter': diameter}

data = pd.DataFrame(invoer)

# Maak een nieuwe kolom aan, waarbij we het 
# oppervlak van een dwarsdoorsnede handmatig invoeren.
data['Oppervlak'] = [28.3, 50.3, 78.5]

print(data)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-2cfc8ac89bc2> in <cell line: 9>()
      7 # Maak een nieuwe kolom aan, waarbij we het
      8 # oppervlak van een dwarsdoorsnede handmatig invoeren.
----> 9 data['Oppervlak'] = [28.3, 50.3, 78.5]
     10 
     11 print(data)

~/.local/lib/python3.8/site-packages/pandas/core/frame.py in __setitem__(self, key, value)
   3042         else:
   3043             # set column
-> 3044             self._set_item(key, value)
   3045 
   3046     def _setitem_slice(self, key: slice, value):

~/.local/lib/python3.8/site-packages/pandas/core/frame.py in _set_item(self, key, value)
   3118         """
   3119         self._ensure_valid_index(value)
-> 3120         value = self._sanitize_column(key, value)
   3121         NDFrame._set_item(self, key, value)
   3122 

~/.local/lib/python3.8/site-packages/pandas/core/frame.py in _sanitize_column(self, key, value, broadcast)
   3766 
   3767             # turn me into an ndarray
-> 3768             value = sanitize_index(value, self.index)
   3769             if not isinstance(value, (np.ndarray, Index)):
   3770                 if isinstance(value, list) and len(value) > 0:

~/.local/lib/python3.8/site-packages/pandas/core/internals/construction.py in sanitize_index(data, index)
    745     """
    746     if len(data) != len(index):
--> 747         raise ValueError(
    748             "Length of values "
    749             f"({len(data)}) "

ValueError: Length of values (3) does not match length of index (4)