Đây là một ví dụ cho thấy cách API scikit-learning có thể được sử dụng để phân cụm tài liệu theo chủ đề bằng cách sử dụng phương pháp Bag of Words Show
Hai thuật toán được demo. và biến thể có khả năng mở rộng hơn của nó,. Ngoài ra, phân tích ngữ nghĩa tiềm ẩn được sử dụng để giảm kích thước và khám phá các mẫu tiềm ẩn trong dữ liệu Ví dụ này sử dụng hai trình vector hóa văn bản khác nhau. một và một. Xem sổ ghi chép ví dụ để biết thêm thông tin về vectorizers và so sánh thời gian xử lý của chúng Để phân tích tài liệu thông qua phương pháp học có giám sát, hãy xem tập lệnh ví dụ # Author: Peter Prettenhofer <[email protected]> # Lars Buitinck # Olivier Grisel <[email protected]> # Arturo Amor <[email protected]> # License: BSD 3 clause Đang tải dữ liệu văn bảnChúng tôi tải dữ liệu từ , bao gồm khoảng 18.000 bài đăng trong nhóm tin về 20 chủ đề. Với mục đích minh họa và để giảm chi phí tính toán, chúng tôi chọn một tập hợp con gồm 4 chủ đề chỉ chiếm khoảng 3.400 tài liệu. Xem ví dụ để có được trực giác về sự chồng chéo của các chủ đề đó Lưu ý rằng, theo mặc định, các mẫu văn bản chứa một số siêu dữ liệu của tin nhắn, chẳng hạn như from collections import defaultdict from sklearn import metrics from time import time evaluations = [] evaluations_std = [] def fit_and_evaluate(km, X, name=None, n_runs=5): name = km.__class__.__name__ if name is None else name train_times = [] scores = defaultdict(list) for seed in range(n_runs): km.set_params(random_state=seed) t0 = time() km.fit(X) train_times.append(time() - t0) scores["Homogeneity"].append(metrics.homogeneity_score(labels, km.labels_)) scores["Completeness"].append(metrics.completeness_score(labels, km.labels_)) scores["V-measure"].append(metrics.v_measure_score(labels, km.labels_)) scores["Adjusted Rand-Index"].append( metrics.adjusted_rand_score(labels, km.labels_) ) scores["Silhouette Coefficient"].append( metrics.silhouette_score(X, km.labels_, sample_size=2000) ) train_times = np.asarray(train_times) print(f"clustering done in {train_times.mean():.2f} ± {train_times.std():.2f} s ") evaluation = { "estimator": name, "train_time": train_times.mean(), } evaluation_std = { "estimator": name, "train_time": train_times.std(), } for score_name, score_values in scores.items(): mean_score, std_score = np.mean(score_values), np.std(score_values) print(f"{score_name}: {mean_score:.3f} ± {std_score:.3f}") evaluation[score_name] = mean_score evaluation_std[score_name] = std_score evaluations.append(evaluation) evaluations_std.append(evaluation_std)1, from collections import defaultdict from sklearn import metrics from time import time evaluations = [] evaluations_std = [] def fit_and_evaluate(km, X, name=None, n_runs=5): name = km.__class__.__name__ if name is None else name train_times = [] scores = defaultdict(list) for seed in range(n_runs): km.set_params(random_state=seed) t0 = time() km.fit(X) train_times.append(time() - t0) scores["Homogeneity"].append(metrics.homogeneity_score(labels, km.labels_)) scores["Completeness"].append(metrics.completeness_score(labels, km.labels_)) scores["V-measure"].append(metrics.v_measure_score(labels, km.labels_)) scores["Adjusted Rand-Index"].append( metrics.adjusted_rand_score(labels, km.labels_) ) scores["Silhouette Coefficient"].append( metrics.silhouette_score(X, km.labels_, sample_size=2000) ) train_times = np.asarray(train_times) print(f"clustering done in {train_times.mean():.2f} ± {train_times.std():.2f} s ") evaluation = { "estimator": name, "train_time": train_times.mean(), } evaluation_std = { "estimator": name, "train_time": train_times.std(), } for score_name, score_values in scores.items(): mean_score, std_score = np.mean(score_values), np.std(score_values) print(f"{score_name}: {mean_score:.3f} ± {std_score:.3f}") evaluation[score_name] = mean_score evaluation_std[score_name] = std_score evaluations.append(evaluation) evaluations_std.append(evaluation_std)2 (chữ ký) và from collections import defaultdict from sklearn import metrics from time import time evaluations = [] evaluations_std = [] def fit_and_evaluate(km, X, name=None, n_runs=5): name = km.__class__.__name__ if name is None else name train_times = [] scores = defaultdict(list) for seed in range(n_runs): km.set_params(random_state=seed) t0 = time() km.fit(X) train_times.append(time() - t0) scores["Homogeneity"].append(metrics.homogeneity_score(labels, km.labels_)) scores["Completeness"].append(metrics.completeness_score(labels, km.labels_)) scores["V-measure"].append(metrics.v_measure_score(labels, km.labels_)) scores["Adjusted Rand-Index"].append( metrics.adjusted_rand_score(labels, km.labels_) ) scores["Silhouette Coefficient"].append( metrics.silhouette_score(X, km.labels_, sample_size=2000) ) train_times = np.asarray(train_times) print(f"clustering done in {train_times.mean():.2f} ± {train_times.std():.2f} s ") evaluation = { "estimator": name, "train_time": train_times.mean(), } evaluation_std = { "estimator": name, "train_time": train_times.std(), } for score_name, score_values in scores.items(): mean_score, std_score = np.mean(score_values), np.std(score_values) print(f"{score_name}: {mean_score:.3f} ± {std_score:.3f}") evaluation[score_name] = mean_score evaluation_std[score_name] = std_score evaluations.append(evaluation) evaluations_std.append(evaluation_std)3 cho các bài đăng khác. Chúng tôi sử dụng tham số from collections import defaultdict from sklearn import metrics from time import time evaluations = [] evaluations_std = [] def fit_and_evaluate(km, X, name=None, n_runs=5): name = km.__class__.__name__ if name is None else name train_times = [] scores = defaultdict(list) for seed in range(n_runs): km.set_params(random_state=seed) t0 = time() km.fit(X) train_times.append(time() - t0) scores["Homogeneity"].append(metrics.homogeneity_score(labels, km.labels_)) scores["Completeness"].append(metrics.completeness_score(labels, km.labels_)) scores["V-measure"].append(metrics.v_measure_score(labels, km.labels_)) scores["Adjusted Rand-Index"].append( metrics.adjusted_rand_score(labels, km.labels_) ) scores["Silhouette Coefficient"].append( metrics.silhouette_score(X, km.labels_, sample_size=2000) ) train_times = np.asarray(train_times) print(f"clustering done in {train_times.mean():.2f} ± {train_times.std():.2f} s ") evaluation = { "estimator": name, "train_time": train_times.mean(), } evaluation_std = { "estimator": name, "train_time": train_times.std(), } for score_name, score_values in scores.items(): mean_score, std_score = np.mean(score_values), np.std(score_values) print(f"{score_name}: {mean_score:.3f} ± {std_score:.3f}") evaluation[score_name] = mean_score evaluation_std[score_name] = std_score evaluations.append(evaluation) evaluations_std.append(evaluation_std)4 để loại bỏ các tính năng đó và có vấn đề phân cụm hợp lý hơn import numpy as np from sklearn.datasets import fetch_20newsgroups categories = [ "alt.atheism", "talk.religion.misc", "comp.graphics", "sci.space", ] dataset = fetch_20newsgroups( remove=("headers", "footers", "quotes"), subset="all", categories=categories, shuffle=True, random_state=42, ) labels = dataset.target unique_labels, category_sizes = np.unique(labels, return_counts=True) true_k = unique_labels.shape[0] print(f"{len(dataset.data)} documents - {true_k} categories") 3387 documents - 4 categories Định lượng chất lượng của kết quả phân cụmTrong phần này, chúng tôi xác định một chức năng để chấm điểm các quy trình phân cụm khác nhau bằng cách sử dụng một số chỉ số Các thuật toán phân cụm về cơ bản là các phương pháp học tập không giám sát. Tuy nhiên, vì chúng tôi tình cờ có nhãn lớp cho tập dữ liệu cụ thể này, nên có thể sử dụng các chỉ số đánh giá tận dụng thông tin sự thật cơ bản “được giám sát” này để định lượng chất lượng của các cụm kết quả. Ví dụ về các số liệu như vậy là như sau
Nếu không biết nhãn sự thật cơ bản, việc đánh giá chỉ có thể được thực hiện bằng chính kết quả của mô hình. Trong trường hợp đó, Hệ số Silhouette có ích Để tham khảo thêm, xem from collections import defaultdict from sklearn import metrics from time import time evaluations = [] evaluations_std = [] def fit_and_evaluate(km, X, name=None, n_runs=5): name = km.__class__.__name__ if name is None else name train_times = [] scores = defaultdict(list) for seed in range(n_runs): km.set_params(random_state=seed) t0 = time() km.fit(X) train_times.append(time() - t0) scores["Homogeneity"].append(metrics.homogeneity_score(labels, km.labels_)) scores["Completeness"].append(metrics.completeness_score(labels, km.labels_)) scores["V-measure"].append(metrics.v_measure_score(labels, km.labels_)) scores["Adjusted Rand-Index"].append( metrics.adjusted_rand_score(labels, km.labels_) ) scores["Silhouette Coefficient"].append( metrics.silhouette_score(X, km.labels_, sample_size=2000) ) train_times = np.asarray(train_times) print(f"clustering done in {train_times.mean():.2f} ± {train_times.std():.2f} s ") evaluation = { "estimator": name, "train_time": train_times.mean(), } evaluation_std = { "estimator": name, "train_time": train_times.std(), } for score_name, score_values in scores.items(): mean_score, std_score = np.mean(score_values), np.std(score_values) print(f"{score_name}: {mean_score:.3f} ± {std_score:.3f}") evaluation[score_name] = mean_score evaluation_std[score_name] = std_score evaluations.append(evaluation) evaluations_std.append(evaluation_std) K-nghĩa là phân cụm trên các tính năng văn bảnHai phương pháp trích xuất tính năng được sử dụng trong ví dụ này
Hơn nữa, có thể xử lý hậu kỳ các tính năng được trích xuất đó bằng cách giảm kích thước. Chúng ta sẽ khám phá tác động của những lựa chọn đó đối với chất lượng phân cụm trong phần sau Trích xuất tính năng bằng TfidfVectorizerTrước tiên, chúng tôi đánh giá các công cụ ước tính bằng cách sử dụng trình tạo véc tơ từ điển cùng với chuẩn hóa IDF như được cung cấp bởi ________số 8_______ vectorization done in 0.444 s n_samples: 3387, n_features: 7929 Sau khi bỏ qua các thuật ngữ xuất hiện trong hơn 50% tài liệu (do from collections import defaultdict from sklearn import metrics from time import time evaluations = [] evaluations_std = [] def fit_and_evaluate(km, X, name=None, n_runs=5): name = km.__class__.__name__ if name is None else name train_times = [] scores = defaultdict(list) for seed in range(n_runs): km.set_params(random_state=seed) t0 = time() km.fit(X) train_times.append(time() - t0) scores["Homogeneity"].append(metrics.homogeneity_score(labels, km.labels_)) scores["Completeness"].append(metrics.completeness_score(labels, km.labels_)) scores["V-measure"].append(metrics.v_measure_score(labels, km.labels_)) scores["Adjusted Rand-Index"].append( metrics.adjusted_rand_score(labels, km.labels_) ) scores["Silhouette Coefficient"].append( metrics.silhouette_score(X, km.labels_, sample_size=2000) ) train_times = np.asarray(train_times) print(f"clustering done in {train_times.mean():.2f} ± {train_times.std():.2f} s ") evaluation = { "estimator": name, "train_time": train_times.mean(), } evaluation_std = { "estimator": name, "train_time": train_times.std(), } for score_name, score_values in scores.items(): mean_score, std_score = np.mean(score_values), np.std(score_values) print(f"{score_name}: {mean_score:.3f} ± {std_score:.3f}") evaluation[score_name] = mean_score evaluation_std[score_name] = std_score evaluations.append(evaluation) evaluations_std.append(evaluation_std)9 đặt) và các thuật ngữ không có trong ít nhất 5 tài liệu (do from sklearn.feature_extraction.text import TfidfVectorizer vectorizer = TfidfVectorizer( max_df=0.5, min_df=5, stop_words="english", ) t0 = time() X_tfidf = vectorizer.fit_transform(dataset.data) print(f"vectorization done in {time() - t0:.3f} s") print(f"n_samples: {X_tfidf.shape[0]}, n_features: {X_tfidf.shape[1]}")0 đặt), số lượng thuật ngữ duy nhất from sklearn.feature_extraction.text import TfidfVectorizer vectorizer = TfidfVectorizer( max_df=0.5, min_df=5, stop_words="english", ) t0 = time() X_tfidf = vectorizer.fit_transform(dataset.data) print(f"vectorization done in {time() - t0:.3f} s") print(f"n_samples: {X_tfidf.shape[0]}, n_features: {X_tfidf.shape[1]}")1 thu được là khoảng 8.000. Ngoài ra, chúng ta có thể định lượng độ thưa thớt của ma trận from sklearn.feature_extraction.text import TfidfVectorizer vectorizer = TfidfVectorizer( max_df=0.5, min_df=5, stop_words="english", ) t0 = time() X_tfidf = vectorizer.fit_transform(dataset.data) print(f"vectorization done in {time() - t0:.3f} s") print(f"n_samples: {X_tfidf.shape[0]}, n_features: {X_tfidf.shape[1]}")2 dưới dạng phần của các mục nhập khác 0 được chia cho tổng số phần tử print(f"{X_tfidf.nnz / np.prod(X_tfidf.shape):.3f}") 0.007 Chúng tôi thấy rằng khoảng 0. 7% mục nhập của ma trận from sklearn.feature_extraction.text import TfidfVectorizer vectorizer = TfidfVectorizer( max_df=0.5, min_df=5, stop_words="english", ) t0 = time() X_tfidf = vectorizer.fit_transform(dataset.data) print(f"vectorization done in {time() - t0:.3f} s") print(f"n_samples: {X_tfidf.shape[0]}, n_features: {X_tfidf.shape[1]}")2 là khác không Phân cụm dữ liệu thưa thớt với phương tiện kVì cả hai và tối ưu hóa một hàm mục tiêu không lồi, việc phân cụm của chúng không được đảm bảo là tối ưu cho một init ngẫu nhiên nhất định. Hơn nữa, trên dữ liệu chiều cao thưa thớt, chẳng hạn như văn bản được vector hóa bằng cách sử dụng phương pháp Bag of Words, k-mean có thể khởi tạo trọng tâm trên các điểm dữ liệu cực kỳ biệt lập. Những điểm dữ liệu đó có thể luôn là trọng tâm của riêng chúng Đoạn mã sau minh họa hiện tượng trước đó đôi khi có thể dẫn đến các cụm mất cân bằng cao như thế nào, tùy thuộc vào việc khởi tạo ngẫu nhiên from sklearn.cluster import KMeans for seed in range(5): kmeans = KMeans( n_clusters=true_k, max_iter=100, n_init=1, random_state=seed, ).fit(X_tfidf) cluster_ids, cluster_sizes = np.unique(kmeans.labels_, return_counts=True) print(f"Number of elements asigned to each cluster: {cluster_sizes}") print() print( "True number of documents in each category according to the class labels: " f"{category_sizes}" ) Number of elements asigned to each cluster: [ 1 1 3384 1] Number of elements asigned to each cluster: [1733 717 238 699] Number of elements asigned to each cluster: [1115 256 1417 599] Number of elements asigned to each cluster: [1695 649 446 597] Number of elements asigned to each cluster: [ 254 2117 459 557] True number of documents in each category according to the class labels: [799 973 987 628] Để tránh vấn đề này, một khả năng là tăng số lần chạy với các khởi tạo ngẫu nhiên độc lập from sklearn.feature_extraction.text import TfidfVectorizer vectorizer = TfidfVectorizer( max_df=0.5, min_df=5, stop_words="english", ) t0 = time() X_tfidf = vectorizer.fit_transform(dataset.data) print(f"vectorization done in {time() - t0:.3f} s") print(f"n_samples: {X_tfidf.shape[0]}, n_features: {X_tfidf.shape[1]}")6. Trong trường hợp như vậy, việc phân cụm có quán tính tốt nhất (hàm mục tiêu của phương tiện k) được chọn import numpy as np from sklearn.datasets import fetch_20newsgroups categories = [ "alt.atheism", "talk.religion.misc", "comp.graphics", "sci.space", ] dataset = fetch_20newsgroups( remove=("headers", "footers", "quotes"), subset="all", categories=categories, shuffle=True, random_state=42, ) labels = dataset.target unique_labels, category_sizes = np.unique(labels, return_counts=True) true_k = unique_labels.shape[0] print(f"{len(dataset.data)} documents - {true_k} categories")0 import numpy as np from sklearn.datasets import fetch_20newsgroups categories = [ "alt.atheism", "talk.religion.misc", "comp.graphics", "sci.space", ] dataset = fetch_20newsgroups( remove=("headers", "footers", "quotes"), subset="all", categories=categories, shuffle=True, random_state=42, ) labels = dataset.target unique_labels, category_sizes = np.unique(labels, return_counts=True) true_k = unique_labels.shape[0] print(f"{len(dataset.data)} documents - {true_k} categories")1 Tất cả các số liệu đánh giá phân cụm đó có giá trị tối đa là 1. 0 (để có kết quả phân cụm hoàn hảo). Giá trị cao hơn là tốt hơn. Các giá trị của Chỉ số Rand đã điều chỉnh gần bằng 0. 0 tương ứng với một nhãn ngẫu nhiên. Lưu ý từ các điểm số ở trên rằng việc phân công cụm thực sự cao hơn mức cơ hội, nhưng chất lượng tổng thể chắc chắn có thể cải thiện Hãy nhớ rằng các nhãn lớp có thể không phản ánh chính xác các chủ đề tài liệu và do đó, các chỉ số sử dụng nhãn không nhất thiết là tốt nhất để đánh giá chất lượng của quy trình phân cụm của chúng tôi Thực hiện giảm kích thước bằng LSAMột from sklearn.feature_extraction.text import TfidfVectorizer vectorizer = TfidfVectorizer( max_df=0.5, min_df=5, stop_words="english", ) t0 = time() X_tfidf = vectorizer.fit_transform(dataset.data) print(f"vectorization done in {time() - t0:.3f} s") print(f"n_samples: {X_tfidf.shape[0]}, n_features: {X_tfidf.shape[1]}")7 vẫn có thể được sử dụng miễn là kích thước của không gian được véc tơ hóa trước tiên được giảm để làm cho phương tiện k ổn định hơn. Với mục đích như vậy, chúng tôi sử dụng , hoạt động trên ma trận số lượng thuật ngữ/tf-idf. Do kết quả SVD không được chuẩn hóa nên chúng tôi thực hiện lại quá trình chuẩn hóa để cải thiện kết quả. Sử dụng SVD để giảm kích thước của vectơ tài liệu TF-IDF thường được gọi là phân tích ngữ nghĩa tiềm ẩn (LSA) trong tài liệu khai thác văn bản và truy xuất thông tin import numpy as np from sklearn.datasets import fetch_20newsgroups categories = [ "alt.atheism", "talk.religion.misc", "comp.graphics", "sci.space", ] dataset = fetch_20newsgroups( remove=("headers", "footers", "quotes"), subset="all", categories=categories, shuffle=True, random_state=42, ) labels = dataset.target unique_labels, category_sizes = np.unique(labels, return_counts=True) true_k = unique_labels.shape[0] print(f"{len(dataset.data)} documents - {true_k} categories")2 import numpy as np from sklearn.datasets import fetch_20newsgroups categories = [ "alt.atheism", "talk.religion.misc", "comp.graphics", "sci.space", ] dataset = fetch_20newsgroups( remove=("headers", "footers", "quotes"), subset="all", categories=categories, shuffle=True, random_state=42, ) labels = dataset.target unique_labels, category_sizes = np.unique(labels, return_counts=True) true_k = unique_labels.shape[0] print(f"{len(dataset.data)} documents - {true_k} categories")3 Sử dụng một lần khởi tạo duy nhất có nghĩa là thời gian xử lý sẽ giảm cho cả hai và import numpy as np from sklearn.datasets import fetch_20newsgroups categories = [ "alt.atheism", "talk.religion.misc", "comp.graphics", "sci.space", ] dataset = fetch_20newsgroups( remove=("headers", "footers", "quotes"), subset="all", categories=categories, shuffle=True, random_state=42, ) labels = dataset.target unique_labels, category_sizes = np.unique(labels, return_counts=True) true_k = unique_labels.shape[0] print(f"{len(dataset.data)} documents - {true_k} categories")4 import numpy as np from sklearn.datasets import fetch_20newsgroups categories = [ "alt.atheism", "talk.religion.misc", "comp.graphics", "sci.space", ] dataset = fetch_20newsgroups( remove=("headers", "footers", "quotes"), subset="all", categories=categories, shuffle=True, random_state=42, ) labels = dataset.target unique_labels, category_sizes = np.unique(labels, return_counts=True) true_k = unique_labels.shape[0] print(f"{len(dataset.data)} documents - {true_k} categories")5 Chúng ta có thể quan sát thấy rằng việc phân cụm trên biểu diễn LSA của tài liệu nhanh hơn đáng kể (cả vì from sklearn.feature_extraction.text import TfidfVectorizer vectorizer = TfidfVectorizer( max_df=0.5, min_df=5, stop_words="english", ) t0 = time() X_tfidf = vectorizer.fit_transform(dataset.data) print(f"vectorization done in {time() - t0:.3f} s") print(f"n_samples: {X_tfidf.shape[0]}, n_features: {X_tfidf.shape[1]}")7 và vì kích thước của không gian đặc trưng LSA nhỏ hơn nhiều). Hơn nữa, tất cả các số liệu đánh giá phân cụm đã được cải thiện. Chúng tôi lặp lại thí nghiệm với import numpy as np from sklearn.datasets import fetch_20newsgroups categories = [ "alt.atheism", "talk.religion.misc", "comp.graphics", "sci.space", ] dataset = fetch_20newsgroups( remove=("headers", "footers", "quotes"), subset="all", categories=categories, shuffle=True, random_state=42, ) labels = dataset.target unique_labels, category_sizes = np.unique(labels, return_counts=True) true_k = unique_labels.shape[0] print(f"{len(dataset.data)} documents - {true_k} categories")6 import numpy as np from sklearn.datasets import fetch_20newsgroups categories = [ "alt.atheism", "talk.religion.misc", "comp.graphics", "sci.space", ] dataset = fetch_20newsgroups( remove=("headers", "footers", "quotes"), subset="all", categories=categories, shuffle=True, random_state=42, ) labels = dataset.target unique_labels, category_sizes = np.unique(labels, return_counts=True) true_k = unique_labels.shape[0] print(f"{len(dataset.data)} documents - {true_k} categories")7 Thuật ngữ hàng đầu trên mỗi cụmVì có thể đảo ngược, chúng tôi có thể xác định các trung tâm cụm, cung cấp trực giác về các từ có ảnh hưởng nhất cho mỗi cụm. Xem tập lệnh ví dụ để so sánh với các từ dễ đoán nhất cho từng lớp mục tiêu import numpy as np from sklearn.datasets import fetch_20newsgroups categories = [ "alt.atheism", "talk.religion.misc", "comp.graphics", "sci.space", ] dataset = fetch_20newsgroups( remove=("headers", "footers", "quotes"), subset="all", categories=categories, shuffle=True, random_state=42, ) labels = dataset.target unique_labels, category_sizes = np.unique(labels, return_counts=True) true_k = unique_labels.shape[0] print(f"{len(dataset.data)} documents - {true_k} categories")8 import numpy as np from sklearn.datasets import fetch_20newsgroups categories = [ "alt.atheism", "talk.religion.misc", "comp.graphics", "sci.space", ] dataset = fetch_20newsgroups( remove=("headers", "footers", "quotes"), subset="all", categories=categories, shuffle=True, random_state=42, ) labels = dataset.target unique_labels, category_sizes = np.unique(labels, return_counts=True) true_k = unique_labels.shape[0] print(f"{len(dataset.data)} documents - {true_k} categories")9 BămVectorizerMột vector hóa thay thế có thể được thực hiện bằng cách sử dụng một thể hiện, không cung cấp trọng số IDF vì đây là một mô hình không trạng thái (phương thức phù hợp không làm gì cả). Khi cần trọng số IDF, nó có thể được thêm vào bằng cách chuyển đầu ra thành một thể hiện. Trong trường hợp này, chúng tôi cũng thêm LSA vào đường ống để giảm kích thước và độ thưa thớt của không gian vectơ được băm 3387 documents - 4 categories0 3387 documents - 4 categories1 Người ta có thể quan sát rằng bước LSA mất một thời gian tương đối dài để phù hợp, đặc biệt là với các vectơ băm. Lý do là một không gian băm thường lớn (được đặt thành vectorization done in 0.444 s n_samples: 3387, n_features: 79298 trong ví dụ này). Người ta có thể thử giảm số lượng tính năng với chi phí có phần lớn hơn các tính năng có xung đột băm như trong sổ ghi chép ví dụ Bây giờ chúng tôi điều chỉnh và đánh giá các trường hợp vectorization done in 0.444 s n_samples: 3387, n_features: 79299 và print(f"{X_tfidf.nnz / np.prod(X_tfidf.shape):.3f}")0 trên dữ liệu đã được băm-lsa-reduced này 3387 documents - 4 categories2 3387 documents - 4 categories3 3387 documents - 4 categories4 3387 documents - 4 categories5 Cả hai phương pháp đều dẫn đến kết quả tốt tương tự như chạy cùng một mô hình trên các vectơ LSA truyền thống (không băm) Tóm tắt đánh giá phân cụm3387 documents - 4 categories6 và mắc phải hiện tượng được gọi là Lời nguyền của chiều đối với các bộ dữ liệu chiều cao như dữ liệu văn bản. Đó là lý do tại sao điểm tổng cải thiện khi sử dụng LSA. Sử dụng LSA giảm dữ liệu cũng cải thiện độ ổn định và yêu cầu thời gian phân cụm thấp hơn, mặc dù vậy, hãy nhớ rằng bản thân bước LSA mất nhiều thời gian, đặc biệt là với các vectơ được băm Hệ số Silhouette được xác định trong khoảng từ 0 đến 1. Trong mọi trường hợp, chúng tôi nhận được các giá trị gần bằng 0 (ngay cả khi chúng cải thiện một chút sau khi sử dụng LSA) vì định nghĩa của nó yêu cầu đo khoảng cách, trái ngược với các số liệu đánh giá khác như thước đo V và Chỉ số Rand được điều chỉnh chỉ dựa trên cụm . Lưu ý rằng nói đúng ra, người ta không nên so sánh Hệ số Hình bóng giữa các không gian có kích thước khác nhau, do các khái niệm khác nhau về khoảng cách mà chúng ngụ ý Tính đồng nhất, tính đầy đủ và do đó số liệu đo lường v không mang lại cơ sở liên quan đến ghi nhãn ngẫu nhiên. điều này có nghĩa là tùy thuộc vào số lượng mẫu, cụm và lớp chân lý cơ bản, việc ghi nhãn hoàn toàn ngẫu nhiên sẽ không phải lúc nào cũng mang lại các giá trị giống nhau. Cụ thể, việc ghi nhãn ngẫu nhiên sẽ không mang lại điểm 0, đặc biệt khi số lượng cụm lớn. Vấn đề này có thể được bỏ qua một cách an toàn khi số lượng mẫu lớn hơn một nghìn và số lượng cụm nhỏ hơn 10, đó là trường hợp của ví dụ hiện tại. Đối với cỡ mẫu nhỏ hơn hoặc số lượng cụm lớn hơn, sẽ an toàn hơn khi sử dụng chỉ số được điều chỉnh, chẳng hạn như Chỉ số Rand được điều chỉnh (ARI). Xem ví dụ về bản trình diễn về tác dụng của việc ghi nhãn ngẫu nhiên Kích thước của các thanh lỗi cho thấy nó kém ổn định hơn so với tập dữ liệu tương đối nhỏ này. Sẽ thú vị hơn khi sử dụng khi số lượng mẫu lớn hơn nhiều, nhưng nó có thể phải trả giá bằng sự suy giảm nhỏ về chất lượng phân cụm so với thuật toán k-means truyền thống |