Анализ N-грамм на основе оттиска в Python
Вот как выглядит мой пример набора данных:
Моя цель-понять, сколько впечатлений связано с одним словом, двумя словами, тремя словами, четырьмя словами, пятью словами и шестью словами. Я использовал алгоритм N-грамма, но он возвращает только количество. Это мой текущий N-граммовый код.def find_ngrams(text, n):
word_vectorizer = CountVectorizer(ngram_range=(n,n), analyzer='word')
sparse_matrix = word_vectorizer.fit_transform(text)
frequencies = sum(sparse_matrix).toarray()[0]
ngram =
pd.DataFrame(frequencies,index=word_vectorizer.get_feature_names(),columns=
['frequency'])
ngram = ngram.sort_values(by=['frequency'], ascending=[False])
return ngram
one = find_ngrams(df['query'],1)
bi = find_ngrams(df['query'],2)
tri = find_ngrams(df['query'],3)
quad = find_ngrams(df['query'],4)
pent = find_ngrams(df['query'],5)
hexx = find_ngrams(df['query'],6)
Я понял, что мне нужно сделать: 1. разделите запросы на одно слово до шести слов. 2. прикрепите впечатление к разделенным словам. 3. перегруппируйте все разделенные слова и сумма впечатлений.
Возьмем в качестве примера второй запрос "распространенные заболевания собак и как их лечить". Его следует разделить следующим образом:
(1) 1-gram: dog, common, diseases, and, how, to, treat, them;
(2) 2-gram: dog common, common diseases, diseases and, and how, how to, to treat, treat them;
(3) 3-gram: dog common diseases, common diseases and, diseases and how, and how to, how to treat, to treat them;
(4) 4-gram: dog common diseases and, common diseases and how, diseases and how to, and how to treat, how to treat them;
(5) 5-gram: dog common diseases and how, the queries into one word, diseases and how to treat, and how to treat them;
(6) 6-gram: dog common diseases and how to, common diseases and how to treat, diseases and how to treat them;
2 ответа:
Вот метод! Не самый эффективный, но, давайте не будем оптимизировать преждевременно. Идея состоит в том, чтобы использовать
apply
, чтобы получить новыйpd.DataFrame
с новыми столбцами для всех ngrams, соединить его со старым фреймом данных и выполнить некоторую укладку и группировку.import pandas as pd df = pd.DataFrame({ "squery": ["how to feed a dog", "dog habits", "to cat or not to cat", "dog owners"], "count": [1000, 200, 100, 150] }) def n_grams(txt): grams = list() words = txt.split(' ') for i in range(len(words)): for k in range(1, len(words) - i + 1): grams.append(" ".join(words[i:i+k])) return pd.Series(grams) counts = df.squery.apply(n_grams).join(df) counts.drop("squery", axis=1).set_index("count").unstack()\ .rename("ngram").dropna().reset_index()\ .drop("level_0", axis=1).groupby("ngram")["count"].sum()
Это последнее выражение вернет
pd.Series
, как показано ниже.ngram a 1000 a dog 1000 cat 200 cat or 100 cat or not 100 cat or not to 100 cat or not to cat 100 dog 1350 dog habits 200 dog owners 150 feed 1000 feed a 1000 feed a dog 1000 habits 200 how 1000 how to 1000 how to feed 1000 how to feed a 1000 how to feed a dog 1000 not 100 not to 100 not to cat 100 or 100 or not 100 or not to 100 or not to cat 100 owners 150 to 1200 to cat 200 to cat or 100 to cat or not 100 to cat or not to 100 to cat or not to cat 100 to feed 1000 to feed a 1000 to feed a dog 1000
Spiffy method
Этот, вероятно, немного более эффективен, но он все же материализует плотный N-граммовый вектор из
CountVectorizer
. Он умножает это число по каждому столбцу с количеством показов, а затем добавляет по столбцам, чтобы получить общее количество показов на ngram. Это дает тот же результат, что и выше. Следует отметить, что запрос, имеющий повторяющуюся ngram, также считается двойным.import numpy as np from sklearn.feature_extraction.text import CountVectorizer cv = CountVectorizer(ngram_range=(1, 5)) ngrams = cv.fit_transform(df.squery) mask = np.repeat(df['count'].values.reshape(-1, 1), repeats = len(cv.vocabulary_), axis = 1) index = list(map(lambda x: x[0], sorted(cv.vocabulary_.items(), key = lambda x: x[1]))) pd.Series(np.multiply(mask, ngrams.toarray()).sum(axis = 0), name = "counts", index = index)
Как насчет чего-то вроде этого:
def find_ngrams(input, n): # from http://locallyoptimal.com/blog/2013/01/20/elegant-n-gram-generation-in-python/ return zip(*[input[i:] for i in range(n)]) def impressions_by_ngrams(data, ngram_max): from collections import defaultdict result = [defaultdict(int) for n in range(ngram_max)] for query, impressions in data: words = query.split() for n in range(ngram_max): for ngram in find_ngrams(words, n + 1): result[n][ngram] += impressions return result
Пример:
>>> data = [('how to feed a dog', 10000), ... ('see a dog run', 20000)] >>> ngrams = impressions_by_ngrams(data, 3) >>> ngrams[0] # unigrams defaultdict(<type 'int'>, {('a',): 30000, ('how',): 10000, ('run',): 20000, ('feed',): 10000, ('to',): 10000, ('see',): 20000, ('dog',): 30000}) >>> ngrams[1][('a', 'dog')] # impressions for bigram 'a dog' 30000