Добро пожаловать в пятую часть нашей серии статей о кластеризации текста! Ранее мы рассмотрели генерацию признаков, EDA, LDA для тематических распределений и кластеризацию K-средних. Теперь мы углубляемся в иерархическую кластеризацию, альтернативный метод группировки нашего набора данных из 150 текстов песен в 15 жанрах.
После применения предварительной обработки LDA наша цель состоит в том, чтобы сгруппировать тексты песен на основе сходства. Иерархическая кластеризация позволяет нам исследовать уникальную древовидную структуру, визуализируя отношения между кластерами. В этом посте мы объясним его методологию и применим ее к нашему предварительно обработанному набору данных. Давайте начнем!
Краткий обзор иерархической кластеризации
Иерархическая кластеризация группирует похожие точки данных в древовидную иерархию. Например, учитывая данные о марафонцах с указанием возраста, пола, времени финиша и часов тренировок, этот метод может группировать бегунов со схожими характеристиками. Группируя бегунов с одинаковыми характеристиками, формируется иерархическая структура, объединяющая меньшие группы в более крупные.
Модуль Scipy cluster.hierarchy
обеспечивает иерархическую кластеризацию и визуализацию дендрограммы, помогая анализировать такие данные, как производительность 2000 марафонцев. Код для примера немного длинный, поэтому я покажу здесь только основные моменты, вы можете найти полный код в репозитории GitHub поста в блоге.
# Step 2: Calculate distances axes[1].set_title('Calculate Distances') dendrogram(Z, truncate_mode='level', p=3, show_leaf_counts=True, ax=axes[1], no_labels=True) axes[1].set_xlabel('Calculate Pairwise Distances') axes[1].set_ylabel('Distance') # Steps 3-5: Find closest clusters, merge, update distances axes[2].set_title('Find Closest Clusters, Merge, Update Distances') dendrogram(Z, truncate_mode='level', p=5, show_leaf_counts=True, ax=axes[2], no_labels=True) axes[2].axhline(y=max_d, color='r', linestyle='--') axes[2].set_xlabel('Find, Merge, Update') axes[2].set_ylabel('Distance') # Step 6: Repeat Steps 3-5 axes[3].set_title('Repeat Steps 3-5') dendrogram(Z, truncate_mode='level', p=8, show_leaf_counts=True, ax=axes[3], no_labels=True) axes[3].axhline(y=max_d, color='r', linestyle='--') axes[3].set_xlabel('Repeat Process') axes[3].set_ylabel('Distance') # Step 7: Build a dendrogram axes[4].set_title('Build a Dendrogram') dendrogram(Z, truncate_mode='level', p=10, show_leaf_counts=True, ax=axes[4], no_labels=True) axes[4].axhline(y=max_d, color='r', linestyle='--') axes[4].set_xlabel('Build Dendrogram') axes[4].set_ylabel('Distance')
Этот код визуализирует процесс иерархической кластеризации с помощью дендрограмм. На шаге 2 рассчитываются попарные расстояния между кластерами и строится дендрограмма для представления этих расстояний.
Шаги 3–5 включают поиск ближайших кластеров, их объединение и обновление расстояний. Дендрограмма обновляется для отображения новой структуры после каждой итерации.
На шаге 6 шаги 3–5 повторяются до тех пор, пока все кластеры не будут объединены, создавая окончательную дендрограмму. Дендрограмма визуально представляет иерархию кластеров и порядок их слияния, обеспечивая понимание процесса кластеризации и взаимосвязей между точками данных.
ПРИМЕНЕНИЕ ЭТОГО К НАШИМ ЛИРИКАМ
# Vectorize the text data using CountVectorizer vectorizer = CountVectorizer(stop_words='english', max_df=0.95, min_df=2) dtm = vectorizer.fit_transform(song_lyrics) # Perform LDA for topic modeling n_topics = 5 lda = LatentDirichletAllocation(n_components=n_topics, random_state=42) lda.fit(dtm) # Get the topic distributions for each song topic_dist = lda.transform(dtm) # Apply hierarchical clustering to the topic distributions Z = linkage(topic_dist, method='ward') # Get the cluster assignments and visualize the final clustering result max_d = 2 # A chosen distance threshold for clustering clusters = fcluster(Z, max_d, criterion='distance')
Этот код предназначен для подготовки текстов песен к кластеризации. Во-первых, он преобразует текстовые данные в числовую форму, используя CountVectorizer
. Он удаляет распространенные английские стоп-слова и сохраняет только слова, которые встречаются как минимум в 2 песнях, но не более чем в 95% из них. Затем он использует LDA, чтобы найти 5 основных тем в текстах песен. После подгонки LDA к числовым данным мы получаем тематические распределения для каждой песни. Иерархическая кластеризация (с использованием метода Уорда) применяется к групповым песням на основе сходства их тем. Наконец, мы определяем пороговое значение расстояния, чтобы разрезать древовидную структуру, что приводит к назначению кластеров для каждой песни.
# Visualize the dendrogram fig, ax = plt.subplots(figsize=(12, 6)) dendrogram(Z, truncate_mode='level', p=3, show_leaf_counts=True, ax=ax) ax.set_xlabel('Song index') ax.set_ylabel('Distance') ax.set_title('Hierarchical Clustering Dendrogram') plt.show()
Дендрограмма создается с использованием матрицы связей Z
с усечением дерева на 12 уровнях. Красная пунктирная линия указывает выбранный порог расстояния max_d
для кластеризации.
Песни на кластер
# Count songs per cluster n_clusters = np.unique(clusters).size song_counts_per_cluster = np.bincount(clusters) # Set up the figure fig, ax = plt.subplots(figsize=(8, 6)) # Define colors for the clusters colors = plt.cm.viridis(np.linspace(0, 1, n_clusters)) # Plot the histogram of song counts per cluster for i, count in enumerate(song_counts_per_cluster[1:], 1): ax.bar(i, count, color=colors[i-1]) ax.text(i, count, str(count), ha='center', va='bottom') ax.set_xlabel('Cluster') ax.set_ylabel('Song Count') ax.set_title('Histogram of Song Counts per Cluster') # Show the plot plt.tight_layout() plt.show()
Этот код вычисляет количество уникальных кластеров в данных и подсчитывает песни в каждом кластере. Затем он создает гистограмму для визуализации количества песен в кластере, где каждый кластер представлен полосой разного цвета. Код также добавляет количество песен в виде текста над каждой полосой, что упрощает интерпретацию данных.
# Display the topics in a wordcloud chart n_words = 10 feature_names = vectorizer.get_feature_names_out() for topic_idx, topic in enumerate(lda.components_): print(f'Topic #{topic_idx + 1}:') top_words = [feature_names[i] for i in topic.argsort()[-n_words:]] wc = WordCloud(width=400, height=400, background_color='white', colormap='viridis') wc.generate_from_frequencies({word: topic[word_idx] for word_idx, word in enumerate(top_words)}) plt.figure() plt.imshow(wc, interpolation='bilinear') plt.axis('off') plt.show()