Методы анализа больших данных (Syllabus) 2025/Lesson ML
Материал из Поле цифровой дидактики
- Урок по анализу данных с использованием методов машинного обучения
Диаграмма 1

Диаграмма 2

Диаграмма процесса очистки текста

Процесс получения данных
library(httr)
library(jsonlite)
library(xml2)
library(tidyverse)
library(quanteda)
# Установка дополнительных пакетов
library(stopwords)
library(stringr)
###########
get_wikipedia_category_members <- function(category_name, language = "ru") {
# Базовый URL API
base_url <- paste0("https://", language, ".wikipedia.org/w/api.php")
all_members <- data.frame()
continue_token <- NULL
repeat {
# Формируем параметры запроса
params <- list(
action = "query",
list = "categorymembers",
cmtitle = paste0("Category:", category_name),
cmlimit = 500, # Максимум результатов за раз
format = "json",
cmtype = "page", # Только статьи, не категории
cmcontinue = continue_token
)
# Выполняем запрос
response <- GET(base_url, query = params)
# Проверяем статус ответа
if (status_code(response) != 200) {
warning("Ошибка при запросе к API: статус ", status_code(response))
break
}
# Парсим JSON
data <- fromJSON(content(response, as = "text", encoding = "UTF-8"))
# Извлекаем члены категории
if (!is.null(data$query$categorymembers)) {
members <- data$query$categorymembers %>%
as_tibble() %>%
select(pageid, title)
all_members <- bind_rows(all_members, members)
}
# Проверяем, есть ли продолжение запроса
if (is.null(data$`query-continue`$categorymembers$cmcontinue)) {
break
}
continue_token <- data$`query-continue`$categorymembers$cmcontinue
}
return(all_members)
}
iot_articles <- get_wikipedia_category_members("Интернет вещей")
cat("Найдено статей:", nrow(iot_articles), "\n")
head(iot_articles)
######################
get_wikipedia_text <- function(article_title, language = "ru") {
base_url <- paste0("https://", language, ".wikipedia.org/w/api.php")
params <- list(
action = "query",
titles = article_title,
prop = "extracts",
explaintext = TRUE, # Получаем чистый текст без Wiki-разметки
format = "json"
)
response <- GET(base_url, query = params)
if (status_code(response) != 200) {
return(NA)
}
data <- fromJSON(content(response, as = "text", encoding = "UTF-8"))
# Извлекаем текст из ответа
pages <- data$query$pages
page_id <- names(pages)[1]
if (!is.null(pages[[page_id]]$extract)) {
return(pages[[page_id]]$extract)
} else {
return(NA)
}
}
# Сбираем тексты для всех найденных статей
# Добавляем задержку между запросами, чтобы не перегружать сервер
collected_texts <- tibble(
title = character(),
text = character()
)
for (i in seq_len(min(nrow(iot_articles), 50))) { # Возьмём первые 50 статей для примера
if (i %% 10 == 0) {
cat("Обработано статей:", i, "\n")
}
article_title <- iot_articles$title[i]
article_text <- get_wikipedia_text(article_title)
if (!is.na(article_text)) {
collected_texts <- add_row(collected_texts,
title = article_title,
text = article_text)
}
# Задержка между запросами (500 мс)
Sys.sleep(0.5)
}
cat("Успешно получено текстов:", nrow(collected_texts), "\n")
###########################
# Функция для предварительной очистки текста
preprocess_text <- function(text) {
# Приведение к нижнему регистру
text <- tolower(text)
# Удаление URL
text <- str_remove_all(text, "https?://[^\\s]+")
# Удаление специальных символов, но сохраняем буквы и пробелы
text <- str_remove_all(text, "[^а-яА-Яa-zA-Z\\s]")
# Удаление множественных пробелов
text <- str_squish(text)
return(text)
}
# Применяем предварительную очистку
cleaned_texts <- collected_texts %>%
mutate(
cleaned_text = map_chr(text, preprocess_text)
)
head(cleaned_texts$cleaned_text, 1)
### Работа с пакетом quanteda
# Создание корпуса
corpus_texts <- corpus(cleaned_texts,
docid_field = "title",
text_field = "cleaned_text")
cat("Корпус создан. Документов:", ndoc(corpus_texts), "\n")
cat("Токенов:", ntoken(corpus_texts), "\n")
# Токенизация текста
tokens_data <- tokens(corpus_texts,
remove_punct = TRUE,
remove_numbers = TRUE,
remove_separators = TRUE)
# Приведение к нижнему регистру
tokens_data <- tokens_tolower(tokens_data)
# Получение русских стоп-слов
russian_stopwords <- stopwords("russian")
# Удаление стоп-слов
tokens_clean <- tokens_select(tokens_data,
pattern = russian_stopwords,
selection = "remove",
min_nchar = 3) # Удаляем слова короче 3 символов
# Стемминг (приведение к корню слова)
tokens_stemmed <- tokens_wordstem(tokens_clean, language = "russian")
cat("Размер словаря после очистки:", ntype(tokens_stemmed), "\n")
# Создание матрицы документ-термин
dtm <- dfm(tokens_stemmed)
cat("Размеры DTM: ", nrow(dtm), " документов, ", ncol(dtm), " термов\n", sep = "")
# Просмотр структуры
head(dtm)
# Топ-10 самых частых слов
topfeatures(dtm, 10)
# Фильтрация редких слов
# Оставляем слова, которые встречаются минимум в 2 документах
# и имеют минимум 5 вхождений в корпусе
dtm_trimmed <- dfm_trim(dtm,
min_docfreq = 2, # мин. документы
min_termfreq = 5) # мин. вхождения
cat("Размеры отфильтрованной DTM: ", nrow(dtm_trimmed), " документов, ",
ncol(dtm_trimmed), " термов\n", sep = "")
# Вычисление TF-IDF (Term Frequency-Inverse Document Frequency)
dtm_tfidf <- dfm_tfidf(dtm_trimmed)
cat("TF-IDF матрица готова\n")
### Статистика текстов
# Получение статистики корпуса
corpus_stats <- tokens_data %>%
ntoken() %>%
tibble(doc_id = names(.), n_tokens = .)
# Визуализация статистики
library(ggplot2)
ggplot(corpus_stats, aes(x = n_tokens)) +
geom_histogram(bins = 20, fill = "steelblue", color = "black") +
labs(title = "Распределение количества токенов в документах",
x = "Количество токенов",
y = "Количество документов") +
theme_minimal()
# Средняя длина документа
cat("Средняя длина документа:", mean(corpus_stats$n_tokens), "токенов\n")
