R Academy · Lekcja

Modelowanie tematów za pomocą LDA

Odkrywaj ukryte tematy w korpusach dokumentów za pomocą pakietu topicmodels.

Lekcja 4 z 413 kroki

Modelowanie tematów za pomocą LDA to bezpłatna lekcja R Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej R Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs R Academy zawiera 4 lekcji w sumie.

Czym jest modelowanie tematów

Modelowanie tematów to nienadzorowana technika uczenia maszynowego, która odkrywa ukrytą strukturę tematyczną w korpusie. Latent Dirichlet Allocation (LDA) zakłada, że każdy dokument jest mieszaniną K tematów, a każdy temat jest rozkładem prawdopodobieństwa słów.

# LDA key assumptions:
# 1. Each document is a mixture of K topics
# 2. Each topic is a distribution over all vocabulary words
# 3. Words are generated by first picking a topic, then a word from that topic

# Example: K=2 topics in a corpus about tech and cooking
# Topic 1 (Tech):    neural(0.15) python(0.12) algorithm(0.10) ...
# Topic 2 (Cooking): recipe(0.14) flour(0.11) bake(0.10) ...

# A document about 'AI-generated recipes' might be:
# 70% Topic 1 (Tech) + 30% Topic 2 (Cooking)

cat('LDA parameters:\n')
cat('K = number of topics (you choose)\n')
cat('alpha = document-topic sparsity prior\n')
cat('beta  = topic-word sparsity prior\n')

DocumentTermMatrix z pakietu tm

LDA wymaga macierzy dokument–termin (DTM): wiersze reprezentują dokumenty, kolumny — słowa, a komórki zawierają liczbę wystąpień słów. Funkcja DocumentTermMatrix() z pakietu tm oraz funkcja cast_dtm() z pakietu tidytext tworzą dane w tym formacie.

library(tm)

# Build a corpus from raw text
docs <- c(
  'machine learning neural networks training algorithms',
  'deep learning gradient backpropagation optimizer',
  'python scikit numpy pandas machine learning',
  'database sql tables indexes queries joins',
  'relational schema normalization foreign primary',
  'nosql mongodb document store redis queries'
)

corpus <- Corpus(VectorSource(docs))
corpus <- tm_map(corpus, removePunctuation)
corpus <- tm_map(corpus, removeWords, stopwords('english'))
corpus <- tm_map(corpus, stripWhitespace)

dtm <- DocumentTermMatrix(corpus)
cat('DTM shape:', nrow(dtm), 'docs x', ncol(dtm), 'terms\n')
cat('Sparsity: ', round(tm::sparsity(dtm) * 100, 1), '%\n')

cast_dtm z pakietu tidytext

cast_dtm(document, term, value) bezpośrednio konwertuje uporządkowany tibble z licznościami słów do obiektu DocumentTermMatrix zgodnego z pakietem topicmodels. Dzięki temu cały pipeline zachowuje styl tidyverse.

library(tidytext)
library(dplyr)

# Tidy corpus
corpus <- tibble::tibble(
  doc_id = c(rep(1, 3), rep(2, 3), rep(3, 3), rep(4, 3)),
  text   = c(
    'neural networks deep learning training',
    'gradient descent backpropagation optimizer',
    'machine learning algorithms classification',
    'database sql tables queries indexes',
    'relational schema normalization joins',
    'foreign primary key constraints transactions',
    'recipe bake flour butter oven',
    'cooking temperature simmer saute ingredients',
    'kitchen knife herbs spices garnish'
  )
)

dtm <- corpus |>
  unnest_tokens(word, text) |>
  anti_join(tidytext::stop_words, by = 'word') |>
  count(doc_id, word) |>
  cast_dtm(doc_id, word, n)

cat('DTM:', nrow(dtm), 'docs x', ncol(dtm), 'terms\n')

LDA(dtm, k = 5): dopasowywanie modelu

LDA(dtm, k = K, control = list(seed = 42)) dopasowuje model LDA z K tematami, korzystając z próbkowania Gibbsa lub VEM. Zawsze ustawiaj seed, aby zapewnić powtarzalność — LDA jest algorytmem stochastycznym, dlatego bez ustalonego ziarna wyniki różnią się między uruchomieniami.

library(tidytext)
library(dplyr)
library(topicmodels)

# Build DTM
corpus <- tibble::tibble(
  doc_id = c(rep(1,3), rep(2,3), rep(3,3), rep(4,3), rep(5,3), rep(6,3)),
  text = c(
    'neural networks deep gradient','backpropagation training optimizer','learning model layers',
    'database sql queries indexes','relational tables joins foreign','schema normalization constraints',
    'recipe flour bake butter','cooking temperature oven simmer','kitchen knife herbs spices'
  )[rep(c(1,2,3,4,5,6), each=1)]
)

dtm <- corpus |>
  unnest_tokens(word, text) |>
  count(doc_id, word) |>
  cast_dtm(doc_id, word, n)

# Fit LDA with k=3 topics
lda_model <- LDA(dtm, k = 3, control = list(seed = 42))
cat('LDA model fitted: k=3 topics\n')
cat('Class:', class(lda_model), '\n')

tidy(lda, matrix = 'beta'): prawdopodobieństwa tematów dla poszczególnych słów

tidy(lda_model, matrix = 'beta') wyodrębnia prawdopodobieństwa tematów dla poszczególnych słów (macierz beta). Każdy wiersz podaje prawdopodobieństwo, że dane słowo zostało wygenerowane przez określony temat. Słowa o wysokim prawdopodobieństwie definiują, czego dotyczy dany temat.

library(topicmodels)
library(tidytext)
library(dplyr)

# Using the built-in AssociatedPress dataset
data('AssociatedPress', package = 'topicmodels')

lda <- LDA(AssociatedPress[1:50, ], k = 4, control = list(seed = 1234))

# Per-word topic probabilities (beta)
beta_tbl <- tidy(lda, matrix = 'beta')
cat('Beta matrix rows:', nrow(beta_tbl), '\n')
cat('Columns:', names(beta_tbl), '\n')

# Top words per topic
top_terms <- beta_tbl |>
  group_by(topic) |>
  slice_max(beta, n = 5) |>
  ungroup()

cat('\nTop 5 words per topic:\n')
print(top_terms)

Wizualizacja słów tematów

Przedstaw N najczęstszych słów dla każdego tematu na fasetowym wykresie słupkowym. Posortuj słowa w obrębie każdego tematu według wartości beta za pomocą reorder_within() i scale_x_reordered() z pakietu tidytext, aby uzyskać niezależne, poprawne sortowanie dla każdej fasety.

library(topicmodels)
library(tidytext)
library(dplyr)
library(ggplot2)

data('AssociatedPress', package = 'topicmodels')
lda <- LDA(AssociatedPress[1:100, ], k = 4, control = list(seed = 42))

tidy(lda, matrix = 'beta') |>
  group_by(topic) |>
  slice_max(beta, n = 8) |>
  ungroup() |>
  mutate(term = reorder_within(term, beta, topic)) |>
  ggplot(aes(term, beta, fill = factor(topic))) +
    geom_col(show.legend = FALSE) +
    facet_wrap(~topic, scales = 'free') +
    scale_x_reordered() +
    coord_flip() +
    labs(x = NULL, y = 'Beta', title = 'Top Words per LDA Topic') +
    theme_minimal(base_size = 10)

tidy(lda, matrix = 'gamma'): prawdopodobieństwa tematów dla poszczególnych dokumentów

tidy(lda_model, matrix = 'gamma') wyodrębnia prawdopodobieństwa tematów dla poszczególnych dokumentów (macierz gamma). Każdy wiersz podaje oszacowany udział danego tematu w dokumencie. Dokumenty z wysoką wartością gamma dla tematu 2 dotyczą w dużej mierze tematu 2.

library(topicmodels)
library(tidytext)
library(dplyr)

data('AssociatedPress', package = 'topicmodels')
lda <- LDA(AssociatedPress[1:30, ], k = 3, control = list(seed = 99))

# Per-document topic proportions (gamma)
gamma_tbl <- tidy(lda, matrix = 'gamma')
cat('Gamma matrix rows:', nrow(gamma_tbl), '\n')

# Dominant topic per document
dominant_topic <- gamma_tbl |>
  group_by(document) |>
  slice_max(gamma, n = 1) |>
  ungroup()

cat('\nDominant topic per document (first 8):\n')
print(head(dominant_topic, 8))

Wybór K: liczba tematów

LDA wymaga wcześniejszego określenia wartości K. Typowe podejścia to: (1) perplexity — niższa wartość jest lepsza, ale maleje monotonicznie wraz ze wzrostem K; (2) miara spójności (pakiet ldatuning); (3) wiedza dziedzinowa; (4) wypróbowanie wartości K = 5, 10, 20 i ręczne przejrzenie list słów.

library(topicmodels)
library(tidytext)

data('AssociatedPress', package = 'topicmodels')

# Evaluate perplexity for K = 2, 3, 4, 5
k_values <- 2:5
perplexities <- vapply(k_values, function(k) {
  model <- LDA(AssociatedPress[1:50, ], k = k,
               control = list(seed = 42))
  perplexity(model)
}, numeric(1))

results <- data.frame(k = k_values, perplexity = round(perplexities, 1))
cat('Perplexity by K:\n')
print(results)
cat('\nNote: lower perplexity = better fit to training data\n')

Nadawanie nazw tematom

LDA tworzy anonimowe tematy (1, 2, 3…). Analityk musi nadać każdemu tematowi nazwę, analizując jego najczęstsze słowa. Utwórz tabelę pomocniczą mapującą numery tematów na opisowe nazwy, a następnie dołącz ją do wyników.

library(topicmodels)
library(tidytext)
library(dplyr)

data('AssociatedPress', package = 'topicmodels')
lda <- LDA(AssociatedPress[1:100, ], k = 4, control = list(seed = 7))

# Top 5 words per topic for manual labelling
tidy(lda, matrix = 'beta') |>
  group_by(topic) |>
  slice_max(beta, n = 5) |>
  summarise(top_words = paste(term, collapse = ', ')) |>
  print()

# After inspecting top words, assign human-readable labels
topic_labels <- tibble::tibble(
  topic = 1:4,
  label = c('Politics', 'Economy', 'Sports', 'Science')  # your interpretation
)

cat('\nTopic labels assigned (example):\n')
print(topic_labels)

LDA dla niestandardowego korpusu

Oto kompletny pipeline LDA od początku do końca dla niestandardowego korpusu: tokenizacja, zbudowanie DTM, dopasowanie LDA, wyodrębnienie macierzy beta i wyświetlenie najczęstszych słów dla każdego tematu.

library(tidytext)
library(dplyr)
library(topicmodels)

# 9 documents across 3 latent topics
docs <- tibble::tibble(
  id   = 1:9,
  text = c(
    'machine learning neural deep training',
    'algorithm gradient backpropagation network',
    'python tensorflow keras model layers',
    'database sql relational tables queries',
    'joins indexes schema foreign primary',
    'transactions normalization constraints',
    'recipe ingredients bake flour butter',
    'cooking temperature simmer oven saute',
    'kitchen knife herbs spices garnish'
  )
)

dtm <- docs |>
  unnest_tokens(word, text) |>
  count(id, word) |>
  cast_dtm(id, word, n)

lda <- LDA(dtm, k = 3, control = list(seed = 123))

tidy(lda, 'beta') |>
  group_by(topic) |>
  slice_max(beta, n = 4) |>
  summarise(words = paste(term, collapse = ', ')) |>
  print()

Ograniczenia LDA

LDA zakłada model worka słów (kolejność słów nie ma znaczenia), przyjmuje, że tematy są stałe w całym korpusie, a wartość K trzeba wybrać z wyprzedzeniem. W przypadku tematów dynamicznych lub hierarchicznych rozważ STM (Structural Topic Model) albo CTM (Correlated Topic Model), dostępne w pakiecie stm.

# LDA assumptions and limitations
limitations <- data.frame(
  Assumption = c(
    'Bag of words', 'Fixed K', 'Topic independence',
    'Static topics', 'No metadata'
  ),
  Alternative = c(
    'word2vec / BERT',
    'ldatuning for K selection',
    'CTM (Correlated Topic Model)',
    'DTM (Dynamic Topic Model)',
    'STM (Structural Topic Model)'
  )
)

print(limitations, row.names = FALSE)

Szybkie sprawdzenie

Co w modelu LDA przedstawia macierz beta?

Podsumowanie: modelowanie tematów za pomocą LDA

Najważniejsze informacje:

  • LDA odkrywa K ukrytych tematów jako rozkłady słów na podstawie macierzy dokument–termin
  • Zbuduj DTM za pomocą cast_dtm(document, word, n) (tidytext) lub DocumentTermMatrix() (tm)
  • LDA(dtm, k = K, control = list(seed = 42)) dopasowuje model
  • tidy(lda, 'beta') = prawdopodobieństwa tematów dla poszczególnych słów (to, co definiuje każdy temat)
  • tidy(lda, 'gamma') = proporcje tematów dla poszczególnych dokumentów (to, czego dotyczy każdy dokument)
  • Używaj miar perplexity lub spójności, aby pomóc w wyborze K
  • Zawsze ręcznie analizuj najczęstsze słowa, aby nadać tematom nazwy
library(topicmodels)
library(tidytext)
library(dplyr)

data('AssociatedPress', package = 'topicmodels')
lda <- LDA(AssociatedPress[1:20, ], k = 2, control = list(seed = 1))

tidy(lda, 'beta') |>
  group_by(topic) |>
  slice_max(beta, n = 3) |>
  summarise(top_words = paste(term, collapse = ', ')) |>
  print()
Bezpłatny start

Ucz się R dzięki korepetycjom AI — za darmo

Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.

Kursy
43
Lekcje
159

Często zadawane pytania

Czy lekcja „Modelowanie tematów za pomocą LDA” jest bezpłatna?

Tak — pełny tekst „Modelowanie tematów za pomocą LDA” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu R Academy, przejdź na CoddyKit PRO. Kurs R Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Modelowanie tematów za pomocą LDA”?

Odkrywaj ukryte tematy w korpusach dokumentów za pomocą pakietu topicmodels. Ćwiczysz R Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć R Academy?

Nie wymagamy żadnego doświadczenia. R Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „Modelowanie tematów za pomocą LDA”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji R Academy?

Tak. Każda lekcja R Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Tokenizacja i usuwanie słów pustych
  2. TF-IDF i analiza częstości terminów
  3. Analiza sentymentu w R
  4. Modelowanie tematów za pomocą LDA
← Powrót do R Academy