Klassisk maskinlæring er modeller som finner mønstre i eksempler og bruker dem til å forutsi en kategori eller et tall. De trenger lite data og lite regnekraft, og de gjør én jobb godt. Hvor den hører hjemme står på maskinlæring-siden.
Har du en tabell med tall og et spørsmål om en kategori eller en verdi, er en språkmodell som regel feil verktøy. Det du trenger er eldre, billigere og ofte bedre.
Når folk sier AI nå, mener de nesten alltid språkmodeller. Men mye av AI-en som faktisk kjører i drift, i banker, energiselskaper og industribedrifter, er noe annet. Det er modeller som gjetter om en transaksjon er svindel, hvor mye strøm en bygning bruker i morgen, eller om en maskin trenger service snart. Det kalles klassisk maskinlæring, og den gjorde jobben lenge før ChatGPT.
| Oppgave | Svarer med | Eksempler |
|---|---|---|
| Klassifisering | En kategori | Er denne delen i ferd med å svikte? Er e-posten spam? Lav, middels eller høy risiko? |
| Regresjon | Et tall | Strømbehov neste time. Prisen på en bolig. Timer til neste service. |
Du gir modellen mange eksempler med riktig svar. Den gjetter, får vite hvor langt unna den var, og justerer seg litt. Etter mange runder treffer den. Trær bygges på en annen måte, ved å velge én deling om gangen, men tanken er den samme: ende opp med færre feil på eksemplene. Det er samme grunnidé som i en språkmodell, men med en mye mindre modell, på mye mindre data og med én bestemt jobb.
På tabeller har trebaserte modeller, som gradient boosting, lenge slått store nevrale nett. I 2022 sammenlignet Grinsztajn, Oyallon og Varoquaux modellene på 45 datasett og fant at trebaserte modeller fortsatt lå øverst på middels store datasett, selv uten å regne med at de er mye raskere å trene. Siden har feltet beveget seg, som tallet lengst til høyre viser.
Det siste tallet viser at historien ikke stopper her. En modell trent på millioner av syntetiske tabeller, TabPFN, slo tidligere metoder på små datasett uten tidkrevende finjustering. Det betyr ikke at du skal bytte i morgen. Det betyr at feltet ikke står stille, og at «enkelt» ikke er det samme som «ferdig utviklet».
Les lisensen før du prøver TabPFN i en bedrift. Koden er Apache 2.0, men modellvektene har egen lisens. README på GitHub (lest 8. oktober 2026) sier at vektene til TabPFN-2.5, 2.6, 3 og 3.5 er ikke-kommersielle, og viser til en egen bedriftslisens for kommersiell bruk. Vektene til TabPFN-2 har Prior Labs-lisensen, som er Apache 2.0 med krav om navngiving. For TabPFN-2.5 og nyere åpnes en nettleser første gang, der du logger inn hos Prior Labs og godtar lisensen. README anbefaler GPU, og sier at CPU er tregt. Installeres med pip install tabpfn. De 2,8 sekundene er tallet fra Nature-artikkelen, og jeg har ikke sjekket hvilken maskinvare som lå bak.
Men også uten nye modeller er det god grunn til å starte enkelt:
Det gjelder tabeller. På bilder, lyd og fri tekst er det motsatt.
| Du har | Start med |
|---|---|
| Tall og kategorier i en tabell | Klassisk maskinlæring: beslutningstrær, gradient boosting (XGBoost, LightGBM), logistisk regresjon |
| Veldig få rader | En enkel modell eller en regel. Tabellmodeller som TabPFN kan testes, men les lisensen først (se over) |
| Bilder, lyd eller rå signaler | Dyplæring, for eksempel nevrale nett for bilder |
| Fri tekst, åpne spørsmål, dialog | Språkmodell |
| Krav om å kunne forklare hvorfor | En modell du kan lese: logistisk regresjon eller et lite beslutningstre |
| Både tekst og tall | Språkmodell til å gjøre teksten om til kategorier, klassisk modell til å forutsi |
Rekkefølgen er poenget. Start der det enkleste kan virke, og gå videre først når du har sett at det ikke holder.
Modellen blir aldri bedre enn dataene. Det er der arbeidet starter, ikke i valget av algoritme.
Før du trener noe: regn ut hva en dum regel gir. Holder 98 av 100 deler, og modellen din alltid svarer «holder», har den 98 prosent rett og finner ikke en eneste feil. Slår ikke modellen den dumme regelen på det du faktisk bryr deg om, har du ikke en modell. Sjekk derfor hvor mange av de som sviktet den fant, ikke bare hvor ofte den hadde rett. Og test alltid på data den ikke har sett under treningen.
En modell trent på katter og hunder får se en elefant. Den svarer «hund, 71 prosent sikker», for det er det eneste den kan svare. Ingenting i modellen sier fra at dette er noe helt annet enn det den ble trent på. Tallet er konstruert.
Det kalles distribusjonsskift, og det skjer når modellen møter data som er annerledes enn treningsdataene. En maskin får ny driftsform, en sensor blir byttet, eller verden endrer seg. Derfor må modeller i drift følges opp og trenes på nytt. Og husk at modellen finner det som henger sammen med utfallet, ikke det som forårsaker det. Handler du som om det er det samme, kan du gjøre noe dumt med stor selvtillit.
Jeg har data om [hva dataene handler om]. Hver rad er [én enhet, for eksempel én del eller én kunde], og jeg vil forutsi [hva]. Jeg har omtrent [antall] rader og [antall] kolonner. Er dette klassifisering, regresjon eller noe annet? Trenger jeg maskinlæring, eller holder en enkel regel? Foreslå en enkel baseline og en modell å starte med, og fortell hva som kan gå galt med akkurat disse dataene.
Klassisk maskinlæring er ikke utdatert. Det er riktig verktøy for en bestemt jobb, og den jobben er det mange som har. Et eksempel på hvordan det ser ut når mønsteret er «lær det normale», står i Å finne det unormale.
«Regn ut den dumme regelen først» som kjørbar kode. Først en liten fil som lager konstruerte data: 2 000 deler, omtrent 3 prosent som sviktet, med vibrasjon og temperatur. Alt er funnet på. Deretter tre regler, bare med standardbiblioteket, som du kan kjøre med én gang. Lagre som deler.py og regel.py i samme mappe.
import random
# Konstruerte data: 2 000 deler, omtrent 3 prosent sviktet.
# Kolonnene er vibrasjon (mm/s) og temperatur (°C). Alle tall er funnet på.
def lag_data(n=2000, andel_svikt=0.03, frø=1):
rng = random.Random(frø)
rader = []
for _ in range(n):
svikt = rng.random() < andel_svikt
if svikt:
rader.append(((rng.gauss(3.4, 0.7), rng.gauss(80, 6)), 1))
else:
rader.append(((rng.gauss(2.0, 0.5), rng.gauss(68, 5)), 0))
return rader
# Del i trening og test. Testdelen brukes aldri til å velge regler.
def del_opp(rader, testandel=0.3, frø=1):
rng = random.Random(frø)
rader = rader[:]
rng.shuffle(rader)
snitt = int(len(rader) * (1 - testandel))
return rader[:snitt], rader[snitt:]import statistics
from deler import lag_data, del_opp
trening, test = del_opp(lag_data())
holdt = [x for x, y in trening if y == 0]
snitt = [statistics.mean(k) for k in zip(*holdt)]
sd = [statistics.stdev(k) for k in zip(*holdt)]
def dum_regel(x):
return 0 # alle deler holder
def terskel_regel(x):
return int(x[0] > 2.8) # fast grense på vibrasjon
def z_score_regel(x, grense=2.5):
z = [(v - m) / s for v, m, s in zip(x, snitt, sd)]
return int(max(z) > grense) # én variabel langt over det normale holder
def vurder(regel):
ekte = [y for _, y in test]
gjett = [regel(x) for x, _ in test]
rett = sum(g == e for g, e in zip(gjett, ekte)) / len(test)
funnet = sum(g and e for g, e in zip(gjett, ekte)) / sum(ekte)
falske = sum(g and not e for g, e in zip(gjett, ekte))
return rett, funnet, falske
print(f"Test: {len(test)} deler, {sum(y for _, y in test)} sviktet")
for navn, regel in [("dum regel", dum_regel), ("terskel", terskel_regel),
("z-score", z_score_regel)]:
rett, funnet, falske = vurder(regel)
print(f"{navn:10} {rett:5.1%} rett | {funnet:5.1%} av svikten funnet | {falske} falske alarmer")Test: 600 deler, 19 sviktet dum regel 96.8% rett | 0.0% av svikten funnet | 0 falske alarmer terskel 94.0% rett | 84.2% av svikten funnet | 33 falske alarmer z-score 97.8% rett | 84.2% av svikten funnet | 10 falske alarmer
Den dumme regelen har 96,8 prosent rett og finner ingenting. Terskelen og z-scoren finner like mange av svikten (16 av 19), men z-scoren gir 10 falske alarmer mot 33 og får dermed høyest andel rett. Det er et lite testsett: 19 sviktede deler betyr at én sviktet del er 5 prosentpoeng, så ikke les mer ut av forskjellen enn at regelen med færrest falske alarmer er den du vil ha. Z-score-regelen lærer snitt og standardavvik fra delene som holdt, og slår alarm når en av målingene ligger mer enn 2,5 standardavvik over det. Den er en enkel modell i seg selv.
Så den samme øvelsen med scikit-learn: en dum regel mot et beslutningstre, med samme data. Installeres med pip install scikit-learn, og filen leser deler.py fra boksen over.
# pip install scikit-learn
from sklearn.dummy import DummyClassifier
from sklearn.metrics import accuracy_score, recall_score
from sklearn.tree import DecisionTreeClassifier
from deler import lag_data, del_opp
trening, test = del_opp(lag_data())
X_tr, y_tr = [x for x, _ in trening], [y for _, y in trening]
X_te, y_te = [x for x, _ in test], [y for _, y in test]
modeller = {
"dum regel": DummyClassifier(strategy="most_frequent"),
"beslutningstre": DecisionTreeClassifier(max_depth=3, random_state=0),
}
for navn, modell in modeller.items():
modell.fit(X_tr, y_tr)
gjett = modell.predict(X_te)
falske = sum(g and not e for g, e in zip(gjett, y_te))
print(f"{navn:15} {accuracy_score(y_te, gjett):5.1%} rett | "
f"{recall_score(y_te, gjett):5.1%} av svikten funnet | {falske} falske alarmer")dum regel 96.8% rett | 0.0% av svikten funnet | 0 falske alarmer beslutningstre 98.7% rett | 73.7% av svikten funnet | 3 falske alarmer
Treet har høyest andel rett og færrest falske alarmer, men finner 14 av de 19 sviktede delene, mot 16 for z-score-regelen. Det er lærdommen i tallene: «andel rett» sier lite når nesten alt holder, så se på hva som blir funnet og hva alarmene koster. Setter du class_weight="balanced" på treet, som gjør at feil på de sjeldne sviktene teller tyngre, endrer bildet seg i samme kjøring: 100 prosent av svikten funnet og 15 falske alarmer, og 97,5 prosent rett. Hvilken av dem som er best, avgjøres av hva en sviktet del og en falsk alarm koster hos deg. Alt dette er ett enkelt tre, ett konstruert datasett og 19 sviktede deler i testsettet, så ikke les mer ut av forskjellene enn at de finnes. Vil du prøve på åpne data, finnes AI4I 2020 Predictive Maintenance Dataset hos UCI: 10 000 syntetiske rader, lisens CC BY 4.0, med Machine failure som mål.
Kjørt 8. oktober 2026 med Python 3.13.16 på Windows 11: deler.py og regel.py, og utskriften over er fra den kjøringen. sk_modell.py er kjørt med scikit-learn 1.9.1 på Python 3.13.11 (et eget miljø på maskinen, ingenting ble installert for anledningen), og utskriften over er fra den kjøringen. Varianten med class_weight="balanced" er kjørt i samme miljø med samme data, men er ikke vist som egen fil. Datasettet fra UCI er ikke lastet ned eller brukt her.
Oppdatert oktober 2026. Kilder: Grinsztajn, Oyallon og Varoquaux, «Why do tree-based models still outperform deep learning on typical tabular data?», NeurIPS 2022 (Datasets and Benchmarks). Hollmann m.fl., «Accurate predictions on small data with a tabular foundation model», Nature 637, 2025. Jeg har lest sammendragene og ikke alle resultattabellene, og 2,8 sekunder gjelder klassifisering på datasett opp til 10 000 rader. Punktene om kostnad og datamengde er erfaringsregler og ikke målt her. Punktene i figuren er konstruert. Lisensopplysningene om TabPFN er fra README på GitHub, lest 8. oktober 2026, og kan endre seg per modellversjon.