Question: I have a large dataset with 3 columns, columns are text, phrase and topic. I want to find a way to extract key-phrases (phrases column) based on the topic. Key-Phrase can be part of the text value or the whole text value. import pandas as pd text = ["great game with a lot of amazing goals from both teams", "goalkeepers from both teams made misteke", "he won all four grand slam championchips", "the best player from three-point line", "Novak Djokovic is the best player of all time", "amazing slam dunks from the best players", "he deserved yellow-card for this foul", "free throw points"] phrase = ["goals", "goalkeepers", "grand slam championchips", "three-point line", "Novak Djokovic", "slam dunks", "yellow-card", "free throw points"] topic = ["football", "football", "tennis", "basketball", "tennis", "basketball", "football", "basketball"] df = pd.DataFrame({"text":text, "phrase":phrase, "topic":topic}) print(df.text) print(df.phrase)  I'm having big trouble with finding a path to do something like this, because I have more than 50000 rows in my dataset and around 48000 of unique values of phrases, and 3 different topics. I guess that building a dataset with all football, basketball and tennis topics are not really the best solution. So I was thinking about making some kind of ML model for this, but again that means that I will have 2 features (text and topic) and one result (phrase), but I will have more than 48000 of different classes in my result, and that is not a good approach. I was thinking about using text column as a feature and applying classification model in order to find sentiment. After that I can use predicted sentiment to extract key features, but I do not know how to extract them.  One more problem is that I get only 66% accuracy when I try to classify sentiment by using CountVectorizer or TfidfTransformer with Random Forest, Decision Tree, or any other classifying algorithm, and also 66% of accuracy if Im using TextBlob for sentiment analysis. Any help?

Answer: It looks like a good approach here would be to use a Latent Dirichlet allocation model, which is an example of what are known as topic models.  A LDA is a an unsupervised model that finds similar groups among a set of observations, which you can then use to assign a topic to each of them. Here I'll go through what could be an approach to solve this by training a model using the sentences in the text column. Though in the case the phrases are representative enough an contain the necessary information to be captured by the models, then they could also be a good (possibly better) candidate for training the model, though that you'll better judge by yourself. Before you train the model, you need to apply some preprocessing steps, including tokenizing the sentences, removing stopwords, lemmatizing and stemming. For that you can use nltk: from nltk.stem import WordNetLemmatizer from nltk.corpus import stopwords from nltk.tokenize import word_tokenize import lda from sklearn.feature_extraction.text import CountVectorizer ignore = set(stopwords.words('english')) stemmer = WordNetLemmatizer() text = [] for sentence in df.text: words = word_tokenize(sentence) stemmed = [] for word in words: if word not in ignore: stemmed.append(stemmer.lemmatize(word)) text.append(' '.join(stemmed))  Now we have more appropriate corpus to train the model: print(text) ['great game lot amazing goal team', 'goalkeeper team made misteke', 'four grand slam championchips', 'best player three-point line', 'Novak Djokovic best player time', 'amazing slam dunk best player', 'deserved yellow-card foul', 'free throw point']  We can then convert the text to a matrix of token counts through CountVectorizer, which is the input LDA will be expecting: vec = CountVectorizer(analyzer='word', ngram_range=(1,1)) X = vec.fit_transform(text)  Note that you can use the ngram parameter to spacify the n-gram range you want to consider to train the model. By setting ngram_range=(1,2) for instance you'd end up with features containing all individual words as well as 2-grams in each sentence, here's an example having trained CountVectorizer with ngram_range=(1,2): vec.get_feature_names() ['amazing', 'amazing goal', 'amazing slam', 'best', 'best player', ....  The advantage of using n-grams is that you could then also find Key-Phrases other than just single words. Then we can train the LDA with whatever amount of topics you want, in this case I'll just be selecting 3 topics (note that this has nothing to do with the topics column), which you can consider to be the Key-Phrases - or words in this case - that you mention. Here I'll be using lda, though there are several options such as gensim. Each topic will have associated a set of words from the vocabulary it has been trained with, with each word having a score measuring the relevance of the word in a topic. model = lda.LDA(n_topics=3, random_state=1) model.fit(X)  Through topic_word_ we can now obtain these scores associated to each topic. We can use argsort to sort the vector of scores, and use it to index the vector of feature names, which we can obtain with vec.get_feature_names: topic_word = model.topic_word_ vocab = vec.get_feature_names() n_top_words = 3 for i, topic_dist in enumerate(topic_word): topic_words = np.array(vocab)[np.argsort(topic_dist)][:-(n_top_words+1):-1] print('Topic {}: {}'.format(i, ' '.join(topic_words))) Topic 0: best player point Topic 1: amazing team slam Topic 2: yellow novak card   The printed results don't really represent much in this case, since the model has been trained with the sample from the question, however you should see more clear and meaningful topics by training with your entire corpus. Also note that for this example I've use the whole vocabulary to train the model. However it seems that in your case what would make more sense, is to split the text column into groups according to the different topics you already have, and train a separate model on each group. But hopefully this gives you a good idea on how to proceed.