Optimalisatietechnieken in Python
Python biedt een scala aan krachtige technieken voor het oplossen van optimalisatieproblemen, van eenvoudige gradient-gebaseerde methoden tot complexere algoritmen. Met deze technieken kun je efficiënt minima of maxima van functies vinden, of het nu in machine learning, engineering of operations research is.
In deze sectie behandelen we veelgebruikte optimalisatietechnieken in Python, waaronder gradient descent, de methode van Newton, de geconjugeerde-gradientenmethode, quasi-Newton-methoden, de Simplex-methode en trust-region-methoden.
Opmerking: bekijk dit DataLab om alle code te zien die is gebruikt om de visualisaties in deze sectie te genereren.
Laten we erin duiken!
Gradient descent
Gradient descent is een van de meest fundamentele technieken in numerieke optimalisatie. Het is een iteratieve methode om het minimum van een functie te vinden door de negatieve gradiënt (of helling) van de functie te volgen.
Het kernidee is om te starten met een initiële schatting en deze iteratief te updaten door in de richting van de steilste afdaling te bewegen totdat er convergentie is bereikt. Het is een van de meest gebruikte optimalisatietechnieken bij het trainen van machine learning-modellen, waar het doel is om de verliesfunctie te minimaliseren.
Methode van Newton
De methode van Newton is een optimalisatietechniek die het minimum vindt met behulp van zowel de gradiënt als de tweede-orde afgeleide (de Hessiaan) van de doelfunctie. In tegenstelling tot gradient descent, dat alleen op eerste-orde afgeleiden steunt, benut de methode van Newton krommingsinformatie, wat zorgt voor snellere convergentie, vooral bij convexe functies.
Hoewel de methode van Newton snel convergeert, vereist ze het berekenen van de Hessiaan, wat computationeel kostbaar en onpraktisch kan zijn voor grootschalige problemen. Ze is echter zeer effectief voor kleine, gladde convexe problemen.

Geconjugeerde-gradientenmethode
De geconjugeerde-gradientenmethode is een efficiënte optimalisatietechniek voor grootschalige problemen, met name wanneer het opslaan van de Hessiaan onpraktisch is. De methode bouwt iteratief geconjugeerde richtingen op en optimaliseert langs die richtingen, in plaats van de volledige Hessiaan te vereisen. Hierdoor is ze geschikt voor problemen zoals het minimaliseren van grote kwadratische functies.
Deze methode is nuttig in eindige-elementenanalyse of grootschalige machine learning-toepassingen, waar matrixberekeningen belastend worden.

Quasi-Newton-methoden (BFGS)
Quasi-Newton-methoden, zoals het Broyden–Fletcher–Goldfarb–Shanno-algoritme (BFGS), benaderen de Hessiaan in plaats van die direct te berekenen. Deze methoden bereiken snellere convergentie dan gradient descent door informatie van tweede orde te benutten zonder de rekenlast van het volledig uitrekenen van de Hessiaan.

Simplex-methode
De Simplex-methode is een veelgebruikt algoritme voor het oplossen van lineaire programmeringsproblemen (LP), waarbij de doelfunctie en de randvoorwaarden lineair zijn. Ze onderzoekt systematisch de hoekpunten van de toelaatbare regio (een polyheder) en beweegt richting het optimale hoekpunt waar de doelfunctie haar maximum- of minimumwaarde bereikt.

Trust-region-methoden
Trust-region-methoden zijn optimalisatie-algoritmen die een lokaal model van de doelfunctie opbouwen binnen een “trust region” rond de huidige oplossing.
In plaats van stappen in een vooraf bepaalde richting te nemen (zoals bij gradient descent), definieert het algoritme een eenvoudiger subprobleem binnen de trust region. Dit subprobleem wordt iteratief opgelost om de oplossing te verfijnen. Deze methoden zijn bijzonder effectief voor complexe, niet-lineaire problemen en bieden meer stabiliteit dan traditionele gradient-gebaseerde methoden.

Trust-regio's en stralen bij het minimaliseren van de functie van Rosenbrock | Bron: Trust Region Methods door Shivangi Khare
Veelgebruikte Python-pakketten voor optimalisatie
Er zijn verschillende libraries en pakketten ontwikkeld om numerieke optimalisatie te vergemakkelijken. Elk heeft zijn eigen sterke punten en toepassingen, maar ongeacht het optimalisatieprobleem waar je voor staat, is er doorgaans een robuuste tool in Python om je te helpen.
Hier zijn vier van de meest gangbare optimalisatiepakketten:
SciPy optimization (scipy.optimize)
De module scipy.optimize is een veelzijdige library binnen het SciPy-ecosysteem met een breed scala aan algoritmen voor zowel onbeperkte als beperkte optimalisatieproblemen. De module bevat functies voor het vinden van minima van scalaire en multivariabele functies, het oplossen van nulpunten (root-finding) en het fitten van krommen op data.
Functies in deze module zijn onder meer:
minimize(): Een functie om een scalaire functie van één of meer variabelen te minimaliseren.
from scipy.optimize import minimize
def objective_function(x):
return x[0]**2 + x[1]**2
result = minimize(objective_function, [1, 1], method='BFGS')
print(result.x) # Optimal solution
# >>> [-1.07505143e-08 -1.07505143e-08]
root(): Vindt het nulpunt van een vectorfunctie – uiterst nuttig voor het oplossen van systemen van niet-lineaire vergelijkingen.
from scipy.optimize import root
def equations(vars):
x, y = vars
return [x + 2*y - 3, x - y - 1]
result = root(equations, [0, 0])
print(result.x)
# >>> [1.66666667 0.66666667]
curve_fit(): Deze functie fit een kromme op een set datapunten en is nuttig voor curve fitting en parameterinschatting.
from scipy.optimize import curve_fit
import numpy as np
def model(x, a, b):
return a * np.exp(b * x)
x_data = np.array([1, 2, 3])
y_data = np.array([2.7, 7.4, 20.1])
params, covariance = curve_fit(model, x_data, y_data)
print(params) # Fitted parameters
# >>> [0.9981286 1.00089935]
CVXPY
CVXPY is een Python-library ontworpen voor convex-optimisatieproblemen. Het stelt je in staat om deze problemen te definiëren en op te lossen met een hoog-niveau, declaratieve syntax. Het vereenvoudigt het formuleren van complexe optimalisatieproblemen door gebruikers de doelfunctie en beperkingen op een natuurlijke en leesbare manier te laten specificeren.
CVXPY biedt de volgende features:
- Declaratieve syntax: CVXPY biedt een intuïtieve manier om optimalisatieproblemen te modelleren met Python’s wiskundige expressies.
- State-of-the-art solvers: Het interface’t met geavanceerde solvers zoals ECOS, SCS en OSQP, die convex-problemen efficiënt verwerken.
import cvxpy as cp
# Define variables
x = cp.Variable()
y = cp.Variable()
# Define constraints
constraints = [x + y == 1, x - y >= 2]
# Define the objective function
objective = cp.Minimize(x**2 + y**2)
# Formulate the problem
prob = cp.Problem(objective, constraints)
# Solve the problem
result = prob.solve()
print(f"Optimal value: {result}")
print(f"x: {x.value}, y: {y.value}")
# >>> Optimal value: 2.5
# x: 1.5, y: -0.5000000000000001
Pyomo
Pyomo is een flexibel en uitgebreid optimalisatiemodelleerpakket dat lineaire, niet-lineaire en gemengd-gehele programmering ondersteunt. Het is ontworpen voor complexe optimalisatieproblemen en integreert naadloos met solvers zoals GLPK, CBC en CPLEX.
De features van Pyomo omvatten:
- Modelleringsflexibiliteit: Met Pyomo kun je optimalisatieproblemen met grote flexibiliteit definiëren, inclusief complexe beperkingen en doelen.
- Solverintegratie: Het ondersteunt een breed scala aan solvers, waardoor je de beste tool voor een specifiek probleem kunt kiezen.
Gurobi en CPLEX (via Pyomo of directe API)
Gurobi en CPLEX zijn high-performance solvers voor grootschalige optimalisatieproblemen. Ze worden veel gebruikt in het bedrijfsleven voor taken zoals supply chain-optimalisatie, portefeuillebeheer en logistiek.
Ze bieden geavanceerde algoritmen die zijn ontworpen om complexe en grootschalige problemen efficiënt aan te pakken.
- Gurobi: Toegankelijk via Pyomo of de directe API. Gurobi staat bekend om zijn snelheid en betrouwbaarheid bij het oplossen van lineaire, gehele en kwadratische programmeringsproblemen.
- CPLEX: Evenzo biedt CPLEX krachtige optimalisatiecapaciteiten en wordt het in diverse sectoren gebruikt voor het oplossen van complexe operationele en strategische problemen. Toegang kan via Pyomo of rechtstreeks via de API.
Deze solvers worden vaak ingezet voor industriële schaalproblemen waarbij rekenkundige efficiëntie en robuustheid cruciaal zijn.
Toepassingen van numerieke optimalisatie in Python in de praktijk
Zoals ik in de introductie aangaf, speelt numerieke optimalisatie een cruciale rol in verschillende domeinen. Het biedt essentiële technieken voor het oplossen van complexe problemen en het nemen van datagedreven beslissingen.
Bijvoorbeeld:
- Machine learning: Modellen worden in de kern getraind met numerieke optimalisatie. Dit houdt in dat je de optimale parameters vindt die de verliesfunctie minimaliseren en zo kwantificeren hoe goed het model de doelvariabele voorspelt.
- Operations research: Optimalisatietechnieken helpen strategische beslissingen te nemen die diverse operationele metrics maximaliseren of minimaliseren. Door doelfuncties te optimaliseren onder randvoorwaarden kunnen onderzoekers efficiëntie verbeteren in processen zoals supply chain management, personeelsplanning en productieplanning.
- Financiën: Numerieke optimalisatie is cruciaal in de financiële sector voor taken zoals portefeuille-optimalisatie. Het helpt bij het bepalen van de beste activaverdeling om rendement te maximaliseren of risico te minimaliseren.
- Technisch ontwerp: Numerieke optimalisatie wordt toegepast om systemen en structuren te ontwerpen die aan specifieke prestatiecriteria voldoen en tegelijkertijd de kosten minimaliseren. Dit helpt bij efficiënte ontwerpen voor alles van bruggen en vliegtuigen tot productieprocessen en energiesystemen.
Best practices voor numerieke optimalisatie in Python
Om de beste resultaten uit je optimalisatie-inspanningen in Python te halen, moet je met verschillende factoren rekening houden. Volg in elk geval deze best practices:
De juiste algoritmekeuze
Het kiezen van het juiste optimalisatie-algoritme is cruciaal voor optimale resultaten. De keuze hangt af van de aard van het probleem:
- Lineair vs. niet-lineair: Voor lineaire problemen zijn technieken voor lineaire programmering zoals de Simplex- of interior-point-methode geschikt. Voor niet-lineaire problemen zijn methoden zoals gradient descent, de methode van Newton of quasi-Newton-methoden (bijv. BFGS) vaak geschikter.
- Beperkt vs. onbeperkt: Voor problemen met randvoorwaarden zijn algoritmen zoals Sequential Quadratic Programming (SQP) of methoden die beperkingen native afhandelen (bijv. interior-point-methoden) nodig. Onbeperkte problemen kunnen efficiënt worden opgelost met gradient descent of de methode van Newton.
De juiste algoritmekeuze op basis van de kenmerken van het probleem zorgt voor snellere convergentie en nauwkeurigere oplossingen.
Omgaan met randvoorwaarden
Randvoorwaarden in optimalisatieproblemen kunnen de keuze van algoritme en oplossingsstrategie sterk beïnvloeden. Er zijn verschillende benaderingen om met beperkingen om te gaan:
- Strafmethoden (penalty): Neem beperkingen op in de doelfunctie door een strafterm toe te voegen voor schendingen. Zo transformeer je een beperkt probleem naar een onbeperkt probleem, waardoor onbeperkte optimalisatiemethoden gebruikt kunnen worden.
- Barrièremethoden: Gebruik barrièrefuncties om te waarborgen dat beperkingen niet worden geschonden. Deze methoden voegen een barrièreterm toe aan de doelfunctie die naar oneindig gaat naarmate je de randvoorwaarden nadert.
- Native ondersteuning: Maak gebruik van solvers met ingebouwde ondersteuning voor beperkingen. Veel moderne optimalisatiesolvers, zoals in
scipy.optimizeof CVXPY, kunnen beperkingen direct en efficiënt afhandelen.
De juiste aanpak voor het behandelen van beperkingen zorgt ervoor dat oplossingen haalbaar zijn en aan alle eisen voldoen.
Schalen en pre-processen
Goed schalen en pre-processen van data kan de prestaties van optimalisatie-algoritmen aanzienlijk verbeteren:
- Schalen: Normaliseer of standardiseer invoerdata zodat features evenveel bijdragen aan de doelfunctie. Dit kan problemen met numerieke stabiliteit voorkomen en de convergentie verbeteren.
- Pre-processen: Pas technieken toe zoals feature engineering of dimensionaliteitsreductie om het probleem te vereenvoudigen. Goed pre-processen verkleint de complexiteit van het optimalisatieprobleem en versnelt het oplossingsproces.
Resultaten interpreteren
Het interpreteren van resultaten van optimalisatie-algoritmen omvat inzicht in verschillende aspecten:
- Kwaliteit van de oplossing: Beoordeel de kwaliteit door te controleren of aan optimale voorwaarden en beperkingen is voldaan. Vergelijk de resultaten met bekende benchmarks of valideer met cross-validatietechnieken.
- Convergentiecriteria: Controleer of het algoritme is geconvergeerd via meldingen, aantal iteraties of veranderingen in de waarde van de doelfunctie. Zorg dat de gevonden oplossing dicht bij het echte optimum ligt.
- Numerieke precisie: Houd rekening met de impact van numerieke precisie op de resultaten. Kleine numerieke fouten kunnen zich opstapelen en de uiteindelijke oplossing beïnvloeden, vooral bij grootschalige problemen of strakke toleranties.
Conclusie
Numerieke optimalisatie is een hoeksteen van modern probleemoplossen. Het biedt krachtige tools om complexe uitdagingen aan te pakken in domeinen zoals machine learning, engineering, financiën en operations research.
Het rijke Python-ecosysteem van optimalisatielibraries—zoals SciPy, CVXPY en Pyomo—maakt deze geavanceerde technieken toegankelijker en stelt onderzoekers, ingenieurs en data scientists in staat om efficiënte systemen te ontwerpen, modellen te optimaliseren en slimmere, datagedreven beslissingen te nemen.
Gewapend met de juiste technieken en best practices ben je nu goed voorbereid om zelfs de meest uitdagende optimalisatieproblemen in Python aan te pakken. Bekijk deze bronnen om verder te leren:
FAQs
Wat is optimalisatie?
Optimalisatie is het proces van het vinden van het minimum of maximum van een functie met iteratieve rekenmethoden in plaats van analytische oplossingen.
Waarom is optimalisatie belangrijk?
Optimalisatie is belangrijk omdat het helpt om complexe, realistische problemen op te lossen in vakgebieden zoals machine learning, engineering en financiën, waar directe oplossingen onpraktisch of onmogelijk zijn.
Welke Python-pakketten zijn het beste voor numerieke optimalisatie?
Populaire Python-pakketten voor numerieke optimalisatie zijn onder andere SciPy (voor general-purpose optimalisatie), CVXPY (voor convex optimalisatie), Pyomo (voor flexibele modellering) en krachtige solvers zoals Gurobi en CPLEX, die geschikt zijn voor grootschalige toepassingen in de industrie.
Hoe wordt numerieke optimalisatie gebruikt in machine learning?
In machine learning wordt numerieke optimalisatie gebruikt om de verliesfunctie te minimaliseren, die meet hoe goed een model zijn doelvariabelen voorspelt.
Wat is het verschil tussen beperkte en onbeperkte optimalisatie?
Onbeperkte optimalisatie houdt in dat je de optimale waarde van een doelfunctie vindt zonder beperkingen op de variabelen. Bij beperkte optimalisatie daarentegen worden beperkingen (gelijkheden of ongelijkheden) opgelegd aan de variabelen, en moet de optimale oplossing aan deze beperkingen voldoen terwijl de functie wordt geoptimaliseerd.


Optimalisatie is een van de belangrijkste technieken in machine learning. Het was een van de eerste dingen die ik leerde, maar ik merkte al snel dat de toepassing ervan veel verder reikt dan alleen ML.
Numerieke optimalisatie speelt een cruciale rol bij het oplossen van complexe problemen in uiteenlopende vakgebieden. Zonder optimalisatie zouden data scientists, economen en ingenieurs vastlopen met inefficiënte, dure tools en niet-optimale beslissingen.
Daarom behandelen we in dit artikel optimalisatie in Python, inclusief de meest gebruikte pakketten, technieken en best practices.
Gordel om, maak je klaar voor de rit en volg mee met dit DataLab-werkboek.
Wat is numerieke optimalisatie?
Voor veel problemen in de echte wereld is het lastig om rechtstreeks de beste oplossing te bepalen. Het oplossen van deze problemen vereist een iteratieve aanpak, en precies daar komt numerieke optimalisatie om de hoek kijken.
Numerieke optimalisatie is het proces van het vinden van de minimum- of maximumwaarde van een functie met behulp van iteratieve rekenmethoden, in plaats van analytische oplossingen die via algebraïsche bewerkingen worden afgeleid.
In tegenstelling tot analytische methoden, die mogelijk exacte oplossingen in gesloten vorm geven, steunt numerieke optimalisatie op algoritmen die de optimale oplossing benaderen door schattingen gaandeweg te verbeteren over meerdere iteraties.
Deze aanpak is vooral nuttig bij functies die:
Een exacte analytische oplossing is in zulke gevallen onmogelijk of onpraktisch, vandaar de iteratieve aanpak.
Veelvoorkomende optimalisatieproblemen
In numerieke optimalisatie worden problemen doorgaans ingedeeld op basis van de aard van de doelfunctie en de aanwezigheid of afwezigheid van randvoorwaarden.
De meest voorkomende problemen vallen daarom in de volgende categorieën:
Onbeperkte optimalisatie
Dit is de eenvoudigste vorm van optimalisatie. Het gaat om het vinden van het minimum of maximum van een doelfunctie zonder beperkingen op de variabelen.
Het doel is om het punt te bepalen waarop de functie haar optimale waarde (minimum of maximum) bereikt, uitsluitend op basis van de wiskundige structuur ervan.
Technieken zoals gradient descent of de methode van Newton worden vaak gebruikt om onbeperkte problemen op te lossen (hierover later meer). De focus ligt op het iteratief verbeteren van de oplossing door de afgeleiden van de functie te evalueren.
Een voorbeeld is het minimaliseren van een kostenfunctie f(x) die afhangt van één of meer variabelen x, zonder beperkingen op de waarden die x kan aannemen; dit is een typisch onbeperkt probleem.
Beperkte optimalisatie
Beperkte optimalisatieproblemen houden daarentegen in dat je de optimale waarde van een doelfunctie vindt onder één of meer beperkingen op de variabelen. Deze beperkingen kunnen gelijkheden of ongelijkheden zijn.
De uitdaging bij beperkte optimalisatie is om de functie te optimaliseren en er tegelijk voor te zorgen dat de oplossing aan de opgegeven beperkingen voldoet.
Een typisch voorbeeld in technisch ontwerp is het minimaliseren van materiaalkosten (de doelfunctie) met inachtneming van fysieke beperkingen zoals sterkte of gewicht (de randvoorwaarden).
Methoden zoals Lagrange-vermenigvuldigers, straf- en barrièrefuncties worden vaak gebruikt om deze beperkingen in het optimalisatieproces op te nemen.
Lineaire vs. niet-lineaire optimalisatie
Bij lineaire optimalisatie zijn zowel de doelfunctie als de randvoorwaarden, je raadt het al… lineair. Dit betekent dat lineaire vergelijkingen of ongelijkheden de relaties tussen de variabelen weergeven.
De oplossingsruimte voor lineaire optimalisatieproblemen is doorgaans eenvoudiger en goed gestructureerd, wat vaak leidt tot efficiënte oplossingen met methoden zoals Simplex of interior-point.
Een klassiek voorbeeld van lineaire optimalisatie is lineaire programmering, waarbij het doel kan zijn om de winst (een lineaire functie) te maximaliseren onder randvoorwaarden rond middelen (lineaire ongelijkheden).
Daarentegen omvat niet-lineaire optimalisatie een niet-lineaire doelfunctie of niet-lineaire randvoorwaarden, waardoor het probleem aanzienlijk complexer wordt.
In realistische toepassingen zien we vaak niet-lineaire optimalisatieproblemen waar de relaties tussen variabelen niet rechtlijnig zijn. Deze problemen kunnen meerdere lokale optima hebben, wat ze uitdagender maakt dan lineaire problemen.
Technieken zoals gradient-gebaseerde methoden, de methode van Newton en evolutionaire algoritmen worden vaak ingezet voor niet-lineaire optimalisatie.
Een voorbeeld van niet-lineaire optimalisatie is het minimaliseren van een energiefunctie met complexe fysieke afhankelijkheden, zoals het optimaliseren van de vorm van een vliegtuigvleugel voor aerodynamische efficiëntie, waarbij niet-lineaire relaties bestaan tussen ontwerpvariabelen en prestatie-indicatoren.