0Pricing
R Academy · درس

نمذجة الموضوعات باستخدام LDA

اكتشف الموضوعات الكامنة في مجموعات المستندات باستخدام حزمة topicmodels

نمذجة الموضوعات باستخدام LDA درس مجاني في R Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في R Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة R Academy 4 دروس في المجموع.

ما هي نمذجة الموضوعات؟

نمذجة الموضوعات هي تقنية تعلّم آلي غير خاضعة للإشراف تكتشف البنية الموضوعية الكامنة في مجموعة نصوص. تفترض Latent Dirichlet Allocation (LDA) أن كل مستند مزيج من K موضوعات، وأن كل موضوع توزيع احتمالي للكلمات.

# 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 من tm

يتطلب LDA مصفوفة المستند-المصطلح (DTM): تمثل الصفوف المستندات، وتمثل الأعمدة الكلمات، بينما تمثل الخلايا أعداد الكلمات. تنتج الدالة DocumentTermMatrix() في حزمة tm أو الدالة cast_dtm() في tidytext هذا التنسيق.

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 من tidytext

تحوّل cast_dtm(document, term, value) tibble منظّمًا يحتوي على أعداد الكلمات مباشرةً إلى DocumentTermMatrix المتوافق مع حزمة topicmodels. ويحافظ ذلك على أسلوب 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): ملاءمة النموذج

تُلائم LDA(dtm, k = K, control = list(seed = 42)) نموذج LDA ذي K موضوعات باستخدام أخذ عينات Gibbs أو VEM. احرص دائمًا على ضبط قيمة seed لضمان قابلية إعادة الإنتاج — إذ إن LDA عشوائي، وقد تختلف النتائج بين عمليات التشغيل من دون بذرة ثابتة.

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'): احتمالات الموضوعات لكل كلمة

تستخرج tidy(lda_model, matrix = 'beta') احتمالات الموضوعات لكل كلمة (مصفوفة beta). يوضح كل صف احتمال أن تكون كلمة محددة قد وُلّدت بواسطة موضوع محدد. وتحدد الكلمات ذات الاحتمالات العالية موضوع كل موضوع.

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)

تصوير كلمات الموضوعات

مثّل أعلى N كلمة لكل موضوع في مخطط أعمدة مقسّم إلى أوجه. رتّب الكلمات داخل كل موضوع حسب قيمة beta باستخدام reorder_within() وscale_x_reordered() من tidytext، لضمان الترتيب المستقل الصحيح لكل وجه.

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'): احتمالات الموضوعات لكل مستند

تستخرج tidy(lda_model, matrix = 'gamma') احتمالات الموضوعات لكل مستند (مصفوفة gamma). يوضح كل صف النسبة المقدّرة من المستند المنسوبة إلى موضوع محدد. وتكون المستندات ذات قيمة gamma العالية للموضوع 2 متعلقةً بالموضوع 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))

اختيار K: عدد الموضوعات

يتطلب LDA تحديد K مسبقًا. ومن الأساليب الشائعة: (1) مقياس perplexity — الأقل أفضل، لكنه ينخفض رتيبًا مع زيادة K؛ (2) درجة التماسك (من حزمة ldatuning)؛ (3) المعرفة بالمجال؛ (4) تجربة K = 5 و10 و20 وفحص قوائم الكلمات يدويًا.

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')

تسمية الموضوعات

ينتج LDA موضوعات مجهّلة (1 و2 و3…). ويجب على المحلل البشري تسمية كل موضوع من خلال فحص كلماته الأبرز. أنشئ جدول بحث يربط أرقام الموضوعات بأسماء وصفية، ثم اربطه بنتائجك.

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 على مجموعة نصوص مخصّصة

إليك مسارًا متكاملًا من البداية إلى النهاية لتطبيق LDA على مجموعة نصوص مخصّصة: تقسيم النص إلى رموز، وبناء DTM، وملاءمة LDA، واستخراج مصفوفة beta، وعرض الكلمات الأبرز لكل موضوع.

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()

قيود LDA

يفترض LDA نموذج حقيبة الكلمات (أي إن ترتيب الكلمات لا يهم)، وأن الموضوعات ثابتة عبر مجموعة النصوص، وأنه يجب اختيار K مسبقًا. بالنسبة إلى الموضوعات الديناميكية أو الهرمية، فكّر في STM (Structural Topic Model) أو CTM (Correlated Topic Model) المتاحين في حزمة 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)

تحقّق سريع

في LDA، ماذا تمثّل مصفوفة beta؟

مراجعة: نمذجة الموضوعات باستخدام LDA

أهم النقاط:

  • يكتشف LDA عدد K من الموضوعات الكامنة بوصفها توزيعات للكلمات انطلاقًا من مصفوفة المستند-المصطلح
  • أنشئ DTM باستخدام cast_dtm(document, word, n) (tidytext) أو DocumentTermMatrix() (tm)
  • تُلائم LDA(dtm, k = K, control = list(seed = 42)) النموذج
  • tidy(lda, 'beta') = احتمالات الموضوعات لكل كلمة (ما يحدد كل موضوع)
  • tidy(lda, 'gamma') = نسب الموضوعات لكل مستند (موضوع كل مستند)
  • استخدم مقاييس perplexity أو التماسك للمساعدة في اختيار K
  • افحص دائمًا الكلمات الأبرز يدويًا لتسمية الموضوعات
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()

الأسئلة الشائعة

هل درس «نمذجة الموضوعات باستخدام LDA» مجاني؟

نعم — نص درس «نمذجة الموضوعات باستخدام LDA» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة R Academy، انتقل إلى CoddyKit PRO. تتضمن دورة R Academy 4 دروس في المجموع.

ماذا ستتعلم في «نمذجة الموضوعات باستخدام LDA»؟

اكتشف الموضوعات الكامنة في مجموعات المستندات باستخدام حزمة topicmodels تتمرن على R Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ R Academy؟

لا تُشترط خبرة سابقة. R Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «نمذجة الموضوعات باستخدام LDA»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس R Academy هذا؟

نعم. كل درس في R Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تجزئة النص وإزالة كلمات التوقف
  2. تحليل TF-IDF وتكرار المصطلحات
  3. تحليل المشاعر في R
  4. نمذجة الموضوعات باستخدام LDA
← العودة إلى R Academy