Machine Learning Academy · Lektion

Bag of Words: CountVectorizer och TfidfVectorizer

Ni kommer att tokenisera text, bygga ett vokabulär, omvandla dokument till räknevektorer och använda TF-IDF-viktning för att minska vikten för vanliga ord.

Lektion 2 av 413 steg

Bag of Words: CountVectorizer och TfidfVectorizer är en gratis lektion i Machine Learning Academy på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Machine Learning Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Machine Learning Academy innehåller totalt 4 lektioner.

Problemet med att omvandla text till tal

Maskininlärningsmodeller kräver numeriska indata, men text är i grunden ostrukturerad. För att omvandla textdokument till ett format som en modell kan förstå krävs ett systematiskt tillvägagångssätt. Bag of Words-modellen (BoW) är den enklaste och mest använda metoden: den behandlar ett dokument som en oordnad samling ord, ignorerar grammatik och ordföljd och räknar hur många gånger varje ord förekommer. Resultatet är en numerisk vektor — ett tal per ord i vokabulären. Trots sin enkelhet är BoW förvånansvärt effektiv för textklassificering, skräppostfiltrering och sentimentanalys.

# Bag of Words: ignore order, just count words
doc1 = 'the cat sat on the mat'
doc2 = 'the cat ate the rat'

# Vocabulary: all unique words across documents
vocab = sorted(set(doc1.split() + doc2.split()))
print('Vocabulary:', vocab)

# Count vectors
vec1 = [doc1.split().count(w) for w in vocab]
vec2 = [doc2.split().count(w) for w in vocab]
print('doc1 vector:', vec1)
print('doc2 vector:', vec2)

CountVectorizer: skapa vokabulären

Scikit-learns CountVectorizer automatiserar processen för Bag of Words. Den: (1) tokeniserar varje dokument genom att dela upp det vid blanksteg och skiljetecken, (2) bygger en vokabulär från alla unika token som hittas under fit(), och (3) omvandlar varje dokument till en gles vektor med ordräkningar. Resultatet är en dokument-term-matris där raderna är dokument och kolumnerna är ord i vokabulären. Gles representation används eftersom de flesta ord bara förekommer i en liten andel av dokumenten — de flesta poster är noll.

from sklearn.feature_extraction.text import CountVectorizer

corpus = [
    'I love Python and machine learning',
    'Machine learning is awesome',
    'Python is great for data science',
    'I hate bugs in Python code'
]

vec = CountVectorizer()
X = vec.fit_transform(corpus)  # Returns sparse matrix

print('Vocabulary size:', len(vec.vocabulary_))
print('Matrix shape:', X.shape)  # (4 docs, N vocabulary words)
print('Vocabulary:', sorted(vec.vocabulary_.keys()))

Glesa matriser och minneseffektivitet

CountVectorizer returnerar en gles matris eftersom de flesta ordräkningar är noll — ett dokument om Python nämner inte ”elefant” eller ”galax”. Att lagra alla nollor skulle slösa enorma mängder minne. En gles matris lagrar endast värden som inte är noll och deras positioner. För en vokabulär med 100 000 ord och 10 000 dokument skulle den fullständiga matrisen vara 8 GB; den glesa versionen kanske bara 50 MB. Behåll alltid textfunktionsmatriser i glesa format tills du är säker på att efterföljande operationer stöder det — en konvertering till tät form kan tömma minnet för stora textkorpusar.

from sklearn.feature_extraction.text import CountVectorizer
from scipy.sparse import issparse
import numpy as np

corpus = ['Python is great', 'Machine learning rocks', 'Data science rules']
vec = CountVectorizer()
X_sparse = vec.fit_transform(corpus)

print('Is sparse:', issparse(X_sparse))        # True
print('Shape:', X_sparse.shape)
print('Non-zero entries:', X_sparse.nnz)       # Only non-zero values stored
print('Density:', X_sparse.nnz / np.prod(X_sparse.shape))  # Very low

# Dense (RAM-expensive for large corpora)
X_dense = X_sparse.toarray()
print('Dense shape:', X_dense.shape)

Förbehandling: stoppord, gemener och n-gram

CountVectorizer erbjuder inbyggda alternativ för textförbehandling. lowercase=True (standard) säkerställer att ”Python” och ”python” är samma token. stop_words='english' tar bort vanliga ord som ”the”, ”is” och ”a”, vilka tillför liten betydelse. ngram_range=(1,2) inkluderar både enskilda ord (unigram) och på varandra följande ordpar (bigram), vilket fångar fraser som ”not good” som en unigrammodell annars skulle misstolka som ”not” och ”good” var för sig. Bigram förbättrar klassificeringskvaliteten avsevärt vid sentimentanalys där negationer spelar roll.

from sklearn.feature_extraction.text import CountVectorizer

corpus = ['not good at all', 'very good movie', 'bad experience']

# Unigrams only (default)
uni_vec = CountVectorizer(stop_words='english')
print('Unigram features:', uni_vec.fit(corpus).get_feature_names_out())

# Bigrams too
bigram_vec = CountVectorizer(ngram_range=(1,2), stop_words='english')
bigram_features = bigram_vec.fit(corpus).get_feature_names_out()
print('Unigram+Bigram features:', bigram_features)
# 'not good' appears as a bigram -- captures negation

Problemet med råa räkningar: vanliga ord

Råa ordräkningar har en grundläggande brist: mycket vanliga ord dominerar vektorn trots att de innehåller lite särskiljande information. Ordet ”the” kan förekomma 50 gånger i en nyhetsartikel utan att säga något om artikelns ämne. Däremot antyder en sällsynt fackterm som ”eigenvalue”, som bara förekommer två gånger, starkt att dokumentet handlar om matematik. TF-IDF (Term Frequency-Inverse Document Frequency) hanterar detta genom att minska vikten för ord som förekommer i många dokument och öka vikten för ord som förekommer i få dokument men ofta i det aktuella dokumentet.

from sklearn.feature_extraction.text import CountVectorizer
import numpy as np

corpus = [
    'the cat sat on the mat the cat is fat',
    'the eigenvalue decomposition is powerful math'
]

vec = CountVectorizer()
X = vec.fit_transform(corpus).toarray()
features = vec.get_feature_names_out()

for i, doc in enumerate(corpus[:1]):
    counts = sorted(zip(features, X[i]), key=lambda x: -x[1])
    print('Top words by count in doc 1:')
    for word, count in counts[:5]:
        print(f'  {word}: {count}')
# 'the' dominates even though it is meaningless

TF-IDF: termfrekvens och invers dokumentfrekvens

TF-IDF justerar ordens betydelse utifrån två faktorer: Term Frequency (TF) — hur ofta ordet förekommer i det här dokumentet (lokalt viktigt), och Inverse Document Frequency (IDF) — logaritmen av kvoten mellan det totala antalet dokument och antalet dokument som innehåller ordet (globalt sällsynt = mer särskiljande). TF-IDF(w, d) = TF(w,d) * IDF(w) där IDF(w) = log((N+1)/(df+1)) + 1 (scikit-learn använder utjämnad IDF). Ett ord som bara förekommer i 1 av 1000 dokument har mycket högt IDF; ett ord som förekommer i alla dokument har ett IDF nära 0.

import numpy as np

# Manual TF-IDF
documents = [
    'cat sat mat cat',   # 'cat' appears twice here
    'dog ran park',
    'cat dog park'
]

N = len(documents)  # 3 documents

# IDF for 'cat': appears in documents 0 and 2 (df=2)
df_cat = 2
idf_cat = np.log((N + 1) / (df_cat + 1)) + 1

# TF for 'cat' in doc0: 2 out of 4 words
tf_cat_doc0 = 2 / 4

tfidf_cat_doc0 = tf_cat_doc0 * idf_cat
print(f'TF-IDF(cat, doc0) = {tfidf_cat_doc0:.4f}')

TfidfVectorizer: textomvandling i ett steg

TfidfVectorizer kombinerar tokenisering, vektorisering av ordräkningar och TF-IDF-viktning i en enda transformerare. Den tillämpar L2-normalisering som standard, så att varje dokumentvektor har enhetslängd — vilket gör dokument med olika längd jämförbara. Resultatet är fortfarande en gles matris. TfidfVectorizer ger nästan alltid bättre resultat än CountVectorizer vid textklassificeringsuppgifter, särskilt när korpusen innehåller dokument med varierande längd eller när vanliga stoppord inte har tagits bort uttryckligen.

from sklearn.feature_extraction.text import TfidfVectorizer

corpus = [
    'I love Python and machine learning',
    'Machine learning is awesome',
    'Python is great for data science',
    'I hate bugs in Python code'
]

tfidf = TfidfVectorizer(stop_words='english', max_features=20)
X = tfidf.fit_transform(corpus)

print('Shape:', X.shape)
print('Features:', tfidf.get_feature_names_out())

# Inspect TF-IDF weights for document 0
import numpy as np
weights = zip(tfidf.get_feature_names_out(), X.toarray()[0])
for word, weight in sorted(weights, key=lambda x: -x[1])[:5]:
    print(f'  {word}: {weight:.4f}')

Parametrarna max_features och vocabulary

För stora korpusar med miljontals dokument kan vokabulären växa till hundratusentals termer. max_features=N behåller endast de N vanligaste orden, vilket minskar minnesanvändningen och snabbar upp träningen. min_df ignorerar ord som förekommer i färre än så här många dokument (tar bort mycket sällsynta termer som kan vara stavfel eller unika identifierare). max_df ignorerar ord som förekommer i mer än så här stor andel av dokumenten (tar bort inofficiella stoppord som förekommer överallt). Typiska produktionsinställningar: max_features=50,000, min_df=5, max_df=0.95.

from sklearn.feature_extraction.text import TfidfVectorizer

corpus = ['...']  # assume large corpus

tfidf = TfidfVectorizer(
    max_features=50000,   # Top 50k words by frequency
    min_df=5,            # Ignore words in fewer than 5 documents
    max_df=0.95,         # Ignore words in more than 95% of docs
    ngram_range=(1, 2),  # Include bigrams
    stop_words='english',
    sublinear_tf=True    # Replace TF with 1+log(TF) to dampen outliers
)

print('CountVectorizer vs TfidfVectorizer settings configured')
print('sublinear_tf=True: dampens high-frequency words further')

CountVectorizer jämfört med TfidfVectorizer: när ska de användas?

Använd CountVectorizer när: (1) modellen redan hanterar frekvensviktning internt (t.ex. förväntar sig Multinomial Naive Bayes råa räkningar), eller (2) dokumentlängden är enhetlig och frekvensskillnaderna är meningsfulla. Använd TfidfVectorizer när: (1) dokumenten varierar i längd, (2) vanliga ord inte filtreras bort som stoppord, eller (3) du använder algoritmer som förutsätter normaliserade funktionsvektorer (SVM, logistisk regression). För Naive Bayes specifikt fungerar CountVectorizer med MultinomialNB ofta bäst. För SVM eller logistisk regression är TfidfVectorizer standardvalet.

from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.model_selection import cross_val_score

corpus = ['spam message buy now', 'hello friend how are you',
          'click here to buy', 'good morning everyone']
labels = [1, 0, 1, 0]  # 1=spam, 0=ham

# Naive Bayes: works well with CountVectorizer
nb_pipe = Pipeline([('vec', CountVectorizer()), ('clf', MultinomialNB())])

# Logistic regression: works better with TF-IDF
lr_pipe = Pipeline([('vec', TfidfVectorizer()), ('clf', LogisticRegression())])

print('CountVectorizer + MultinomialNB: standard for text Naive Bayes')
print('TfidfVectorizer + LogisticRegression: standard for text linear models')

Granska dokument-term-matrisen

Efter vektoriseringen kan du granska dokument-term-matrisen för att förstå vad som har lärts in. Om du omvandlar den till en Pandas DataFrame med funktionsnamn som kolumnrubriker blir det enkelt att se hur varje ord representeras. Detta felsökningssteg är viktigt: det visar om tokeniseringen fungerade korrekt, om stoppord togs bort, om vokabulären fångade de förväntade termerna och om TF-IDF-vikterna verkar rimliga. Granska alltid ett urval av matrisen innan du tränar modellen, så att du upptäcker fel i förbehandlingen tidigt.

from sklearn.feature_extraction.text import TfidfVectorizer
import pandas as pd

corpus = [
    'Python machine learning tutorial',
    'Deep learning neural networks',
    'Python data analysis pandas numpy'
]

tfidf = TfidfVectorizer()
X = tfidf.fit_transform(corpus)

# Convert to DataFrame for inspection
df = pd.DataFrame(
    X.toarray(),
    columns=tfidf.get_feature_names_out()
)

print('Document-Term Matrix (TF-IDF weights):')
print(df.to_string())

Teckennivåbaserade n-gram för robust tokenisering

Tokenisering på ordnivå fungerar sämre när texten innehåller stavfel, förkortningar eller morfologiska varianter. Teckennivåbaserade n-gram behandlar överlappande sekvenser av tecken som egenskaper i stället för hela ord. Om du anger analyzer='char_wb' i TfidfVectorizer tillsammans med ngram_range=(3,5) genereras delsträngar på 3 till 5 tecken med ordgränser. Det gör modellen robust mot felstavningar och flerspråkig text. Det är särskilt användbart för språkidentifiering, författarskapsanalys och text från sociala medier där stavningen är inkonsekvent. Teckennivåbaserade n-gram är också grunden för subword-tokenisering som används i transformermodeller som BERT.

from sklearn.feature_extraction.text import TfidfVectorizer

corpus = [
    'python programming language',
    'pythn programmng (typo)',  # Misspellings
    'java programming'
]

# Word-level (default): typos create unseen tokens
word_vec = TfidfVectorizer(analyzer='word')
word_features = word_vec.fit(corpus).get_feature_names_out()
print('Word features:', word_features)

# Character n-gram: handles typos gracefully
char_vec = TfidfVectorizer(analyzer='char_wb', ngram_range=(3, 4))
X_char = char_vec.fit_transform(corpus)
print('Char n-gram features:', len(char_vec.get_feature_names_out()), 'total')
print('Typos share substrings with correct words -> similar vectors')

Snabbtest

Testa dina kunskaper om begrepp inom Machine Learning med Python från den här lektionen.

Lektionssammanfattning

I den här lektionen har du lärt dig att Bag of Words omvandlar text till vektorer med ordräkningar med hjälp av CountVectorizer, att TF-IDF minskar vikten för vanliga ord och ökar vikten för särskiljande sällsynta ord med hjälp av TfidfVectorizer, samt viktiga parametrar för förbehandling, bland annat stop_words, ngram_range, max_features och min_df. Nästa steg är att träna en Multinomial Naive Bayes-klassificerare på textdata.

Gratis att börja

Lär dig Python med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
30
Lektioner
120

Vanliga frågor

Är lektionen ”Bag of Words: CountVectorizer och TfidfVectorizer” gratis?

Ja – hela texten till ”Bag of Words: CountVectorizer och TfidfVectorizer” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Machine Learning Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i Machine Learning Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Bag of Words: CountVectorizer och TfidfVectorizer”?

Ni kommer att tokenisera text, bygga ett vokabulär, omvandla dokument till räknevektorer och använda TF-IDF-viktning för att minska vikten för vanliga ord. Ni övar på Machine Learning Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig Machine Learning Academy?

Du behöver inga förkunskaper. Utbildningen i Machine Learning Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.

Hur lång tid tar lektionen ”Bag of Words: CountVectorizer och TfidfVectorizer”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här Machine Learning Academy-lektionen?

Ja. Varje Machine Learning Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Bayes sats på klarspråk
  2. Bag of Words: CountVectorizer och TfidfVectorizer
  3. Träna en multinomial Naive Bayes-klassificerare
  4. Laplace-utjämning och problemet med nollsannolikheter
← Tillbaka till Machine Learning Academy