def score_clusters(collection): """ Считает среднeвзвешенные оценки для каждого кластера :param collection: :return: """ db = connect_to_db() cluster_db = db[collection] logging.info('Database connected') clusters_pd = download_collection(collection) logging.info('Clusters downloaded') for topic_idx in clusters_pd.index: total_views = sum([db.dereference(lecture)['views'] for lecture in clusters_pd.loc[topic_idx, 'lectures']]) logging.info('\tTotal views for {} topic counted'.format(topic_idx)) score_result = defaultdict(float) for lecture in clusters_pd.loc[topic_idx, 'lectures']: lec_id = db.dereference(lecture)['_id'] scores = db.dereference(lecture)['scores'] views = db.dereference(lecture)['views'] for key in scores: score_result[key] += scores[key] * views logging.info('\t\t Lecture {} in topic {} counted'.format(lec_id, topic_idx)) for key in score_result: score_result[key] /= total_views logging.info("\t'{:^12}' score in topic {} normalized".format(key, topic_idx)) cluster_db.update({'_id': int(topic_idx)}, {'$set': {'scores': dict(score_result)}}) logging.info('Topic {} dumped to db'.format(topic_idx))
def lda_cluster_text(alpha: float, docs_topics: pd.DataFrame, dumb_to_db=True): """ Формирует кластеры и записывает их в базу данных :param alpha: Порог :param docs_topics: Вероятностное распределение документов по темам :param dumb_to_db: :return: """ clusters = defaultdict(list) topics_docs = docs_topics.T logging.info('Docs_topics transposed') for i in topics_docs.index: for col in topics_docs.columns: if topics_docs.loc[i, col] >= alpha: clusters[int(i)].append(int(col)) logging.info('Clusters created') if dumb_to_db: lda_topics = connect_to_db()['lda_clusters'] lda_topics.drop() logging.info('lda_topics connected') for topic_idx in clusters: lectures = [DBRef('lectures', id) for id in clusters[topic_idx]] lda_topics.update({"_id": topic_idx}, {"$set": {"lectures": lectures}}) logging.info('{} topic dumped to db'.format(topic_idx)) return clusters
def lda_topics_modeling(n_topics: int, id2text, corpus, id2word, n_top_features=10, dump_to_db=True): """ Возвращает вероятностное распределение документов по темам :param n_topics: Число возможных тем (топиков) :param id2text: Список имен (индексов) текстов :param corpus: текстов :param id2word: Список слов :param n_top_features: Число выводимых слов, характеризующих кластер :param dump_to_db: True - записывает топики в базу данных, False - не записывает топики в базуданных :return: кортеж с распределений слов по темам и документов по темам """ t0 = time() lda = LatentDirichletAllocation(n_topics=n_topics) logging.info('LDA created in {:.3} sec'.format(time() - t0)) t0 = time() doc_topic_dist = lda.fit_transform(corpus) logging.info('LDA model fit-transformed in {:.3} sec'.format(time() - t0)) # Загрузка полученных топиков в базу данных if dump_to_db: lda_topics = connect_to_db()['lda_clusters'] lda_topics.drop() for topic_idx, topic_dist in enumerate(lda.components_): doc = { '_id': int(topic_idx), 'terms': [ id2word[i] for i in np.argsort(topic_dist)[:-n_top_features - 1:-1] ] } lda_topics.insert(doc) logging.info('Topic {} dumped to database'.format(topic_idx)) # Нормализация весов (получение вероятностей) topic_word_dist = np.apply_along_axis(_normalize_weights, 1, lda.components_) doc_topic_dist = np.apply_along_axis(_normalize_weights, 1, doc_topic_dist) topic_word_dist = pd.DataFrame(topic_word_dist, index=id2word) doc_topic_dist = pd.DataFrame(doc_topic_dist, columns=id2text) return topic_word_dist, doc_topic_dist, lda
def lda_topics_modeling(n_topics: int, id2text, corpus, id2word, n_top_features=10, dump_to_db=True): """ Возвращает вероятностное распределение документов по темам :param n_topics: Число возможных тем (топиков) :param id2text: Список имен (индексов) текстов :param corpus: текстов :param id2word: Список слов :param n_top_features: Число выводимых слов, характеризующих кластер :param dump_to_db: True - записывает топики в базу данных, False - не записывает топики в базуданных :return: кортеж с распределений слов по темам и документов по темам """ t0 = time() lda = LatentDirichletAllocation(n_topics=n_topics) logging.info('LDA created in {:.3} sec'.format(time() - t0)) t0 = time() doc_topic_dist = lda.fit_transform(corpus) logging.info('LDA model fit-transformed in {:.3} sec'.format(time() - t0)) # Загрузка полученных топиков в базу данных if dump_to_db: lda_topics = connect_to_db()['lda_clusters'] lda_topics.drop() for topic_idx, topic_dist in enumerate(lda.components_): doc = {'_id': int(topic_idx), 'terms': [id2word[i] for i in np.argsort(topic_dist)[:-n_top_features - 1:-1]]} lda_topics.insert(doc) logging.info('Topic {} dumped to database'.format(topic_idx)) # Нормализация весов (получение вероятностей) topic_word_dist = np.apply_along_axis(_normalize_weights, 1, lda.components_) doc_topic_dist = np.apply_along_axis(_normalize_weights, 1, doc_topic_dist) topic_word_dist = pd.DataFrame(topic_word_dist, index=id2word) doc_topic_dist = pd.DataFrame(doc_topic_dist, columns=id2text) return topic_word_dist, doc_topic_dist, lda
def kcluster_text(corpus, n_clusters: int, id2text: list, id2word: list, n_components: int, n_top_features=10, dump_to_db=False) -> tuple: """ Ф-ция проводит кластеризацию текстов методом k-средних и загружает полученные кластеры в базу данных :param id2text: Список имен (индексов) текстов :param n_clusters: Число кластеров :param n_components: Число самых важных слов, по которым проводится кластеризация :param id2word: Список слов :param corpus: Корпус текстов :param n_top_features: Число выводимых слов, характеризующих кластер :return: Словарь кластеров, а так же """ # Понижение размерности матрицы при помощи латентно-семантического анализа # Выделяет n самых значимых слова (n_components), отбрасывая все остальные if n_components: t0 = time() svd = TruncatedSVD(n_components) lsa = make_pipeline(svd, Normalizer(copy=False)) corpus = lsa.fit_transform(corpus) logging.info("LSA applied in {:.3}".format(time() - t0)) # Кластеризация методом К-средних t0 = time() km_model = KMeans(n_clusters=n_clusters, verbose=-1) cluster_labels = km_model.fit_predict(corpus) logging.info('K-means performed in {0:.3}'.format(time() - t0)) # Полученные кластеры упаковываются вместе с характерными для них лекциями в словарь clusters = defaultdict(list) for text_id, label in enumerate(km_model.labels_): clusters[label].append(id2text[text_id]) # Выделяет центроиды для полученых кластеров if n_components: # Если был применен SVD метод, возвращает нормальную размерность original_space_centroids = svd.inverse_transform(km_model.cluster_centers_) order_centroids = original_space_centroids.argsort()[:, ::-1] else: order_centroids = km_model.cluster_centers_.argsort()[:, ::-1] # Каждому кластеру приписвыает n_top_features слов top_features = defaultdict(list) for cluster_id in range(n_clusters): for word_id in order_centroids[cluster_id, :n_top_features]: top_features[cluster_id].append(id2word[word_id]) # Если в качестве id2text данны индексы, то происходит запись кластеров в базу данных if dump_to_db: collection = connect_to_db()['k_clusters'] collection.drop() logging.info("Table '{0}_{1}' created ".format('clusters', n_clusters)) for cluster_id in dict(clusters): doc = {'_id': int(cluster_id), 'top_words': top_features[cluster_id], 'lectures': [DBRef(collection='lectures', id=lect_id) for lect_id in clusters[int(cluster_id)]]} logging.info("Cluster {} dumped to database".format(int(cluster_id))) collection.insert(doc) # Сведение данных в один список result = [{'_id': int(cluster_id), 'top_words': top_features[cluster_id], 'titles': clusters[int(cluster_id)]} for cluster_id in clusters] return result, cluster_labels