Datums en tijdreeksen met pandas
GemiddeldLes 6 van 8 in Cursus Data-analyse met Python: NumPy, pandas en visualisatie
Wat je leert
- Sla tijdstippen en tijdsduren op in de datetime-types van pandas, lees datums uit tekst in zonder dag en maand te verwisselen en haal kalenderonderdelen zoals maand en weekdag eruit.
- Werk met tijdstempels, tijdsduren en kalenderonderdelenGebruik Timestamp, Timedelta en het datatype datetime64, bereken de tijd tussen gebeurtenissen en haal onderdelen zoals jaar, uur en weekdag eruit met de
.dt-accessor. - Lees datums uit tekst in en maak ze op voor uitvoerConverteer tekst en getallen naar datetime-waarden met
pd.to_datetime, kies formaten zodat dag en maand nooit worden verwisseld, verwerk waarden die niet kunnen worden ingelezen en zet datetime-waarden terug om naar leesbare tekst.
- Werk met tijdstempels, tijdsduren en kalenderonderdelen
- Maak een opgeschoonde, gesorteerde tijdindex, selecteer daarmee elke gewenste dag, maand of elk gewenst tijdvenster en vergelijk elke waarde met eerdere waarden.
- Maak en controleer een tijdindexMaak van een datetime-kolom een gesorteerde DatetimeIndex, verwerk dubbele tijdstempels en bepaal de frequentie en ontbrekende datums van een reeks.
- Selecteer rijen op datum en tijdstip van de dagSelecteer volledige jaren, maanden, dagen en bereiken met datumtekenreeksen, filter op weekdag of tijdstip en voorkom vergissingen die de verkeerde rijen opleveren.
- Vergelijk waarden door de tijd met verschuivingen, verschillen en procentuele veranderingenVerschuif waarden achteruit en vooruit, bereken veranderingen en groeipercentages en begrijp hoe pandas twee tijdreeksen op datum uitlijnt.
- Maak en controleer een tijdindex
- Maak regelmatige reeksen datums, verschuif datums volgens kalenderregels zoals “één maand later” of “volgende werkdag” en werk met volledige maanden, kwartalen en boekjaren als perioden.
- Maak regelmatige datumreeksen met frequentiecodesGenereer reeksen datums en tijden met
pd.date_range, kies de juiste frequentiecode en bepaal de eerste en laatste datum correct. - Verschuif datums volgens kalenderregelsOnderscheid vaste tijdsduren van kalenderregels en gebruik DateOffset en verschuivingen naar maandeinden, werkdagen en andere kalenderpunten om datums correct te verschuiven.
- Werk met volledige maanden, kwartalen en boekjaren als periodenGeef tijdsintervallen weer met Period en PeriodIndex, converteer tussen tijdstempels en perioden en verwerk kwartalen van een boekjaar.
- Maak regelmatige datumreeksen met frequentiecodes
- Aggregeer gedetailleerde gegevens tot dag-, week-, maand- of kwartaaltotalen en -gemiddelden, vul een fijner tijdsraster en pas resampling tegelijk toe op meerdere reeksen.
- Verlaag de frequentie met totalen, gemiddelden en andere samenvattingenGebruik
resampleom gegevens in ruimere tijdsintervallen te aggregeren, kies de juiste aggregatie en lees intervalgrenzen en -labels correct. - Verhoog de frequentie van een tijdreeks en vul ontbrekende waarden aanZet gegevens over naar een fijner tijdsraster, vul nieuwe tijdspunten door waarden vooruit of achteruit door te geven of te interpoleren, en maak ontbrekende datums zichtbaar.
- Pas resampling via groepen op meerdere tijdreeksen tegelijk toePas resampling per groep toe op een lange tabel met veel winkels, sensoren of klanten en herstructureer het resultaat om het te vergelijken.
- Verlaag de frequentie met totalen, gemiddelden en andere samenvattingen
- Bereken voortschrijdende gemiddelden en andere vensterstatistieken over een aantal rijen of een tijdsinterval, en cumulatieve totalen en gewogen gemiddelden die de volledige geschiedenis meenemen.
- Bereken voortschrijdende statistieken over een vast aantal rijenGebruik
rolling(n)voor voortschrijdende gemiddelden, sommen en andere statistieken, bepaal hoe onvolledige vensters worden verwerkt en pas vensters per groep toe. - Gebruik tijdgebaseerde vensters voor onregelmatige gegevensDefinieer vensters met een tijdsinterval zoals “7D”, begrijp welke waarnemingen elk venster bevat en kies tussen vensters op basis van rijen en tijdgebaseerde vensters.
- Houd cumulatieve totalen, cumulatieve maxima en exponentieel gewogen gemiddelden bijGebruik uitbreidende vensters voor cumulatieve statistieken en relatieve dalingen vanaf het cumulatieve maximum, en exponentieel gewogen gemiddelden die recente waarden meer gewicht geven.
- Bereken voortschrijdende statistieken over een vast aantal rijen
- Ken de juiste tijdzone toe aan tijdstempels, converteer tussen tijdzones, combineer gegevens uit verschillende tijdzones en verwerk de uren die bij de overgang naar of van zomertijd worden overgeslagen of herhaald.
- Ken tijdzones toe aan tijdstempels en converteer tussen tijdzonesOnderscheid tijdstempels zonder en met tijdzone, ken een tijdzone toe met
tz_localize, converteer mettz_converten combineer gegevens die in verschillende tijdzones zijn vastgelegd. - Verwerk zomertijd in tijdreeksenHerken overgeslagen en herhaalde lokale uren, ken daar bewust een tijdzone aan toe en pas resampling en verschuivingen correct toe op dagen met 23 of 25 uur.
- Ken tijdzones toe aan tijdstempels en converteer tussen tijdzones
Tijdreeksen met pandas: uitleg
1Zet datums en tijden om in gegevens waarmee pandas kan rekenen
Datums komen binnen als tekenreeksen, getallen en kloktijden, maar voor een analyse is een consistente weergave nodig. Leer die invoer om te zetten in tijdstippen en tijdsduren, mislukte conversies te controleren en bruikbare kalenderonderdelen uit te lezen. De voorbeelden maken onderscheid tussen een opgeslagen datetime-waarde en de tekst waarin die wordt weergegeven, zodat je later bij sorteren, selecteren en rekenen rekening houdt met de kalender. Kleine details zoals formaatcodes voor maand en minuut en de opslagresolutie kunnen een resultaat sterk veranderen.
1.1 Werk met tijdstempels, tijdsduren en kalenderonderdelen
Een datum is bruikbaarder als pandas weet dat het een datum is. Een tijdreeks koppelt waarnemingen aan tijdstippen of tijdsintervallen. Energiemetingen per uur vormen een regelmatige reeks; bestellingen die met onregelmatige tussenpozen binnenkomen, vormen een onregelmatige reeks. Tekst zoals “12/31/2024” kan na “03/01/2025” worden gesorteerd, hoewel december eerder kwam. Consequent gebruikte volledige ISO-tekenreeksen worden correct gesorteerd, maar met datetime-waarden kun je ook op kalenderonderdelen selecteren en rekenen.
Kies het juiste tijdobject
Python biedt datetime, date en timedelta. In pandas bevat een Timestamp één tijdstip, heeft een datetime-kolom het datatype datetime64[unit] en bevat een DatetimeIndex datetime-rijlabels. NaT betekent een ontbrekend tijdstip. Spoor dit op met pd.isna(); als je een ontbrekend tijdstip aftrekt, levert dat opnieuw een ontbrekend tijdstip op.
De eenheid in datetime64[us] is microseconden, de opslagresolutie. Andere eenheden zijn seconden (s), milliseconden (ms) en nanoseconden (ns). pandas 3 leest tekst normaal in met microseconderesolutie en gebruikt nanoseconden als de tekst die nodig heeft. Een fijnere resolutie gebruikt meer van het bereik van gehele getallen: datums met nanoseconderesolutie lopen slechts van 1677 tot 2262.
Bereken verstreken tijd
import pandas as pd
start = pd.Timestamp("2025-03-10 18:00")
end = pd.Timestamp("2025-03-14 09:30")
elapsed = end - start
hours = elapsed / pd.Timedelta(hours=1)
elapsed is 3 dagen, 15 uur en 30 minuten. De drie dagen dragen 72 uur bij, dus hours is 87,5. elapsed.total_seconds() geeft 315.000. Het attribuut .days geeft alleen 3; dat is het aantal volledige dagen, niet de volledige tijdsduur in dagen. Maak tijdsduren met pd.Timedelta(hours=36) of lees er meerdere in met pd.to_timedelta(["1h", "90min"]).
Als je een tijdstempel van een volledige datetime-kolom aftrekt, krijg je per rij een tijdsduur. Gebruik .dt.days voor het aantal volledige dagen of deel de kolom met tijdsduren door een Timedelta met een tijdseenheid voor totalen met een breukdeel.
Lees kalenderonderdelen uit en rond tijden af
Op een kolom halen .dt.year, .dt.month, .dt.hour en .dt.quarter kalenderonderdelen eruit. .dt.day_of_week nummert maandag als 0 tot en met zondag als 6; .dt.day_name() geeft een naam. 14 maart 2025 is een vrijdag, met nummer 4. Bij een index gebruik je deze attributen rechtstreeks: df.index.month. De schrijfwijzen day_of_week en day_of_year vervangen oudere schrijfwijzen die in pandas 3.1 als verouderd zijn aangemerkt.
Een weekdag kan een groeperingssleutel worden: df.groupby(df["timestamp"].dt.day_name())["kwh"].mean(). Groeperen op maandnummer combineert die maand over verschillende jaren; een maandperiode houdt elk jaar apart.
Voor 09.37 uur geeft .dt.floor("h") 09.00 uur, .dt.ceil("h") 10.00 uur en .dt.round("15min") 09.30 uur. .dt.normalize() stelt de kloktijd in op middernacht en behoudt datetime-waarden. .dt.date levert daarentegen Python-date-objecten op en verliest de functies van een datetime-kolom.
Houd numerieke eenheden expliciet
astype("int64") geeft aantallen in de eigen eenheid van de kolom. Een aantal microseconden is 1.000 keer kleiner dan het aantal nanoseconden voor hetzelfde moment. Als een externe berekening nanoseconden nodig heeft, gebruik je s.dt.as_unit("ns").astype("int64"); een Timestamp of index gebruikt rechtstreeks .as_unit("ns"). Voor verstreken tijd voorkom je die eenheidsvalkuil door met Timedelta-waarden te rekenen.
Belangrijkste punten
- Een Timestamp is een tijdstip; een Timedelta is verstreken tijd.
- Gebruik Timedelta-waarden met een tijdseenheid om volledige tijdsduren te krijgen, inclusief breukdelen.
- Kalenderattributen gebruiken
.dtop kolommen en directe toegang op indexen. - Ontbrekende tijdstippen zijn
NaT. - Aantallen als gehele getallen voor datetime-waarden hangen af van de opslagresolutie.
1.2 Lees datums uit tekst in en maak ze op voor uitvoer
Door tekst in te lezen geef je die een kalenderbetekenis. Stel vóór het converteren van een datumkolom het formaat vast en controleer of de kolom tijdsverschillen, ongeldige invoer of ontbrekende waarden bevat. ISO 8601 schrijft het jaar eerst, zoals in “2025-03-14T09:30:00”, en voorkomt dubbelzinnigheid tussen dag en maand.
Geef het bronformaat op
“03/04/2025” kan 4 maart of 3 april betekenen. pd.to_datetime("03/04/2025") leest de maand eerst; dayfirst=True leest de dag eerst. Een bekend formaat opgeven is duidelijker:
raw = pd.Series(["14/03/2025 18:45", "15/03/2025 09:00"])
parsed = pd.to_datetime(raw, format="%d/%m/%Y %H:%M")
%Y is een jaar met vier cijfers, %m een maand en %d een dag. %H is een uur op een 24-uursklok, %M een minuut en %S een seconde. Gebruik %I met %p voor een 12-uursklok en AM/PM. %b en %B lezen afgekorte en volledige maandnamen. De hoofdletter %M betekent minuten en kan dus de kleine letter %m voor maanden niet vervangen.
Zonder format leidt pandas een formaat af uit de eerste aanwezige waarde en past het dat toe op de kolom. Als “03/04/2025” eerst komt, mislukt een latere “13/04/2025” wanneer is afgeleid dat de maand eerst komt. Als je de rijen anders ordent, kan het afgeleide formaat veranderen. format="ISO8601" verwerkt ISO-varianten. format="mixed" leest waarden afzonderlijk in, maar kan niet bepalen welke dubbelzinnige conventie de bron gebruikt; schoon die conventie eerst op of controleer die.
Inspecteer mislukte conversies
raw = pd.Series(["2025-01-15", "not a date", None])
parsed = pd.to_datetime(raw, format="%Y-%m-%d", errors="coerce")
failed = parsed.isna() & raw.notna()
Het resultaat bevat 15 januari en twee NaT-waarden. parsed.isna().sum() is 2 omdat ook de oorspronkelijk ontbrekende waarde wordt meegeteld. failed.sum() is 1 omdat alleen “not a date” aanwezig was en niet kon worden ingelezen. Inspecteer raw[failed] voordat je besluit de waarde te herstellen of te verwijderen. Met deze typeconversie kan het inlezen doorgaan, maar ze verbergt ook typefouten zoals een onmogelijke maand. De standaardinstelling errors="raise" stopt bij ongeldige invoer; pandas 3 heeft errors="ignore" verwijderd.
Lees bestanden en numerieke tijdstempels in
pd.read_csv("meter.csv", parse_dates=["timestamp"], index_col="timestamp") vraagt om de datum en tijd in te lezen en een tijdindex te maken. Controleer na het inlezen de resulterende datatypes. Tekstkolommen in pandas 3 gebruiken het datatype str; oudere versies tonen meestal object.
Voeg aparte datum- en tijdtekenreeksen met een spatie samen voordat je ze inleest. Kolommen met de namen year, month en day kun je rechtstreeks combineren met pd.to_datetime(df[["year", "month", "day"]]).
Geef voor Unix-aantallen de eenheid op. pd.to_datetime(1735689600, unit="s", utc=True) geeft middernacht UTC op 1 januari 2025. Het aantal milliseconden is 1735689600000 met unit="ms". Als je de verkeerde eenheid gebruikt, verandert het geïnterpreteerde tijdstip.
Maak pas op voor presentatie
parsed.dt.strftime("%d %b %Y") schrijft tekst zoals “15 Jan 2025”. De methode .isoformat() van een Timestamp schrijft een ISO-tekenreeks. Maand- en weekdagnamen volgen de taal- en regio-instellingen van het systeem; de getoonde voorbeelden gebruiken Engels. Behoud datetime-waarden tijdens de analyse en maak ze op bij export, omdat je met tekenreeksen niet meer als datums kunt rekenen.
Belangrijkste punten
- Gebruik bij voorkeur eenduidige ISO-datums als je de bron bepaalt.
- Geef een bekend inleesformaat expliciet op.
- Onderscheid ongeldige invoer van waarden die al ontbraken.
- Gebruik bij Unix-aantallen de juiste eenheid: seconden of milliseconden.
- Maak aan het einde van de analyse op als tekst.
%mbetekent maand;%Mbetekent minuut.
2Indexeer, selecteer en vergelijk gegevens op basis van tijd
Een tijdindex maakt datums bruikbaar als rijlabels, maar vóór het vergelijken moet je de labels zorgvuldig controleren. Sorteer waarnemingen, bepaal wat dubbele tijdstempels betekenen en maak ontbrekende datums zichtbaar. Selecteer daarna kalenderperioden of terugkerende tijdvensters en vergelijk waarden met eerdere waarden. Het centrale onderscheid is dat tussen rijpositie en werkelijke tijd: een vorige rij kan meerdere dagen eerder zijn en twee reeksen worden gecombineerd door tijdstempels te koppelen.
2.1 Maak en controleer een tijdindex
Een bruikbare tijdindex is ingelezen, geordend en gecontroleerd. Een tabel kan meerdere gebeurtenissen op één moment, ontbrekende dagen of ongeordende gegevensbatches bevatten. Elke situatie verandert de betekenis van latere berekeningen.
Maak datetime-rijlabels
df["timestamp"] = pd.to_datetime(df["timestamp"], format="%Y-%m-%d %H:%M")
df = df.set_index("timestamp").sort_index()
set_index() verplaatst de kolom naar de rijlabels; het leest geen tekst in als datum en tijd. Controleer met df.index.dtype of het datatype een datetime-type is en met df.index.is_monotonic_increasing of de volgorde chronologisch is. Gelijke opeenvolgende tijden zijn toegestaan in een stijgende index, dus deze controle stelt de uniciteit niet vast.
Een DatetimeIndex ondersteunt selectie op datum en resampling. Tekstlabels worden geen tijdindex alleen omdat ze op datums lijken. Je kunt tijdstempels ook in een kolom laten staan: df.resample("D", on="timestamp") gebruikt die kolom zonder de index te veranderen. Een PeriodIndex is een andere weergave van een tijdreeks wanneer rijen tijdsintervallen zoals maanden beschrijven.
Bepaal wat herhaalde tijdstippen betekenen
df.index.is_unique geeft aan of elk label verschillend is. df.index.duplicated() markeert herhaalde labels na het eerste. Stel dat twee metingen, 3 en 5, bij 1 januari horen en een meting van 4 bij 2 januari. Als je dubbele metingen met df.groupby(level=0).mean() middelt, krijg je op beide datums 4,0.
Die bewerking is een beslissing over de gegevens. Als rijen afzonderlijke aankopen zijn, kan optellen geschikt zijn. Als een import een record heeft verdubbeld, kan het geschikt zijn om met df[~df.index.duplicated(keep="last")] de laatste kopie te behouden. Verwijder geen geldige transacties uitsluitend om een index uniek te maken. Bewerkingen die op elk doellabel één waarde plaatsen, waaronder reindex() en asfreq(), vereisen unieke bronlabels.
Onderscheid opgeslagen en afgeleide frequentie
Een index die met pd.date_range() is gemaakt, heeft normaal een .freq. Bij ingelezen tijdstempels is .freq vaak gelijk aan None, ook als ze op opeenvolgende dagen vallen. pd.infer_freq(df.index) onderzoekt minstens drie tijdstempels en geeft een code zoals “D” of “ME” terug als het een regelmatig patroon vindt. Onregelmatige tussenpozen geven None.
Frequentiemetadata vormen geen controle op volledigheid. Maak de kalender die je verwacht om afwezige dagelijkse rijen te zoeken:
calendar = pd.date_range(df.index.min(), df.index.max(), freq="D")
missing = calendar.difference(df.index)
Een ontbrekende dag heeft geen rij. Dat verschilt van een aanwezige rij met NaN. Een kalender die wordt begrensd door het waargenomen minimum en maximum kan geen ontbrekende datums buiten dat bereik onthullen; gebruik de geplande begin- en einddatum van de rapportage als die bekend zijn.
Bereid latere bewerkingen voor
Sorteren maakt deelbereiken voorspelbaar en is vereist voor tijdgebaseerde schuivende vensters. Ontbrekende rijen zijn ook van belang als een berekening slaagt: shift(1) betekent één rij terug en rolling(7) betekent zeven rijen. Geen van beide controleert of elke rij één dag vertegenwoordigt. Bewaar bij een lange tabel ook de sleutel van de reeks, zoals sensor of winkel, zodat latere bewerkingen afzonderlijk per reeks kunnen worden uitgevoerd.
Belangrijkste punten
- Lees datums in voordat je de tijdindex instelt en sorteer de index.
- Controleer volgorde en uniciteit afzonderlijk.
- Verwerk dubbele labels volgens wat de bijbehorende rijen voorstellen.
- Vergelijk met een volledige kalender om afwezige datums te vinden.
2.2 Selecteer rijen op datum en tijdstip van de dag
Zodra de index gesorteerde datetime-waarden bevat, zijn datumtekenreeksen bruikbaar om te selecteren. Hun nauwkeurigheid bepaalt hoeveel tijd ze voorstellen: een jaar, een maand, een dag of een bepaalde minuut.
Selecteer een volledige kalenderperiode
Voor dagelijkse gegevens van januari tot en met maart 2025 selecteert ts.loc["2025"] alle 90 dagen. ts.loc["2025-02"] selecteert de 28 dagen van februari. Bij uurgegevens selecteert een dagtekenreeks de hele dag, niet alleen middernacht.
Gebruik ook op een DataFrame .loc:
february = df.loc["2025-02", "kwh"]
spring_onward = df.loc["2025-03-01":]
df["2025-02"] vraagt daarentegen om een kolom met die naam. Door de aanwezigheid van een tijdindex verandert kolomselectie met vierkante haken niet in rijselectie.
Lees het eindpunt nauwkeurig
Een deelbereik op basis van labels bevat beide grenspunten. ts.loc["2025-01-30":"2025-02-02"] bevat 30 en 31 januari en 1 en 2 februari. Een deelbereik op basis van posities zoals ts.iloc[0:4] stopt vóór positie 4.
Het einde van een deelbereik met een gedeeltelijke tekenreeks bevat de volledige genoemde periode. Bij uurgegevens bevat df.loc[:"2025-06-01"] heel 1 juni. df.loc[:"2025-06-01 00:00"] stopt om middernacht. Zo bevat een deelbereik dat eindigt op “2025-02” ook heel februari. Een nauwkeurigere tekenreeks verandert de grens, dus schrijf het afkappunt passend bij de vraag.
ts.truncate(before="2025-03-01") behoudt alles vanaf 1 maart. Het argument after= snijdt het andere einde af. Door eerst te sorteren voorkom je fouten die kunnen ontstaan als deelbereiken met datumtekenreeksen ongeordende labels tegenkomen.
Selecteer terugkerende kalendervoorwaarden
Kalenderattributen leveren booleaanse maskers op:
weekends = df[df.index.day_of_week >= 5]
evening_march = df[(df.index.month == 3) & (df.index.hour >= 18)]
Maandag is 0, dus zaterdag en zondag zijn 5 en 6. Elke voorwaarde heeft haakjes nodig als je ze met & of | combineert. Gebruik bij een datetime-kolom df["timestamp"].dt.day_of_week in plaats van een indexattribuut. Het weekdagmasker selecteert een herhaald kalenderpatroon; dat verschilt van de selectie van één aaneengesloten datumbereik.
Selecteer een tijdvenster op elke datum
df.between_time("09:00", "17:00") selecteert die uren op elke dag. Beide grenzen zijn standaard inbegrepen, wat op een volledige dag met uurgegevens negen rijen oplevert. inclusive="left" neemt 09.00 uur mee en sluit 17.00 uur uit, wat er acht oplevert. df.at_time("12:00") selecteert elke dag precies het middaguur.
Een tijdvenster kan over middernacht heen lopen. between_time("22:00", "06:00") selecteert rijen van de late avond en vroege ochtend in de hele index. Het selecteert geen ononderbroken interval tussen twee bepaalde datums. Bij een index met tijdzone gebruikt selectie met datumtekenreeksen de lokale tijdzone van de index; converteer de index voordat je een rapportagedag in een andere tijdzone selecteert.
Belangrijkste punten
- Een gedeeltelijke datumtekenreeks selecteert de volledige periode.
- Deelbereiken op basis van labels bevatten het eindpunt; deelbereiken op basis van posities sluiten de eindpositie uit.
- Gebruik
.locvoor selectie op datum in een DataFrame. - Kalendermaskers en tijdvensters selecteren terugkerende patronen.
- Controleer de nauwkeurigheid van het eindpunt en de tijdzone voordat je filtert.
2.3 Vergelijk waarden door de tijd met verschuivingen, verschillen en procentuele veranderingen
Voor een verandering heb je een duidelijk vergelijkingspunt nodig. “Vorig” kan de vorige waargenomen rij, de vorige kalenderdag of dezelfde maand een jaar geleden betekenen. Kies die betekenis voordat je een vertraagde waarde of groeipercentage berekent.
Plaats eerdere waarden naast huidige waarden
Voor bezoekersaantallen 200, 210 en 189 op 3 tot en met 5 maart geeft s.shift(1) de waarden NaN, 200 en 210. De methode verplaatst waarden één rij naar beneden en behoudt de labels. De nieuwe eerste plaats ontbreekt omdat er geen eerdere waarneming is. shift(-1) geeft 210, 189 en NaN: een vooruitgeschoven waarde die de volgende waarde naar de huidige rij brengt.
df["previous"] = df["visitors"].shift(1)
df["change"] = df["visitors"].diff()
df["growth"] = df["visitors"].pct_change()
diff() trekt de voorgaande waarde af en geeft NaN, 10 en −21. pct_change() deelt de huidige waarde door de vorige en trekt er 1 van af; dat geeft NaN, 0,05 en −0,10. Dit zijn verhoudingen: 0,05 betekent 5%, niet 0,05%. Uitvoer met drijvendekommagetallen kan kleine extra cijfers bevatten; rond na het berekenen af voor de weergave.
Kies de vertraging in rijen of in tijd
pct_change(7) vergelijkt met zeven rijen eerder. Dat is alleen dezelfde weekdag een week eerder als er precies één rij per dag is zonder hiaten. Bij een volledige maandelijkse reeks geeft pct_change(12) de verandering ten opzichte van een jaar eerder.
shift(1, freq="D") verschuift de tijdstempels één dag vooruit en laat de waarden aan die verschoven labels gekoppeld. Elke waarde blijft behouden. Berekeningen met het origineel worden daarna op datum uitgelijnd:
previous_day = s.shift(1, freq="D")
daily_change = s - previous_day
Als de bron alleen waarnemingen op maandag en donderdag heeft, vergelijkt een gewone shift(1) donderdag met maandag. Een datumverschuiving biedt een vergelijking met woensdag; als woensdag ontbreekt, ontbreekt de dagelijkse verandering voor donderdag. Dat hiaat opvullen is een afzonderlijke beslissing over de gegevens.
Houd rekening met uitlijning op labels bij berekeningen
Twee Series worden gecombineerd op tijdstempel, niet op rijpositie. Tel de waarden 200, 210 en 189 op 3, 4 en 5 maart op bij de waarden 1 en 1 op 4 en 7 maart. Alleen 4 maart heeft twee waarnemingen, dus de som is 211. De vereniging van datums is 3, 4, 5 en 7 maart; de overige resultaten ontbreken.
Gebruik s.add(other, fill_value=0) als een afwezige waarneming werkelijk nul betekent, zoals bij een gecontroleerde telling van gebeurtenissen. Het is geen algemene oplossing voor ontbrekende sensormetingen.
Begin vergelijkingen per reeks opnieuw
Sorteer een lange tabel op de sleutel van de reeks en op datum en bereken daarna binnen groepen. df.groupby("store")["sales"].pct_change() vergelijkt elke winkel alleen met zichzelf. Voor winkel A met verkopen van eerst 100 en dan 110 en winkel B met eerst 50 en dan 40 zijn de groeipercentages ontbrekend, 0,10, ontbrekend en −0,20. Een gewone berekening over de hele kolom zou de eerste verkoop van B vergelijken met de laatste verkoop van A. Dat numerieke resultaat zou een wisseling van winkel beschrijven, geen groei door de tijd.
Belangrijkste punten
- Een vertraagde waarde plaatst eerdere waarden naast latere waarden.
pct_change()geeft een verhouding; vermenigvuldig die met 100 om een percentage uit te drukken.- Verschuivingen van rijen en datums beantwoorden verschillende vragen.
- Berekeningen lijnen tijdstempels uit, geen posities.
- Bereken veranderingen afzonderlijk binnen elke reeks.
3Genereer datums en gebruik frequenties, verschuivingen en perioden
Kalenderregels maken herhaald werken met datums betrouwbaar. Genereer een volledig bereik op basis van een frequentie, verschuif naar het volgende maandeinde of de volgende werkdag en geef volledige maanden of kwartalen een label met perioden. Elke weergave beantwoordt een andere vraag: een tijdsduur telt verstreken tijd, een verschuiving volgt een kalenderregel en een periode duidt een tijdsinterval aan. Door kalenderpunten en grenspunten nauwkeurig te lezen, voorkom je fouten van één te veel of te weinig en verwarring over boekjaren.
3.1 Maak regelmatige datumreeksen met frequentiecodes
Een regelmatige datumreeks is een kalender die je kunt genereren in plaats van elk label te typen. Je kunt ermee testgegevens van labels voorzien, een verwacht rapportageraster definiëren of ontbrekende waarnemingen zichtbaar maken nadat je de index hebt aangepast.
Geef een begin en een regel op
ends = pd.date_range("2025-01-01", periods=4, freq="ME")
De vier tijdstempels zijn 31 januari, 28 februari, 31 maart en 30 april. “ME” betekent maandeinde, dus de eerste datum is het eerste maandeinde op of na het begin. Een regelmatige frequentie kan een kalenderregel volgen, ook als de verstreken tijd tussen de tijdstippen varieert.
Geef normaal twee van start, end en periods op, plus freq. Zonder expliciete frequentie is de standaard één kalenderdag. periods is een aantal tijdstempels, geen aantal tussenpozen: vier tijdstempels op uurbasis bevatten drie tussenpozen.
Lees veelgebruikte codes
| Regel | Code | Voorbeeld van gebruik |
|---|---|---|
| Kalenderdag of werkdag | D, B | Dagelijkse datums of datums van maandag tot en met vrijdag |
| Week op een vaste weekdag | W, W-MON | Zondagen of maandagen |
| Maandgrens | MS, ME | Eerste of laatste kalenderdag |
| Kwartaalgrens | QS, QE | Begin of einde van een kwartaal |
| Jaargrens | YS, YE | Begin of einde van een jaar |
| Vast tijdsinterval | h, min, s, ms | Uren tot en met milliseconden |
Veelvouden drukken grotere intervallen uit: “15min”, “2h” en “90min”. Als je om 08.00 uur begint met vier perioden van “90min”, krijg je 08.00, 09.30, 11.00 en 12.30 uur. “1h30min” drukt dezelfde tussenpoos uit.
Frequenties voor tijdstempels gebruiken in pandas 3 “ME”, “QE”, “YE”, “BME”, “h”, “min”, “s”, “ms” en “us”. De oudere codes “M”, “Q”, “Y” of “A”, “BM”, “H”, “T”, “S”, “L” en “U” werken niet meer in deze bewerkingen met tijdstempels. Maandperioden gebruiken nog steeds “M”, omdat een periode een tijdsinterval beschrijft.
Volg kalenderpunten en werkdagen
Een kalendergebonden reeks neemt het opgegeven begin niet per se op in de uitvoer. Als je op 15 januari 2025 begint met freq="MS", krijg je eerst 1 februari. In januari 2025 geeft “W-MON” de datums 6, 13, 20 en 27 januari; “W” geeft zondagen. “WOM-3FRI” betekent de derde vrijdag van elke maand.
“B” slaat weekenden over, maar kent geen lokale feestdagen. Maart 2025 bevat 21 datums van maandag tot en met vrijdag. Een aangepaste kalender kan een opgegeven feestdag uitsluiten:
pd.bdate_range("2025-03-01", "2025-03-31",
freq="C", holidays=["2025-03-17"])
Die reeks bevat 20 datums. De lijst met feestdagen is expliciet; een land wordt niet afgeleid uit een tijdzone of taal.
Tel grenspunten zorgvuldig
Begin- en eindpunten die op de frequentie vallen, zijn standaard inbegrepen. Elk uur van 1 januari om middernacht tot en met 2 januari om middernacht geeft 25 tijdstempels. Gebruik periods=24 voor precies 24 metingen per uur of inclusive="left" om het eindpunt uit te sluiten. normalize=True stelt de begin- en eindtijd opnieuw in op middernacht. Voeg tz="Asia/Tokyo" toe als de gegenereerde labels een tijdzone moeten bevatten.
Belangrijkste punten
- Frequentiecodes drukken tijdsintervallen of vaste kalenderpunten uit.
- Een kalendergebonden reeks begint op de eerste datum die aan de regel voldoet.
- Voor werkdagreeksen moet je feestdagen expliciet opgeven.
- Tel tijdstempels en bepaal afzonderlijk of grenspunten zijn inbegrepen.
- Gebruik de huidige codes van pandas 3 voor frequenties van tijdstempels.
3.2 Verschuif datums volgens kalenderregels
“Een maand later” is een kalenderinstructie. “Dertig dagen later” is verstreken tijd. De resultaten kunnen verschillen omdat niet alle maanden en jaren evenveel dagen bevatten.
Onderscheid tijdsduur van kalenderverschuiving
Een Timedelta telt een vaste hoeveelheid verstreken tijd op. Een DateOffset volgt kalendervelden. Vanaf 31 januari 2025:
t = pd.Timestamp("2025-01-31")
t + pd.DateOffset(months=1) # February 28
t + pd.Timedelta(days=30) # March 2
Voor de DateOffset ga je eerst naar februari en behoud je daarna dag 31 als die bestaat. Die bestaat niet, dus pandas begrenst de datum tot de laatste geldige dag van februari. Vanaf 31 januari 2024 is het resultaat 29 februari, omdat het een schrikkeljaar is. pd.Timedelta(months=1) is ongeldig: een maand heeft geen vaste tijdsduur.
Hetzelfde onderscheid geldt voor jaren. Vanaf 1 januari 2024 eindigen 365 verstreken dagen op 31 december 2024. pd.DateOffset(years=1) eindigt op 1 januari 2025. Gebruik de eenheid die de eigenlijke vraag noemt in plaats van een handig aantal dagen te nemen.
Verschuif naar een kalenderpunt
pd.offsets.MonthEnd(1) verschuift naar het volgende maandeinde. Vanaf 15 januari 2025 geeft dit 31 januari. Vanaf 31 januari geeft het 28 februari. Het aantal één betekent dat je naar een volgend kalenderpunt gaat, dus ook een datum die al op een maandeinde valt, verschuift.
MonthEnd(0) verschuift een datum vooruit naar het einde van de huidige maand, maar laat een bestaand maandeinde ongewijzigd. Dit is handig om elke waarneming het einde van de maand als label te geven:
month_labels = df.index + pd.offsets.MonthEnd(0)
Een verschuiving heeft ook rollforward() en rollback(). Voor 15 januari is het dichtstbijzijnde maandeinde vooruit 31 januari en achteruit 31 december 2024. Deze bewerkingen selecteren het dichtstbijzijnde geldige kalenderpunt in een richting.
Verschuif via werkdagen
14 maart 2025 is een vrijdag. Als je pd.offsets.BDay(1) optelt, krijg je maandag 17 maart. Als je één verstreken dag optelt, krijg je zaterdag 15 maart. Een standaardwerkdagregel slaat weekenden over; voor feestdagen moet je expliciet een aangepaste kalender opgeven.
Frequentietekenreeksen zijn korte namen voor verschuivingsobjecten: “ME” komt overeen met MonthEnd, “B” met BusinessDay en “W-MON” met een week die aan maandag is gekoppeld. Zo kan dezelfde kalenderbetekenis een reeks, resamplingregel of datumverschuiving bepalen.
Behoud het bedoelde tijdstip bij de overgang naar of van zomertijd
In pandas 3 betekent pd.offsets.Day(1) één kalenderdag en blijft het lokale tijdstip gelijk. pd.Timedelta(days=1) telt precies 24 uur op. Vanaf het middaguur op 29 maart 2025 in Amsterdam eindigt de kalenderverschuiving op 30 maart om het middaguur, na slechts 23 verstreken uren. De Timedelta eindigt om 13.00 uur. Een terugkerende lokale afspraak en een gemeten bedrijfstijd van apparatuur vereisen daarom verschillende bewerkingen.
Belangrijkste punten
- Maanden en jaren zijn kalenderregels, geen vaste tijdsduren.
- Een maandverschuiving begrenst de datum tot de laatste geldige dag van de doelmaand.
MonthEnd(1)verschuift een bestaand maandeinde vooruit;MonthEnd(0)behoudt het.- Verschuivingen op basis van werkdagen slaan weekenden over.
- Een kalenderdag en 24 verstreken uren kunnen verschillen.
3.3 Werk met volledige maanden, kwartalen en boekjaren als perioden
Een maandelijks verkooptotaal hoort bij een volledige maand. Je kunt het één tijdstempel als label geven, maar een periode (Period) vermeldt het tijdsinterval direct. Een periode combineert een waarde met een frequentie, dus “2025-03” met frequentie “M” betekent heel maart 2025.
Geef tijdsintervallen weer en verschuif ze
march = pd.Period("2025-03", freq="M")
months = pd.period_range("2025-01", "2025-04", freq="M")
months is een PeriodIndex met vier elementen en datatype period[M]. De start_time van maart is 1 maart om middernacht; de end_time is 31 maart om 23:59:59.999999 bij microseconderesolutie. Het einde is het laatste moment, niet middernacht aan het begin van de laatste dag.
Rekenen met perioden gaat in de eigen eenheid van de periode. march + 1 is april 2025. Juni min maart bij maandfrequentie geeft een verschuiving van drie maandeinden, waarvan .n gelijk is aan 3. Een maandperiode kent ook .days_in_month: februari 2025 heeft 28 dagen.
Converteer tijdstippen naar perioden en terug
monthly_labels = df.index.to_period("M")
column_labels = df["date"].dt.to_period("M")
start_labels = monthly_labels.to_timestamp()
end_labels = monthly_labels.to_timestamp(how="end")
Elk tijdstempel in maart wordt aan dezelfde maandperiode gekoppeld. Als je die periode terugconverteert, krijg je standaard het begin of, als je daarom vraagt, het einde. Hiermee krijg je de oorspronkelijke dag en kloktijd van een waarneming niet terug: die details zijn bij de conversie naar een periode verloren gegaan.
Houd de groepen frequentiecodes apart. Een maandinterval gebruikt “M” in Period en period_range. Een tijdstempel voor een maandeinde gebruikt “ME” in date_range en bij datetime-resampling. De twee namen beschrijven verschillende soorten labels.
Verander de frequentie van een periode
De methode .asfreq() van een periode selecteert een omvattende of omvatte periode met een andere frequentie. march.asfreq("D", how="start") geeft 1 maart als dagperiode; how="end" geeft 31 maart. Een jaarperiode die met how="start" naar “M” wordt geconverteerd, geeft januari.
Hiermee selecteer je een grensperiode; een maandtotaal wordt niet over dagen verdeeld. Voor een reeks met een PeriodIndex kun je met resampling maandperioden aggregeren tot kwartaalperioden. De aantallen dagen in elke maand van 2025 tellen op tot kwartaaltotalen van 90, 91, 92 en 92.
Lees labels van kwartalen van een boekjaar
Een kwartaal van een boekjaar krijgt een naam binnen een boekjaar waarvan de eindmaand expliciet is. Met “Q-JUN” eindigt boekjaar 2025 in juni 2025. Het eerste kwartaal loopt daarom van juli tot en met september 2024:
q = pd.Period("2025Q1", freq="Q-JUN")
Met “Q-MAR” valt 10 mei 2025 in 2026Q1, omdat dat boekjaar in maart 2026 eindigt. Het jaar in een boekjaarlabel hoeft niet overeen te komen met het kalenderjaar van de eerste dag. Bij filters op tijdstempels is het vaak duidelijker om tijdstippen vóór het begin van de volgende periode te selecteren dan de laatste fractie van een seconde van de huidige periode te construeren.
Belangrijkste punten
- Perioden beschrijven tijdsintervallen en verschuiven in hun eigen frequentie-eenheid.
- Bij conversie naar een periode gaan nauwkeurigere details van tijdstempels verloren.
- Frequentiecodes voor perioden en tijdstempels verschillen.
- Boekjaren krijgen het jaar waarin ze eindigen als label.
4Wijzig de frequentie van een tijdreeks met resampling
Als je de frequentie verandert, verandert ook de vraag die je aan de waarnemingen stelt. Gedetailleerde metingen kunnen dagtotalen of maandgemiddelden worden; een reeks met weinig waarnemingen kan een fijner raster met lege plaatsen worden. Kies aggregaties en opvulmethoden op basis van de betekenis van de waarden en controleer daarna de grenzen van de tijdsintervallen. Als een tabel meerdere winkels of sensoren bevat, behoud je hun identiteit in de groepering zodat de resulterende reeksen apart blijven.
4.1 Verlaag de frequentie met totalen, gemiddelden en andere samenvattingen
Resampling beantwoordt vragen zoals “Hoeveel energie is er per dag gebruikt?” of “Wat was de gemiddelde temperatuur per maand?” Het groepeert waarnemingen in tijdsintervallen en past daarna een aggregatie toe.
Kies een statistiek die bij de grootheid past
daily = df.resample("D").agg({"kwh": "sum", "temp_c": "mean"})
Energie in kWh en neerslag in mm tellen op in de tijd. Temperatuur is een niveau, dus een gemiddelde beschrijft die bruikbaarder dan een som. last() past bij een eindsaldo, terwijl max() een piek vindt. Dagelijkse verkopen kun je optellen voor de totale maandverkopen of middelen voor de gemiddelde verkopen per waargenomen dag; de vraag bepaalt de keuze.
resample() geeft een Resampler terug totdat je een aggregatie zoals sum(), mean(), count() of agg() aanroept. Gebruik on="date" als de datetime-waarden in een kolom staan in plaats van in de index.
Lees kalenderintervallen en gedeeltelijke dekking
Een dagelijkse reeks met enen van 1 januari tot en met 30 april 2025 geeft maandtotalen 31, 28, 31 en 30 met resample("ME").sum(). “MS” geeft dezelfde maandtotalen met het begin van de maand als label. Resampling naar kwartaaleinden geeft 90 voor januari tot en met maart en 30 voor een tweede kwartaal dat alleen april bevat. Een label van 30 juni bewijst niet dat mei en juni zijn waargenomen.
Weekintervallen met “W” eindigen op zondag. Dagelijkse waarden 1 tot en met 14 vanaf maandag 3 maart tellen op tot 28 voor de week met label 9 maart en 77 voor de week met label 16 maart. “W-MON” eindigt op maandag; het eerste interval bevat dan alleen 3 maart. Controleer de vaste weekdag voordat je een label als het begin van een week opvat.
Onderscheid wat bij een interval hoort van het label
closed bepaalt welke grens bij een interval hoort. label bepaalt welk tijdstempel bij het resultaat wordt afgedrukt. Voor de meeste regels, waaronder “5min”, “h”, “D” en “MS”, staan beide standaard op “left”.
Waarden 0 tot en met 9, één per minuut vanaf 00.00 uur, leveren standaard twee sommen per vijf minuten op: 10 met label 00.00 uur en 35 met label 00.05 uur. Het eerste interval bevat 00.00 tot en met 00.04 uur. Met closed="right", label="right" zijn de resultaten 0 om 00.00 uur, 15 om 00.05 uur en 30 om 00.10 uur. Het middelste interval bevat 00.01 tot en met 00.05 uur. Alleen het label wijzigen zou niet veranderen welke waarden erbij horen.
Eindregels zoals “ME”, “QE”, “YE”, “W” en “BME” zijn standaard rechts gesloten en hebben rechts een label. Intervallen met een vaste lengte worden normaal uitgelijnd vanaf middernacht van de eerste dag, dus grenzen van 15-minutenintervallen zijn 00.00, 00.15 uur enzovoort.
Onderscheid lege intervallen van echte nullen
De sum() van een lege dag is 0, count() is 0 en mean() is NaN. Gebruik sum(min_count=1) om een ontbrekende waarde te behouden als er geen meting beschikbaar is. Een vastgelegde nul en een afwezige meting blijven dan te onderscheiden.
Voor meerdere samenvattingen van één reeks geeft .ohlc() de openings-, hoogste, laagste en slotwaarde: de eerste, maximale, minimale en laatste waargenomen waarde in elk interval. Metingen 10, 12 en 11 geven opening 10, hoogste 12, laagste 10 en slot 11. Opening en slot hangen af van de tijdsvolgorde, niet van de grootte van de getallen.
Belangrijkste punten
- Kies aggregaties op basis van de betekenis van de waarden.
closedbepaalt wat bij een interval hoort;labelbepaalt de weergegeven tijd.- Weeklabels noemen normaal de einddag van de week.
- Controleer gedeeltelijke eerste en laatste intervallen.
sum(min_count=1)behoudt lege intervallen als ontbrekende waarden.- OHLC betekent eerste, maximale, minimale en laatste waarde.
4.2 Verhoog de frequentie van een tijdreeks en vul ontbrekende waarden aan
Een fijner raster maakt plaatsen, geen metingen. Bepaal voordat je ze vult of elke waarde een toestand, een telling, een geleidelijk veranderende meting of een totaal over een tijdsinterval voorstelt.
Maak de nieuwe plaatsen zichtbaar
s = pd.Series([10.0, 16.0],
index=pd.to_datetime(["2025-06-01", "2025-06-04"]))
daily = s.asfreq("D")
Het dagelijkse resultaat is 10, NaN, NaN, 16. s.resample("D").asfreq() geeft hier hetzelfde raster. Waarden blijven op overeenkomende tijdstempels staan; de nieuwe datums bevatten geen oorspronkelijke waarneming.
Vul aan volgens de betekenis
| Methode | Resultaat op 1 tot en met 4 juni | Passende betekenis |
|---|---|---|
ffill() | 10, 10, 10, 16 | Een toestand blijft gelden totdat die verandert |
bfill() | 10, 16, 16, 16 | Een latere waarde wordt voor eerdere plaatsen gebruikt |
interpolate() | 10, 12, 14, 16 | Verandering wordt langs een rechte lijn geschat |
Een thermostaatinstelling blijft gelden totdat iemand die verandert, dus voorwaarts opvullen is nuttig. Een geleidelijk veranderende waterstand kan interpolatie rechtvaardigen. Nul past alleen bij een telling van gebeurtenissen als het ontbrekende record betekent dat er geen gebeurtenis was. Een sensorstoring bewijst niet dat de meting nul was.
Het interpolatievoorbeeld gebruikt een regelmatig dagelijks raster. De totale verandering is 6 over drie stappen van één dag, dus elke stap telt er 2 bij op. De twee tussenliggende waarden zijn schattingen, geen teruggevonden metingen.
Achterwaarts opvullen gebruikt informatie uit de toekomst. Daarmee kun je niet beschrijven wat een waarnemer op elk eerder moment wist. Voorwaarts opvullen respecteert die tijdsrichting, maar bij lange hiaten kan een doorgegeven toestand toch verouderd raken. daily.ffill(limit=1) vult één plaats na een meting en geeft in dit voorbeeld 10, 10, NaN, 16.
Gebruik expliciete rapportagegrenzen
asfreq("D") loopt van het eerste tot en met het laatste brontijdstempel. Pas de index aan als de kalender verder moet reiken:
calendar = pd.date_range("2025-06-01", "2025-06-05", freq="D")
complete = s.reindex(calendar)
Ook 5 juni is nu zichtbaar. fill_value=0 vult bij het aanpassen van de index nieuw aangemaakte labels, wat nuttig is voor dagen waarop aantoonbaar geen gebeurtenissen plaatsvonden. Het vervangt geen ontbrekende waarden die al in de bron bestonden. Zowel het aanpassen van de index als asfreq() vereist unieke bronlabels.
Houd steekproefsgewijze selectie en aggregatie apart
asfreq() selecteert waarden op doeltijdstempels. Het vat de waarnemingen daartussen niet samen. Bij 48 uurwaarden genummerd van 0 tot en met 47 selecteert asfreq("D") de middernachtmetingen 0 en 24. resample("D").sum() geeft daarentegen 276 en 852 door alle uurwaarden van elke dag op te tellen.
Je kunt een maandtotaal niet voorwaarts opvullen naar elke dag en daarna optellen: dan zou je hetzelfde totaal herhaaldelijk tellen. Een gelijke toedeling per dag vereist dat je deelt door het aantal dagen van de maand. Dat is een aanname over de toedeling, anders dan een toestand doorgeven of een geleidelijk veranderende meting schatten.
Belangrijkste punten
- Een fijner raster voegt lege plaatsen toe, geen waarnemingen.
- Kies de opvulmethode op basis van de betekenis van de grootheid en de tijdsrichting.
- Beperk het opvullen als lange hiaten zichtbaar moeten blijven.
asfreq()selecteert punten; resampling met aggregatie vat intervallen samen.
4.3 Pas resampling via groepen op meerdere tijdreeksen tegelijk toe
Een lange tabel kan veel reeksen in één waardekolom bevatten. Een winkelsleutel onderscheidt winkels en een sensorsleutel onderscheidt sensoren. Groepeer zowel op die identiteit als op tijd als de vraag om een afzonderlijke geschiedenis voor elke reeks vraagt.
Combineer een reekssleutel met een tijdregel
monthly = df.groupby([
"store", pd.Grouper(key="date", freq="ME")
])["sales"].sum()
pd.Grouper plaatst een regel voor tijdsintervallen binnen groupby. key= noemt een datetime-kolom; level= kan een datetime-indexniveau noemen. Het resultaat heeft één indexniveau voor winkel en één voor maandeinde. Door de numerieke kolom te selecteren, blijft de aggregatie gericht op verkopen.
Stel dat winkel A voor 100 verkoopt op 5 januari, 150 op 20 januari en 120 op 3 februari. Winkel B verkoopt voor 80 op 11 januari, 90 op 14 februari en 60 op 25 februari. Het gegroepeerde resultaat is A: januari 250, februari 120; B: januari 80, februari 150. Resampling op de hele tabel zonder de winkelsleutel zou de winkels combineren tot 330 in januari en 270 in februari.
Pas resampling toe binnen elke groep
Een tweede vorm maakt eerst van de datum de index:
monthly = (df.set_index("date")
.groupby("store")["sales"]
.resample("ME").sum())
Dit levert dezelfde totalen op voor waargenomen combinaties van winkel en maand. De twee vormen verschillen wanneer een winkel in een tussenliggende maand geen rijen heeft. Als A alleen in januari en maart voorkomt, maakt resampling per groep een februari-interval tussen de eerste en laatste datum van A; de gewone sum() geeft daar nul. Groeperen op winkel en een Grouper behoudt de combinaties die rijen bevatten, dus de combinatie van A en februari ontbreekt.
Een afwezige combinatie, een leeg interval dat als nul is samengevat en een ontbrekende meting zijn verschillende gegevenstoestanden. Bepaal welke het rapport moet tonen. Pas de index expliciet aan als elke winkel een kalender moet delen die ruimer is dan het waargenomen bereik. Gebruik min_count=1 bij een som als een leeg interval ontbrekend moet blijven.
Herstructureer om te vergelijken
monthly.unstack("store") verplaatst het winkelniveau naar kolommen en laat maanden in rijen staan. In het voorbeeld heeft januari A = 250 en B = 80; februari heeft A = 120 en B = 150. Een ontbrekende combinatie van winkel en maand wordt NaN; unstack("store", fill_value=0) vervangt ontbrekende combinaties door nul als die betekenis passend is.
Houd jaren apart wanneer dat nodig is
Een tijdgroepering met Grouper op “ME” houdt januari 2024 en januari 2025 apart. Groeperen op df["date"].dt.month behoudt alleen maandnummers en voegt beide januarimaanden samen. De eerste vorm beantwoordt “Wat gebeurde er elke maand?” De tweede ondersteunt een seizoensvergelijking zoals de gemiddelde verkopen in januari over meerdere jaren. De keuze hangt af van welke tijdsidentiteit je moet behouden.
Belangrijkste punten
- Groepeer op reeksidentiteit en tijd om afzonderlijke geschiedenissen te behouden.
- Resampling per groep en een tijdgroepering met Grouper verschillen bij lege maanden.
- Met
unstack()kun je reeksen gemakkelijk in kolommen vergelijken. - Maandnummers combineren jaren; maandelijkse tijdsintervallen houden ze apart.
5Vlak gegevens af en vat ze samen met schuivende en uitbreidende vensters
Vensterstatistieken beschrijven hoe een reeks verandert zonder die tot één totaalgetal terug te brengen. Een schuivende berekening volgt recente rijen of recente verstreken tijd, een uitbreidende berekening behoudt de geschiedenis en een exponentieel gewogen gemiddelde geeft geleidelijk meer gewicht aan nieuwere waarnemingen. Ga na welke waarden in elk resultaat terechtkomen, hoe ontbrekende gegevens het beïnvloeden en waar het resultaat zijn label krijgt. Deze keuzes bepalen wat een afgevlakte waarde je kan vertellen.
5.1 Bereken voortschrijdende statistieken over een vast aantal rijen
Een schuivend venster vat herhaaldelijk een verschuivende groep rijen samen. Bij elke nieuwe rij krijgt het venster de huidige waarde erbij en valt uiteindelijk de oudste waarde weg. De vensterlengte bepaalt hoeveel variatie op korte termijn wordt afgevlakt.
Bekijk één venster tegelijk
Voor de waarden 4, 8, 6, 10 en 12:
s = pd.Series([4, 8, 6, 10, 12])
s.rolling(3).mean()
Het eerste volledige venster is [4, 8, 6], met een totaal van 18 en een gemiddelde van 6. Het volgende is [8, 6, 10], met een gemiddelde van 8. Het laatste is [6, 10, 12], met een gemiddelde van ongeveer 9,333. De standaardresultaten zijn NaN, NaN, 6, 8 en 9,333, omdat de eerste twee rijen nog geen drie waarnemingen hebben.
Bepaal de gegevenseisen en plaatsing
min_periods bepaalt het vereiste aantal aanwezige waarden. Voor een venster op basis van een aantal rijen is dat standaard de volledige venstergrootte. Met min_periods=1 gebruiken de eerste gemiddelden eerst één waarde en dan twee: 4 en 6. Door hun kleinere aantallen zijn ze minder stabiel dan de latere gemiddelden van drie waarden.
Ontbrekende waarden nemen nog steeds rijposities in. In [4, NaN, 6, 10, 12] heeft een venster van drie rijen dat de ontbrekende waarde bevat slechts twee geldige waarnemingen. min_periods=2 staat het gemiddelde van [4, NaN, 6] toe, namelijk 5; de standaardinstelling niet.
Resultaten horen normaal bij de laatste rij van het venster. Met center=True verschijnen dezelfde drie gemiddelden van volledige vensters bij de middelste rijen, met NaN, 6, 8, 9,333, NaN als resultaat. Een gecentreerde waarde gebruikt waarnemingen die later zijn dan het label. Gebruik achterwaarts gerichte vensters om te beschrijven wat op elk moment bekend was.
Vat meer samen dan het gemiddelde
Dezelfde vensters ondersteunen sum(), max(), min() en std(). pandas gebruikt standaard de steekproefstandaardafwijking: [4, 8, 6] heeft standaardafwijking 2. Een eigen functie kan een spreidingsbreedte berekenen:
s.rolling(3).apply(lambda v: v.max() - v.min(), raw=True)
De spreidingsbreedtes van de volledige vensters zijn 4, 4 en 6. raw=True geeft arraywaarden door aan de functie. Twee uitgelijnde reeksen kunnen ook een venster delen: a.rolling(3).corr(b) meet de correlatie over de laatste drie gepaarde waarnemingen, zodat het verband door de tijd kan variëren.
Kies een zinvolle lengte en groepering
Met één volledige dagelijkse rij per dag bevat een gemiddelde over zeven rijen elke weekdag eenmaal en middelt het een vaste terugkerende weekdagcomponent uit. Een gemiddelde over twaalf rijen doet hetzelfde voor een vaste jaarcomponent bij volledige maandelijkse gegevens. Langere vensters vlakken meer af, maar reageren later op keerpunten; een achterwaarts gericht gemiddelde over n rijen heeft ongeveer een half venster vertraging, circa (n − 1) / 2 rijen.
Rijen zijn geen dagen. Zeven metingen met hiaten kunnen meer dan een week beslaan. Gebruik een tijdvenster als de vraag verstreken tijd noemt. Sorteer in een lange tabel elke reeks op tijd en pas vensters toe binnen de groep: df.groupby("store")["sales"].rolling(2).sum(). Zo voorkom je dat een venster van de gegevens van de ene winkel naar die van een andere loopt.
Belangrijkste punten
- Een venster op basis van rijen telt rijen, inclusief posities met ontbrekende waarden.
min_periodstelt geldige waarnemingen.- Gecentreerde vensters bevatten waarden die later zijn dan hun labels.
- Langere vensters vlakken meer af en reageren langzamer.
- Pas vensters afzonderlijk toe binnen elke reeks.
- Schuivende methoden kunnen zowel spreiding en verbanden als niveaus samenvatten.
5.2 Gebruik tijdgebaseerde vensters voor onregelmatige gegevens
Onregelmatige gebeurtenissen vragen om vensters die in tijd zijn gedefinieerd. “Bestellingen in de afgelopen drie dagen” moet dezelfde tijdsduur behouden, ook als er op de ene dag veel bestellingen zijn en de volgende dag geen.
Definieer een venster op basis van verstreken tijd
s = pd.Series([5, 3, 4, 6], index=pd.to_datetime([
"2025-05-01", "2025-05-02", "2025-05-05", "2025-05-06"
]))
s.rolling("3D").sum()
De resultaten zijn 5, 8, 4 en 10. Anders dan rolling(3) definieert de tekenreeks “3D” een interval van drie dagen. Het aantal rijen binnen dat interval kan variëren. Sorteer eerst de DatetimeIndex; tijdvensters vereisen een monotoon stijgende volgorde van tijdstippen. Een DataFrame kan een gesorteerde datetime-kolom gebruiken met on="date".
Controleer de grens voordat je optelt
Standaard bevat het venster de huidige tijd en sluit het het moment precies drie dagen eerder uit. Op 5 mei om middernacht loopt het interval van net na 2 mei om middernacht tot en met 5 mei om middernacht. De meting van 2 mei ligt precies op de uitgesloten grens, dus alleen de waarde 4 van 5 mei draagt bij.
Op 6 mei begint het venster net na 3 mei en bevat het de waarden 4 en 6, samen 10. Met closed="both" bevat het venster van 5 mei ook 2 mei en is het totaal 7. Een keuze voor de grens kan een resultaat veranderen, ook als de gegevens en de tijdsduur gelijk blijven.
Een venster van twee rijen op deze reeks geeft NaN, 8, 7 en 10. Op 5 mei bevat het de vorige rij van 2 mei. Dat beantwoordt “de laatste twee metingen”, een andere vraag dan “de laatste drie dagen”.
Stel een minimum aan waarnemingen in
Voor een tijdvenster is min_periods standaard 1. De eerste waarneming kan daarom direct een resultaat opleveren. s.rolling("3D").count() geeft 1, 2, 1 en 2 metingen en maakt zo zichtbaar op hoeveel metingen het resultaat telkens berust. Een gemiddelde op basis van één meting en een gemiddelde op basis van veel metingen zijn allebei geldige berekeningen, maar berusten op verschillende aantallen gegevens.
Met min_periods=2 zijn de sommen NaN, 8, NaN, 10. De tijdsduur is niet veranderd; de berekening vereist nu minstens twee aanwezige waarnemingen binnen die tijdsduur. Een ruimer tijdsinterval garandeert op zichzelf niet meer waarnemingen.
Gebruik vaste lengtes en afzonderlijke reeksen
Een tijdgebaseerd schuivend venster vereist een vaste tijdsduur zoals “30min”, “24h” of “7D”. Een maandeinderegel zoals “1ME” heeft een variabele lengte en kan dit soort schuivend venster niet definiëren. Gebruik een opgegeven vaste lengte zoals “30D” als dat de bedoelde regel is, of aggregeer eerst in maandintervallen als de vraag over kalendermaanden gaat.
Voor afzonderlijke klantgeschiedenissen houdt df.groupby("customer").rolling("30D", on="date")["amount"].sum() de transacties van elke klant bij elkaar. De tijdstippen moeten binnen elke klant geordend zijn. Het resultaat voegt de groepssleutel toe als indexniveau, zodat behouden blijft welke reeks elk venster beschrijft.
Belangrijkste punten
- Tijdvensters selecteren op tijdsduur en kunnen verschillende aantallen rijen bevatten.
- De linkergrens is standaard uitgesloten en de huidige tijd is inbegrepen.
- Voor een tijdvenster is
min_periodsstandaard 1. - Kalendermaanden kunnen niet dienen als vaste duur voor schuivende vensters.
5.3 Houd cumulatieve totalen, cumulatieve maxima en exponentieel gewogen gemiddelden bij
Sommige vragen vereisen de volledige geschiedenis: “Hoeveel is er opgeteld?” of “Wat is de hoogste waarde tot nu toe?” Andere moeten recente waarnemingen zwaarder laten wegen zonder het verleden abrupt weg te laten. Uitbreidende en exponentieel gewogen berekeningen dienen deze verschillende doelen.
Laat de geschiedenis telkens met één rij groeien
Voor de waarden 4, 8, 6, 10 en 12 geeft s.expanding().mean() de waarden 4, 6, 6, 7 en 8. Het vierde resultaat gebruikt alle vier de waarden: hun totaal is 28 en hun gemiddelde is 7. expanding().sum() geeft 4, 12, 18, 28 en 40, hetzelfde als cumsum() op deze volledige reeks. expanding().max() geeft 4, 8, 8, 10 en 12, hetzelfde als cummax().
Uitbreidende vensters vereisen standaard één waarneming. Ze behouden elke eerdere waarneming met gelijk gewicht. Later in een lange reeks draagt een nieuwe waarde slechts een klein deel bij aan de volledige geschiedenis, dus reageert een cumulatief gemiddelde langzaam.
Cumulatieve totalen kunnen bij een grens opnieuw beginnen:
ytd = df.groupby(df.index.year)["sales"].cumsum()
by_store = df.groupby("store")["sales"].cumsum()
Sorteer binnen de betreffende geschiedenis voordat je cumulatief optelt. Een gewone cumulatieve som over door elkaar staande winkels mengt ze.
Meet de afstand onder een cumulatief maximum
Voor 100, 120, 90, 110 en 130 geeft cummax() de waarden 100, 120, 120, 120 en 130. Bereken de relatieve daling vanaf het cumulatieve maximum met s / s.cummax() - 1. Bij 90 is de referentie het eerdere maximum van 120, dus de relatieve daling is −0,25, oftewel 25% onder het maximum. Als je 90 met de eerste waarde 100 vergelijkt, beantwoord je een andere vraag. Bij een nieuw maximum is de relatieve daling nul.
Geef recente waarden meer gewicht
Een exponentieel gewogen voortschrijdend gemiddelde, of EWMA, vermindert het gewicht van oudere waarden met een constante factor. De afvlakkingsfactor volgt uit , dus span=3 geeft 0,5. Voor adjust=False is de bijwerking:
Hier is de nieuwe waarneming, de vorige afgevlakte waarde en het bijgewerkte resultaat. De eerste afgevlakte waarde is gelijk aan de eerste waarneming. Daarna krijgt elke nieuwe waarde gewicht 0,5 en de vorige afgevlakte waarde gewicht 0,5:
s.ewm(span=3, adjust=False).mean()
Voor 4, 8, 6, 10 en 12 zijn de resultaten 4, 6, 6, 8 en 10. De laatste bijwerking neemt het gemiddelde van de nieuwe waarneming 12 en de vorige afgevlakte waarde 8. Ze neemt niet alleen het gemiddelde van de twee meest recente ruwe waarnemingen.
Lees de instelling voor de correctie
De standaardinstelling adjust=True normaliseert met de som van de beschikbare gewichten. Voor dezelfde gegevens zijn de eerste resultaten 4, ongeveer 6,667, 6,286, 8,267 en 10,194. Dit is een andere berekening voor de beginfase dan de recursieve vorm; het verschil neemt af naarmate meer geschiedenis beschikbaar komt.
Kies één argument voor de afname: span, alpha, com of halflife. Een EWMA heeft geen harde grens waar een oude rij plotseling verdwijnt. Een voortschrijdend gemiddelde heeft die grens wel, terwijl een uitbreidend gemiddelde alle eerdere waarden even zwaar laat meewegen. Kies op basis van hoeveel invloed recente veranderingen moeten hebben.
Belangrijkste punten
- Uitbreidende vensters gebruiken de volledige geschiedenis tot en met elke rij.
- Groepeer cumulatieve berekeningen als geschiedenissen opnieuw moeten beginnen.
- De relatieve daling vanaf het cumulatieve maximum vergelijkt een waarde met dat maximum.
- EWMA-gewichten nemen geleidelijk af naarmate waarden ouder worden.
adjust=Falsegebruikt de vorige afgevlakte waarde bij de recursieve bijwerking.- De standaardcorrectie verandert de eerste gewogen gemiddelden.
6Verwerk tijdzones en zomertijd
Een lokale kloktijd duidt alleen een moment aan als de tijdzone bekend is. Ken de tijdzone van vastlegging toe, converteer werkelijke momenten tussen tijdzones en houd berekeningen uitgelijnd in UTC. Lokale rapportages hebben vervolgens de juiste kalendergrenzen nodig, inclusief de uren die bij de overgang naar of van zomertijd worden overgeslagen of herhaald. Door tijdzonetoewijzing en conversie te onderscheiden, kun je records van meerdere locaties combineren zonder hun betekenis ongemerkt te verschuiven.
6.1 Ken tijdzones toe aan tijdstempels en converteer tussen tijdzones
Een kloktijd heeft een locatie nodig om een moment aan te duiden. “2025-07-01 09:00” is een tijdstempel zonder tijdzone. Als je “Europe/Amsterdam” toevoegt, krijgt het een tijdzone: in juli heeft het tijdsverschil +02:00 en stelt het 07.00 uur UTC voor. UTC is de gemeenschappelijke tijdreferentie en kent geen klokverzetting voor zomertijd.
Ken de tijdzone van vastlegging toe
local = pd.Timestamp("2025-07-01 09:00")
aware = local.tz_localize("Europe/Amsterdam")
tz_localize() behoudt 09.00 uur en kent daaraan de betekenis van de tijdzone toe. Gebruik de locatie waar de kloktijd is vastgelegd. Als je dezelfde tijd UTC zou noemen, zou je een ander moment beschrijven, in dit voorbeeld twee uur later.
Gebruik IANA-namen zoals “Europe/Amsterdam”, “America/New_York” en “Asia/Kolkata”. Benoemde regionale tijdzones behouden historische regels voor tijdsverschillen en zomertijd. Een vast tijdsverschil van +01:00 doet dat niet. Korte namen zijn niet consistent: “EST” is vast ingesteld op −05:00, terwijl “CET” seizoensveranderingen volgt. pandas 3 gebruikt de zoneinfo-weergave van Python.
Converteer een al vastgesteld moment
aware.tz_convert("UTC") geeft 07.00 uur UTC. Als je hetzelfde moment converteert, krijg je 03.00 uur in New York, 12.30 uur in Kolkata, 16.00 uur in Tokio en 17.00 uur in Sydney op 1 juli. De kloktijd verandert, maar het werkelijke moment blijft hetzelfde.
| Bewerking | Vereiste invoer | Wat blijft gelijk |
|---|---|---|
tz_localize(zone) | Tijd zonder tijdzone | Lokale kloktijd |
tz_convert(zone) | Tijd met tijdzone | Werkelijk moment |
Een waarde zonder tijdzone converteren geeft een fout omdat geen begintijdzone bekend is. Ook een tijdzone toekennen aan een waarde die er al een heeft, geeft een fout; gebruik voor die bewerking conversie. Gebruik op kolommen .dt.tz_localize() en .dt.tz_convert(). Gebruik op indexen de methoden rechtstreeks of gebruik de methoden van het DataFrame die op de index werken.
Lees tekst met tijdsverschillen in en combineer tijdzones
Een “Z” aan het einde van ISO-tekst betekent UTC. Lees tekst met verschillende tijdsverschillen in met utc=True:
raw = pd.Series(["2025-03-01 10:00+01:00",
"2025-04-01 10:00+02:00"])
common = pd.to_datetime(raw, utc=True)
Deze worden 09.00 en 08.00 uur UTC. Converteer daarna naar een regionale tijdzone voor lokale rapportage. Het inlezen van gemengde tijdsverschillen zonder utc=True geeft in pandas 3 een fout.
Twee reeksen met tijdzone worden uitgelijnd op werkelijke momenten, ook als hun tijdzonelabels verschillen. Amsterdamse metingen om 09.00 en 10.00 uur en Londense metingen om 08.00 en 09.00 uur in juli verwijzen naar overeenkomende momenten. Hun rekenresultaat gebruikt UTC-labels. Vergelijkingen op volgorde tussen tijdstempels zonder en met tijdzone mislukken; een gelijkheidsvergelijking geeft onwaar terug.
Verwijder een tijdzone bewust
tz_convert(None) drukt een waarde met tijdzone eerst uit in UTC en verwijdert daarna de tijdzone. De Amsterdamse tijd 09.00 uur wordt in juli 07.00 uur zonder tijdzone. tz_localize(None) verwijdert de tijdzone en behoudt 09.00 uur zonder tijdzone. Dit zijn verschillende uitkomsten. Bewaar gegevens voor berekeningen met tijdzone in UTC en converteer vóór rapportage of groepering op een lokale dag.
Belangrijkste punten
- Ken aan kloktijden zonder tijdzone de tijdzone van vastlegging toe.
- Converteer tijdstempels met tijdzone om hetzelfde moment elders weer te geven.
- Regionale IANA-namen behouden zomertijdregels.
- Lees gemengde tijdsverschillen in als een gemeenschappelijke UTC-weergave.
- Als je een tijdzone verwijdert, kun je UTC-tijd of lokale kloktijd behouden.
6.2 Verwerk zomertijd in tijdreeksen
Lokale klokken kunnen een uur overslaan of herhalen. Die veranderingen beïnvloeden het inlezen, verstreken tijdsduren en dagtotalen. Benoemde tijdzones laten pandas onderscheid maken tussen de werkelijke momenten achter lokale kloktijden.
Herken een overgeslagen lokale tijd
In Amsterdam ging de klok op 30 maart 2025 van 02.00 naar 03.00 uur. De kloktijd 02.30 uur kwam niet voor. Als je daaraan zonder verwerkingsregel een tijdzone toekent, krijg je een fout:
pd.Timestamp("2025-03-30 02:30").tz_localize(
"Europe/Amsterdam", nonexistent="shift_forward"
)
Het resultaat is 03:00+02:00, de eerste geldige tijd na het hiaat. nonexistent="NaT" behoudt het probleem als ontbrekende waarde. "shift_backward" verschuift naar het laatste geldige moment vóór het hiaat. Als je een record verschuift, verandert het tijdstempel, dus bewaar de oorspronkelijke invoer en documenteer de gekozen verwerkingsregel in de analyse.
Onderscheid twee herhaalde tijdstippen
Op 26 oktober 2025 ging de klok in Amsterdam van 03.00 terug naar 02.00 uur. De lokale tijd 02.30 uur kwam eenmaal voor met tijdsverschil +02:00 en eenmaal met +01:00. In UTC liggen ze een uur uit elkaar.
ambiguous=True selecteert de keer met zomertijd; ambiguous=False selecteert standaardtijd. ambiguous="NaT" markeert een niet-opgeloste tijd als ontbrekend. Een booleaanse lijst kan per rij kiezen. ambiguous="infer" kan een geordende reeks gebruiken die het herhaalde uur bevat, zoals 01.30, 02.00, 02.30, 02.00, 02.30, 03.00 uur. Eén enkele herhaalde kloktijd biedt onvoldoende informatie over de volgorde om af te leiden welke keer bedoeld was.
Tel uren in de lokale dag
De dag van de overgang in de lente heeft 23 uur en die in de herfst 25. Een volledige reeks uurgegevens die met resampling naar lokale dagen is omgezet, heeft daarom wisselende aantallen. Om het gemiddelde energieverbruik per uur te rapporteren, deel je een dagsom door het werkelijke aantal geldige uurmetingen of neem je het gemiddelde ervan. Als je elk totaal door 24 deelt, geef je de overgangsdagen onjuist weer.
Een gedeeltelijke dataset kan ook korte intervallen opleveren. Een UTC-reeks die op 29 maart om 00.00 uur begint, begint in Amsterdam om 01.00 uur, dus op de eerste lokale dag ontbreekt middernacht al vóór de overgangsdag. Controleer zowel de rapportagegrenzen als de tijdzoneregels.
Onderscheid dezelfde kloktijd van een gelijke verstreken tijd
t = pd.Timestamp("2025-03-29 12:00", tz="Europe/Amsterdam")
t + pd.offsets.Day(1) # March 30 at 12:00
t + pd.Timedelta(days=1) # March 30 at 13:00
De kalenderverschuiving behoudt 12.00 uur en overbrugt slechts 23 verstreken uren. De Timedelta telt 24 uur op. In de herfst kan een lokale kalenderdag daarentegen 25 verstreken uren bevatten.
Kies de rapportagetijdzone vóór het groeperen
Resampling volgt de tijdzone van de index. Om het verbruik per lokale datum in Amsterdam op te tellen, converteer je eerst een UTC-index met tijdzone naar “Europe/Amsterdam” en pas je daarna resampling toe naar “D”. Als je eerst in UTC resampling toepast, ontstaan andere daggrenzen die je niet kunt herstellen door alleen de labels van het resultaat te veranderen.
Overgangsdatums verschillen per regio: in New York veranderde de tijd in 2025 op 9 maart en 2 november; in Sydney eindigde de zomertijd op 6 april en begon die op 5 oktober. Tokio en Kolkata kennen geen overgang naar of van zomertijd. Bewaar ruwe momenten in UTC en gebruik de benoemde lokale tijdzone voor kalenderrapportages.
Belangrijkste punten
- Overgeslagen en herhaalde uren vereisen expliciete verwerkingsregels voor tijdzonetoewijzing.
- Een dubbelzinnige lokale tijd kan naar twee verschillende UTC-momenten verwijzen.
- Volledige lokale dagen kunnen 23 of 25 uur bevatten.
- Converteer naar de rapportagetijdzone voordat je op lokale dag groepeert.
- Onderscheid klokveranderingen van onvolledige gegevensdekking.
Tijdreeksen met pandas: voorbeelden
1Zet een tekstlogboek om in bruikbare datums
11 stappen
- 1IntroductieBegin met een datumkolom
Een meterlogboek komt binnen met datums als tekst. Je hebt datums nodig die pandas kan vergelijken, verstreken tijd tussen records en leesbare labels voor een rapport. Dat betekent een Timestamp voor elk tijdstip, een Timedelta voor verstreken tijd en pas aan het einde opgemaakte tekst.
Doorloop de conversie voordat je gaat rekenen. Een tekenreeks kan op een datum lijken zonder zich als een kalenderdatum te gedragen en een dubbelzinnig formaat kan een aannemelijke datum met de verkeerde betekenis opleveren.
- 2VoorbeeldLees de conventie van de bron
Het logboek vermeldt dat datums de dag eerst hebben en een 24-uursklok gebruiken. Eén waarde is “14/03/2025 18:45”. Het formaat is:
format="%d/%m/%Y %H:%M"Lees de codes op volgorde: dag, maand, jaar, uur en minuut.
%men%Mverschillen in hoofdlettergebruik omdat ze verschillende velden voorstellen. De datum is 14 maart; de tijd is 18.45 uur. - 3UitlegPas één bekend formaat toe
Converteer de kolom met het gedocumenteerde formaat:
parsed = pd.to_datetime(raw, format="%d/%m/%Y %H:%M", errors="coerce")Het formaat geldt voor elke aanwezige waarde. Deze typeconversie zet ongeldige invoer om naar
NaT. Zonder bekend formaat leidt pandas het formaat af uit de eerste aanwezige rij; daardoor is een bron met dubbelzinnige datums met schuine strepen gevoelig voor een verkeerde interpretatie. - 4UitdagingTel de werkelijke fouten
Een kolom bevat “14/03/2025 18:45”, “bad” en
None. Na omzetting bij fouten zijn twee resultatenNaT. Hoeveel aanwezige waarden konden niet worden ingelezen en met welk masker vind je ze?---reveal---
Eén aanwezige waarde kon niet worden ingelezen: “bad”. Gebruik
parsed.isna() & raw.notna(). De oorspronkelijkeNoneontbrak al, dus als je elkeNaTtelt, overschat je het aantal mislukte conversies. - 5UitlegHerken tijdstippen en tijdsduren
Een Timestamp stelt één tijdstip voor en een datetime-kolom bevat veel tijdstippen. Een Timedelta stelt verstreken tijd voor.
Trek een Timestamp voor het begin af van een Timestamp voor het einde om een tijdsduur te krijgen. Tel een Timedelta op om een tijdstip met een vaste hoeveelheid te verschuiven.
NaTmarkeert ontbrekende tijdstippen, dus rekenen met een ontbrekend begin of einde levert ook een ontbrekende tijdsduur op. - 6VoorbeeldTrek de twee tijdstippen van elkaar af
Neem deze tijdstempels:
start = pd.Timestamp("2025-03-10 18:00") end = pd.Timestamp("2025-03-14 09:30") elapsed = end - startHet resultaat is 3 dagen en 15:30 uur. Tel eerst de drie volledige dagen en daarna de resterende 15 uur en 30 minuten. Door dit als een Timedelta te bewaren, kun je in de volgende stap de gewenste rapportage-eenheid kiezen zonder dat restant te verliezen.
- 7VoorbeeldConverteer de volledige tijdsduur naar uren
Drie dagen dragen 72 uur bij. Het restant draagt 15,5 uur bij, dus het totaal is 87,5 uur.
hours = elapsed / pd.Timedelta(hours=1)elapsed.daysgeeft alleen 3. Het beschrijft het aantal volledige dagen, dus als je dat aantal met 24 vermenigvuldigt, verlies je 15,5 uur.total_seconds()geeft 315.000 en omvat ook de volledige tijdsduur. - 8UitdagingKies een bruikbaar kalenderkenmerk
Een rapport heeft het gemiddelde aantal kWh per weekdag over veel weken nodig. Welk kalenderkenmerk kan de groeperingssleutel leveren en heeft een kolom
.dtnodig?---reveal---
Gebruik
df["timestamp"].dt.day_name()als groeperingssleutel en neem daarna het gemiddelde vankwh. Een datetime-kolom heeft.dtnodig; een DatetimeIndex biedtday_name()rechtstreeks aan. Dit groepeert terugkerende weekdagen, geen afzonderlijke kalenderdatums. - 9TipControleer eenheden vóór export als gehele getallen
Een datetime-datatype zoals
datetime64[us]slaat aantallen op in microseconden. Een directe conversie naar gehele getallen geeft die aantallen terug, ook als oudere code nanoseconden verwacht.Vraag voor een kolom expliciet om
s.dt.as_unit("ns").astype("int64")als aantallen nanoseconden nodig zijn. Blijf voor het vergelijken van tijdsduren met Timedelta-waarden rekenen, zodat de eenheid met de waarde meegaat. - 10UitdagingBereid het eindrapport voor
Je hebt datums ingelezen en verstreken uren berekend. Het rapport heeft datums zoals “14 Mar 2025” nodig. Moet je de datumkolom vóór het rekenen opmaken en welke expressie levert het label op?
---reveal---
Rond eerst de datetime-berekeningen af en gebruik daarna
parsed.dt.strftime("%d %b %Y")voor weergavelabels. Opmaak geeft tekst terug. De afgekorte maandnaam volgt de taal- en regio-instellingen van het systeem; dit voorbeeld gebruikt Engels. - 11SamenvattingKies de weergave op basis van het doel
Gebruik datetime-waarden voor selectie op kalenderonderdelen en berekeningen, Timedelta-waarden voor verstreken tijdsduren en opgemaakte tekenreeksen voor definitieve labels. Bij het inlezen krijgen conventies van de bron een kalenderbetekenis.
Controleer voordat je een geconverteerde kolom doorgeeft de aanwezige invoer die niet kon worden ingelezen, het datatype en eventuele vereiste uitvoereenheden. Zo krijgt de latere analyse een duidelijke tijdsweergave om mee te werken.
2Maak een opgeschoonde geschiedenis en vergelijk de juiste datums
13 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieGeef elke rij een duidelijke tijdsidentiteit
- 2VoorbeeldLees in, indexeer en sorteer
- 3TipVerwerk herhaalde gebeurtenissen volgens hun betekenis
- 4UitdagingMaak een afwezige datum zichtbaar
- 5UitlegLees de nauwkeurigheid van een selector
- 6UitdagingSelecteer een terugkerend werkvenster
- 7VoorbeeldPlaats de voorganger naast elke waarde
- 8KernpuntEen groeiverhouding is geen percentagelabel
- 9UitlegVerschuif datums voor een kalendervergelijking
- 10UitdagingVolg de uitlijning op labels
- 11VerbandHoud de voorganger van elke winkel apart
- 12UitdagingHerstel een rapport over dagelijkse groei
- 13SamenvattingControleer labels voordat je verandering interpreteert
3Maak kalenders en geef volledige tijdsintervallen labels
12 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieBepaal wat een datum moet voorstellen
- 2VoorbeeldGenereer datums voor maandeinden
- 3TipKoppel de code aan de kalender
- 4UitdagingTel de grenspunten van een reeks
- 5VoorbeeldVerschuif één maand vanaf 31 januari
- 6UitlegBegrijp een datum die al op een kalenderpunt valt
- 7UitdagingKies werktijd of verstreken tijd
- 8UitlegGeef maandtotalen labels voor tijdsintervallen
- 9VoorbeeldConverteer een datum naar een maand en terug
- 10UitdagingLees een boekjaarlabel
- 11UitdagingKies maandelijkse tijdstippen of maandperioden
- 12SamenvattingLaat de kalenderregel de betekenis bepalen
4Maak dag- en maandrapporten uit waarnemingen
13 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieVraag wat de nieuwe frequentie moet betekenen
- 2VoorbeeldAggregeer twee grootheden verschillend
- 3UitlegVolg een interval van vijf minuten
- 4UitdagingVerplaats de waarneming op de grens
- 5TipControleer lege en gedeeltelijke intervallen
- 6VoorbeeldMaak een fijner dagelijks raster
- 7VoorbeeldVul één hiaat op drie manieren
- 8UitdagingBehoud wat bekend was
- 9KernpuntEen geselecteerd punt is geen totaal
- 10VoorbeeldHoud winkels in hun eigen intervallen
- 11UitdagingVerklaar een lege combinatie van winkel en maand
- 12UitdagingHerstel een vergelijkingstabel
- 13SamenvattingLees wat elke uitvoerrij stelt
5Volg de waarnemingen binnen elk venster
16 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieKies hoeveel geschiedenis van belang is
- 2VoorbeeldMaak het eerste volledige rijvenster
- 3VoorbeeldSchuif één rij vooruit
- 4UitdagingTel geldige waarden binnen de posities
- 5TipPlaats resultaten op het juiste tijdstip
- 6UitlegGebruik verstreken tijd voor onregelmatige gebeurtenissen
- 7VoorbeeldVolg de uitgesloten linkergrens
- 8UitdagingVerander de grens en het vereiste aantal waarnemingen
- 9KernpuntEen maand is geen vaste duur voor een schuivend venster
- 10VoorbeeldBehoud de volledige geschiedenis
- 11VoorbeeldVergelijk een waarde met het eerdere maximum
- 12VoorbeeldWerk een recursief gewogen gemiddelde bij
- 13UitlegLees de instelling voor de correctie
- 14UitdagingOnderscheid weging van een recent paar
- 15UitdagingKies hoeveel geschiedenis een rapport meeneemt
- 16SamenvattingBepaal het venster voordat je het resultaat leest
6Koppel momenten over tijdzones en klokveranderingen heen
12 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieOnderscheid de kloktijd van het moment
- 2UitlegKen een tijdzone toe aan een tijd zonder tijdzone
- 3VoorbeeldConverteer één gebeurtenis naar meerdere kloktijden
- 4TipBehoud regionale regels
- 5UitdagingKies hoe een tijdzone wordt verwijderd
- 6UitlegVerwerk een overgeslagen tijd in de lente
- 7UitlegOnderscheid twee voorkomens in de herfst
- 8UitdagingBepaal welke herhaalde kloktijd bedoeld is
- 9VoorbeeldTel een volledige lokale dag
- 10VoorbeeldOnderscheid morgen om 12.00 uur van 24 uur later
- 11UitdagingHerstel het lokale dagrapport
- 12SamenvattingHoud het moment en de rapportagegrens duidelijk
Tijdreeksen met pandas: oefenvragen
Set 1: Lees datums in, selecteer ze en vat ze samen10 Oefenvragen
Vraag 1 van 10
Toon antwoordVerberg antwoord
.days-component van de Timedelta leest, behoud je 24 uur en verlies je de resterende 6,5 uur. Deel de tijdsduur door pd.Timedelta(hours=1) om de volledige duur mee te nemen.Vraag 2 van 10
Toon antwoordVerberg antwoord
%d/%m/%Y behoudt 7 november. %H:%M leest de tijd op een 24-uursklok en de minuten. Als de maand eerst wordt gelezen, ontstaat 11 juli, een geldige datum met de verkeerde betekenis. Daarom is een succesvolle conversie op zichzelf niet genoeg.Vraag 3 van 10
Toon antwoordVerberg antwoord
sort_index() zorgt voor de chronologische volgorde die nodig is voor betrouwbare selectie op tijd. Duplicaten verwijderen zou het probleem niet oplossen, omdat de genoemde index geen herhaald tijdstempel bevat.Vraag 4 van 10
.loc["2025-07-08 09:00":"2025-07-08 12:00"]?Toon antwoordVerberg antwoord
.iloc, laat je 12.00 uur weg en krijg je er drie. Een datetime-deelbereik op basis van labels bevat beide grenzen als overeenkomende rijen aanwezig zijn.Vraag 5 van 10
pd.date_range("2025-08-19", periods=3, freq="MS")?Toon antwoordVerberg antwoord
MS vereist maandbeginnen, dus de eerste passende datum op of na 19 augustus is 1 september. 1 augustus ligt al vóór het opgegeven begin. De reeks bevat 19 augustus niet alleen omdat die datum als begingrens is opgegeven.Vraag 6 van 10
pd.DateOffset(months=1) op?Toon antwoordVerberg antwoord
Vraag 7 van 10
Toon antwoordVerberg antwoord
Vraag 8 van 10
Toon antwoordVerberg antwoord
Vraag 9 van 10
s = pd.Series([3, 9, 6, 12]) de laatste waarde van s.rolling(3).mean()?Toon antwoordVerberg antwoord
Vraag 10 van 10
Toon antwoordVerberg antwoord
Set 2: Vergelijk geschiedenissen en vensterresultaten10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
.dt.day_of_week terug voor een waarneming op zondag?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
pct_change() voor woensdag?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
freq="Q-SEP". Welk tijdsinterval beschrijft pd.Period("2026Q1", freq="Q-SEP")?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
resample("5min", closed="right", label="right").sum()?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
[2, NaN, 8, 14] de laatste twee resultaten van rolling(3, min_periods=2).mean()?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
rolling("3D").sum() op 6 april?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
s / s.cummax() - 1 de relatieve daling vanaf het cumulatieve maximum in de vierde rij?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 3: Kies de juiste kalenderbewerking10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
["2025-09-02", None, "2025-15-02", "bad"]. Die wordt ingelezen met format="%Y-%m-%d", errors="coerce". Hoeveel aanwezige bronwaarden konden niet worden geconverteerd?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
.loc["2025-12-02":"2025-12-03"]?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
pd.date_range("2025-06-10", "2025-06-11", freq="6h") bij de standaardopname van grenspunten?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
.to_timestamp(). Wat gebeurt er met de labels en hun uniciteit?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
pd.Grouper?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
rolling("3D", min_periods=2) met standaardgrenzen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
ewm(span=3, adjust=False)?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
ambiguous=True, aan de andere met ambiguous=False. Hoe ver liggen ze na conversie naar UTC uit elkaar?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 4: Onderzoek berekeningen met tijdreeksen10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
datetime64[us]. Een export vereist aantallen nanoseconden als gehele getallen. Welke kolomexpressie levert die aantallen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
1735689600000 in milliseconden. Welke inleesargumenten behouden de genoemde eenheid en tijdzone?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
a heeft 30 op 1 augustus en 50 op 4 augustus. Je berekent a - a.shift(1, freq="D"). Welke waarden verschijnen op 2 en 4 augustus?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
MonthEnd(0) en het optellen van MonthEnd(1) respectievelijk op voor een tijdstempel dat al op 30 april 2025 valt?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
.asfreq("D", how="end") en daarna met .to_timestamp() met de standaardinstellingen. Welk tijdstempel levert dit op?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
freq="B" van vrijdag 12 september tot en met maandag 15 september 2025. Er zijn geen aangepaste feestdagen opgegeven. Welke datums verschijnen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
asfreq("D"). Waarom is de gerapporteerde waarde niet het dagelijkse energietotaal?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
rolling(5, center=True).mean() en de standaard achterwaarts gerichte rolling(5).mean()?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
tz_convert(None) en tz_localize(None) in die volgorde op?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 5: Combineer tijdregels in volledige analyses10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
["2025-12-02", "03/12/2025"] en vermeldt dat bij datums met schuine strepen de dag eerst komt. Welke interpretatie moet de opschoning behouden?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
pct_change() over de hele kolom?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
resample("D").sum(min_count=1)?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Kom je niet uit je eigen opgave? Huiswerkhulp
Kernbegrippen
A
aantal aanwezige waarnemingen in het venster
achterwaarts gericht venster
achterwaarts opvullen
achterwaarts uitlijnen op een kalenderpunt
rollback() van een verschuiving vindt het dichtstbijzijnde geldige kalenderpunt op of vóór een datum en behoudt een datum die al op dat punt valt.rollback() van een MonthEnd-regel verschuift 15 januari naar 31 december van het voorgaande jaar.afgeleide frequentie
afvlakkingsfactor
asfreq
asfreq() plaatst een reeks op een nieuw raster door overeenkomende tijdstempels te selecteren, zonder tussenliggende waarnemingen te aggregeren.asfreq() op uurgegevens behoudt middernachtmetingen zonder de waarden van de dag op te tellen.C
cumulatief maximum
cumulatieve som
D
DateOffset
DatetimeIndex
.loc een volledige rapportagemaand selecteren.datumreeks
deelbereik op basis van labels inclusief beide grenzen
dubbel tijdstempel
dubbelzinnige lokale tijd
E
exponentieel gewogen voortschrijdend gemiddelde
F
frequentie op basis van de weekdagpositie binnen de maand
"WOM-3FRI" maakt terugkerende datums op de derde vrijdag van elke maand.frequentiecode
"15min" genereert labels per kwartier, terwijl "ME" maandeinden genereert.frequentieconversie van perioden
how="end" kan de laatste dagperiode van een maand selecteren.frequentieverhoging
frequentieverlaging
G
gecentreerd venster
I
IANA-tijdzonenaam
inclusie van intervalgrenzen
indexering met een gedeeltelijke datumtekenreeks
"2025-09" behoudt waarnemingen per uur gedurende heel september.indexniveau naar kolommen verplaatsen
inleesformaat
"%d/%m/%Y" leest “08/11/2025” als 8 november in plaats van 11 augustus.inlezen van gemengde datumnotaties
interval per lokale kalenderdag
intervallabel
ISO 8601
K
kalenderdag
kalendergebonden frequentie
kalendermasker
kwartaal van het boekjaar
L
lineaire interpolatie
M
min_periods
min_periods bepaalt hoeveel geldige waarden een venster nodig heeft voordat het een resultaat geeft en telt ontbrekende cellen daarbij niet mee.min_periods=2, maar niet aan min_periods=3.monotoon stijgende index
MultiIndex
N
NaT
pd.isna().NaT, net als invoer die al ontbrak.niet-bestaande lokale tijd
normalisatie
O
ontbrekend kalenderpunt
open linkergrens
openings-, hoogste, laagste en slotwaarde
opname van grenspunten
P
periode
periodegrens
PeriodIndex
R
relatieve daling vanaf het cumulatieve maximum
relatieve verandering
resampling
resampling per groep
S
schuivend venster
strftime
strftime zet datetime-waarden met formaatcodes om in tekst voor weergave en verandert hun weergave daarmee van datetime-waarden in tekenreeksen.strftime gebruiken om “17 Aug 2025” te tonen nadat de datetime-berekeningen zijn afgerond.T
tijdgebaseerd venster
tijdgroepering met Grouper
groupby regels voor tijdsintervallen levert, naast andere sleutels zoals winkel of sensor.tijdreeks
tijdsduur
tijdsinterval
tijdsresolutie
tijdstempel
tijdstempel met tijdzone
tijdstempel zonder tijdzone
tijdsverschil met UTC
tijdzoneconversie
tijdzonetoewijzing
typeconversie met ontbrekende waarden bij fouten
NaT, zodat de conversie kan worden afgerond en ongeldige waarden als ontbrekend zijn gemarkeerd.U
uitbreidend venster
uitlijning op tijdstempels
Unix-tijdstempel
unit="ms" gebruiken, ook als een aantal seconden erop lijkt.UTC
V
venster met een vaste tijdsduur
venster op basis van het tijdstip van de dag
verschuiving naar het maandeinde
vertraagde waarde
vertraging door afvlakking
verwerkingsregel voor tijdzonetoewijzing
voortschrijdende correlatie
vooruitgeschoven waarde
shift(-1) kan een tabel elke gebeurtenis vergelijken met de volgende vastgelegde gebeurtenis.voorwaarts opvullen
voorwaarts uitlijnen op een kalenderpunt
rollforward() van een verschuiving vindt het dichtstbijzijnde geldige kalenderpunt op of na een datum en behoudt een datum die al op dat punt valt.rollforward() van een MonthEnd-regel verschuift 15 januari naar 31 januari in hetzelfde jaar.W
werkdagfrequentie
Z
zomertijd
#
.dt-accessor
.dt-accessor biedt toegang tot datum-, tijd- en tijdsduurfuncties op een pandas-kolom, waaronder kalendervelden, afronding en eenheidsconversie..dt-accessor in readings["time"].dt.hour levert het vastgelegde uur om op te groeperen.Over deze les
Door StudeliFout melden
Maak je eigen Studiemateriaal
Maak van je aantekeningen, slides en documenten Leermodules, Oefenvragen, Flashcards en 6 andere tools.