- Je maakt een groepssplit zonder dezelfde groep in train en test.
- Je maakt tijdsplits met een gat en opeenvolgende evaluatievensters.
Je meet vier planten op drie dagen. Twaalf rijen lijken veel voorbeelden, maar het zijn nog steeds maar vier planten. Als dezelfde plant in training en test belandt, onderzoek je iets anders dan voorspellen voor een geheel nieuwe plant.
De verdeling moet daarom passen bij je evaluatievraag. Wil je nieuwe planten beoordelen, houd planten bijeen. Wil je de toekomst van bekende planten voorspellen, houd toekomstige metingen apart.
1. Nieuwe planten blijven volledig onbekend
Een groepssplit (group split) wijst een hele groep aan training of test toe. Hier is een groep één plant; alle records van plant B gaan dus naar dezelfde kant. De record-ID benoemt een meting, de groep benoemt de plant die meerdere metingen kan hebben.
Neem drie records: A met ID 1, B met ID 2 en weer A met ID 3. Kies B als testgroep: training krijgt ID's 1 en 3, test krijgt ID 2. Je bewaart de volgorde waarin die records binnenkwamen.
rows = [
{"groep": "A", "id": 1},
{"groep": "B", "id": 2},
{"groep": "A", "id": 3}
]
testgroepen = {"B"}
train = []
test = []
for i in range(len(rows)):
groep = rows[i]["groep"]
if groep in testgroepen:
test.append(rows[i])
if groep not in testgroepen:
train.append(rows[i])
print(train[0]["id"], train[1]["id"]) # 1 3
print(test[0]["id"]) # 2
{"B"} maakt een set met één groepsnaam. Anders dan bij een dictionary staat er geen dubbele punt met een bijbehorende waarde. De twee voorwaarden sluiten elkaar uit: dezelfde groep kan niet tegelijk wel en niet in de set zitten.
Maak split_groepen(rows, testgroepen) en geef (train, test) terug. Maak nieuwe lijsten en verander de oorspronkelijke records niet. Een opgegeven testgroep die niet in de gegevens voorkomt voegt geen records toe.
In de visualisatie zie je vier planten met ieder drie metingen. Per rij geeft zes trainingsrijen, zes testrijen en vier gedeelde planten. Kies Per groep: de aantallen blijven zes en zes, maar er zijn nul gedeelde planten.
Vier planten, elk gemeten op drie dagen. Kies een split en volg welke metingen samen blijven.
Alle vier de planten staan aan beide kanten. Dit toetst geen generalisatie naar onbekende planten.
Kies daarna Op tijd. Dag 1 en 2 vormen acht trainingsrijen; dag 3 vormt vier testrijen, met alle vier planten aan beide kanten. Dat is passend voor een nieuwe dag van bekende planten, maar geen proef met onbekende planten.
2. Neem alleen informatie die op tijd beschikbaar is
Veelgemaakte fout: een eerdere meetdatum voldoende vinden. Het antwoord bij die meting kan pas dagen later bekend worden. Dan zou training toch informatie gebruiken die bij de voorspelling nog toekomst was.
We laten daarom zo nodig een gat (gap) vóór het testbegin. Stel de tijdgrens t op 4 en de gap g op 1. Van tijden 0, 1, 2, 3, 4 en 5 gaan 0–2 naar training, 3 naar het gat en 4–5 naar test.
s is de tijd van één record, t de testgrens en g de niet-negatieve gap. Beide grenzen gebruiken dezelfde tijdseenheid als de metingen. Onze oefenrijen staan al chronologisch en bevatten eindige numerieke tijden.
rows = []
for i in range(6):
rows.append({"tijd": i})
t = 4
gap = 1
train = []
test = []
gat = []
for i in range(len(rows)):
tijd = rows[i]["tijd"]
if tijd < t - gap:
train.append(rows[i])
if tijd >= t:
test.append(rows[i])
if tijd >= t - gap and tijd < t:
gat.append(rows[i])
print(train) # tijden 0, 1, 2
print(gat) # [{'tijd': 3}]
print(test) # [{'tijd': 4}, {'tijd': 5}]
and betekent dat beide voorwaarden tegelijk moeten gelden. Maak split_tijd(rows, t, gap=0) met resultaat (train, test, gat); de standaardwaarde 0 laat geen gat. Weiger een negatieve gap met ValueError vóór je splitst: anders kunnen dezelfde tijden zowel training als test worden.
De benodigde gap volgt uit meetvensters en wanneer antwoorden beschikbaar komen. Een willekeurig gekozen gat bewijst geen veiligheid; controleer de grenzen tegen het echte meetproces.
3. Herhaal met een groeiend verleden
Bij rolling-origin evaluation schuift het toetsmoment vooruit. Voor zeven chronologische punten zijn de indices 0 tot en met 6. Met drie eerste trainingspunten en een testhorizon van twee ontstaat eerst training 0–2 met test 3–4, daarna training 0–4 met test 5–6.
Hier gebruiken we regelmatige meetmomenten en informatie die meteen beschikbaar is, dus geen gap. Eerdere testpunten mogen pas in een latere ronde naar training. Binnen iedere ronde blijven alle testindices na alle trainingsindices liggen.
n = 7
initial = 3
horizon = 2
vensters = []
stop = n - horizon + 1
for end in range(initial, stop, horizon):
train = list(range(end))
test = list(range(end, end + horizon))
vensters.append((train, test))
print(vensters[0]) # ([0,1,2], [3,4])
print(vensters[1]) # ([0,1,2,3,4], [5,6])
range(start, stop, stap) begint bij start, stopt vóór stop en springt telkens stap verder. End is de eerste testindex: 3 en daarna 5. De laatste toegestane start is n−horizon; de +1 maakt die grens bereikbaar ondanks de exclusieve stop.
Maak tijdvensters(n, initial, horizon) voor gehele aantallen, met n minstens nul en beide venstergroottes minstens één. Weiger ongeldige aantallen met ValueError. Gebruik alleen volledige testvensters: voor n=4, initial=3 en horizon=2 is het resultaat [].
Wat neem je mee?
- Groepen bijeenhouden toetst nieuwe groepen; een tijdgrens toetst een latere periode.
- Houd rekening met vertraagde informatie en controleer een gap vóór je gegevens verdeelt.
- Groeiend trainen gebruikt per ronde alleen het beschikbare verleden.
Hierna bereiden we kenmerken voor, steeds binnen de eerlijke grenzen die je nu kunt bouwen.