Classification of Amazon Food Reviews | by Sohail Hosseini | Towards Data Science

The goal here is to classify Food reviews based on customers' text. So the first step would be to download the dataset. It would be fascinating for suppliers to use reviews from their customers to provide better service to them. Reviews include several features like ‘ProductId’, ‘UserId’, ‘Score’, and ‘text’.
But how can we analyze these sorts of problems?
Let’s look at features included in dataset:
print(“There are {} observations and {} features in this dataset. “\ .format(reviews.shape[0],reviews.shape[1]))There are 568454 observations and 10 features in this dataset.
As it shows, the dataset consists of 568454 reviews that span a period of more than ten years. They are ten different features available in this dataset, but we only work ‘text’ and ‘Score’ columns as our input/output, respectively.
We are going to predict Score based on customers' texts. This is called Sentiment Analysis. Other features do not affect the relation between target and feature.
Now, let’s look at features included in dataset:
reviews.head()
To have a better understanding of target (Score) distribution, we use .countplot from the seaborn library. By applying this imported function, we can see the distribution of scores.
import seaborn as sns import matplotlib.pyplot as plt sns.countplot(reviews[‘Score’]) plt.show()
It shows that Score five has the maximum number between the rest of them. Based on Score distribution, which in our case, we use it as our target, it shows that the distribution is skewed, and we can also consider applying logarithm to make it more look like Gaussian. Machine learning works better when inputs and outputs have Gaussian distributions.
Let’s look at the type of each feature with pandas .info() function, which also can give you a general overview of features. It can be helpful to know if there is any missing value for each column, so you will be able to deal with it in an effective way.
reviews.info()
Since we are only working with only two columns, and there is no missing value, we do not need to remove any observation or use an imputation transformer for completing missing values.
Multinomial Naive Bayes classifier is suitable for text classification. Based on the size of the dataset and creating discrete features, I think it is practical to use a machine learning algorithm that runs fast. Otherwise, it takes a while to get a satisfactory output.
Our goal here is to find a relation between input and output. I use the ‘text’ feature as input and ‘score’ as output. So my first step is to convert texts to vectors. We must do that because we are using the Naive Bayes classifier for multinomial models, and this method also accepts numerical inputs. This is the same technique for applying any machine learning algorithm.
from sklearn.feature_extraction.text import TfidfTransformer from sklearn.naive_bayes import MultinomialNB from sklearn.pipeline import Pipeline
We need to convert feedback (texts) to a matrix of token counts in order to extract numerical features from text content. By doing it, a sparse representation of the counts is generated. It is very beneficial as you can imagine unique mapping words to vectors create the massive size of a matrix. CountVectorizer is used for this purpose, which can be imported as follows.
from sklearn.feature_extraction.text import CountVectorizer
There are many words like ‘the,’ ‘them,’ ‘are’ that do not have any effect on the meaning of context, which are called stop words. They are not informative and can be removed by selecting step_words=’english’ as a hyperparameter in CountVectorizer function.
The next step is to normalize the count matrix using tf-idf representation. The main reason behind normalizing frequencies instead of using the raw ones is to decrease the effect of tokens that occur several times in the text, and there’s not as informative as those presented a few times. For instance, the word “document” occurs a thousand times in a given corpus, and “awesome” happens two times. tf-idf works in this situation, like preprocessing data to change raw feature vectors into a representation that is more suitable for machine learning algorithms.
from sklearn.feature_extraction.text import TfidfTransformer
I used the pipeline function to do all steps together. Sequentially apply a list of transforms and a final estimator. Therefore, it starts applying CountVectorizer, Tfidf, and then MultinomialNB. You can have any number of transformers required for your work in Pipeline.
twitter_sentiment = Pipeline([('CVec', CountVectorizer(stop_words='english')),                     ('Tfidf', TfidfTransformer()),                     ('MNB', MultinomialNB())])
In the end, cross_validate is used with the roc_auc metric. k-fold cross-validation is applied and the performance measure is calculated as the average of the values in the loop. In our case, k is assigned as five. Five and ten are common values selected in k-fold cross-validation. The snippet of code is written below.
from sklearn.model_selection import cross_validatecv_pred = cross_validate(twitter_sentiment,                             reviews['Text'],                              reviews['Score'],                              cv=5,                             scoring=('roc_auc_ovr'), n_jobs=-1, verbose =10)
This is a classification problem, so we use Complete Area Under the Receiver Operating Characteristic Curve (ROC-AUC) to measure prediction scores. Since we have a multiclass problem, we are going to ‘roc_auc_ovr’. There are other options available, which could be used for this case. The results we have measured using ROC_AUC are as follows.
cv_pred['test_score']array([0.80588185, 0.81448439, 0.8088359 , 0.81728556, 0.81103624])
For each fold, the score is more than 80%. There are algorithms available like Random Forest, Gradient Boosting which also could be used here. But it depends on what you are looking for in solving each case. Are you searching for a fast answer and better accuracy? Ther is always a trade-off between these two options and you would need to select the best option for each dataset.
The complete code can be accessed through this link.