STA 279 Lab 6
Complete all Questions.
The Goal
We have been working with multinomial regression models, which are models we can use when our response variable is categorical with more than 2 levels. We work with such data a lot when we are dealing with text, so multinomial is a model we encounter often.
Our client for today is a cell phone carrier who is trying to determine what customers are saying about different cell phones they carry. They head over to a common source of reviews online. However, a glitch in the system often means phone reviews are labelled under the wrong brand (this happens A LOT in Amazon and other review systems!). In other words, while looking at reviews for Apple phones, there are actually reviews for Samsung mixed in, and vice versa. This makes it very challenging for companies to find the insight that they need when the reviews are not all from the same product!
They provide us a data set called train with 1000 phones
that are labelled with their brand. They ask us to use those phones to
build a model to (1) predict which brand a phone is and (2) describe any
key traits in reviews that might suggest a phone is from a certain
brand.
They then also provide us a data set called test with
500 phones to use to assess the predictive abilities of our model.
You can use the following code to load the data.
# Load the libraries
library(dplyr)
library(ggplot2)
library(nnet)
library(broom)
# Load the data
train <- read.csv("https://www.dropbox.com/scl/fi/y9srlcqu36qh4x2gxx1mf/CellPhonetrain.csv?rlkey=qc1bgktk8kdg8xo0uwhx9gbiv&st=bp2sdljz&dl=1")
test <- read.csv("https://www.dropbox.com/scl/fi/i875r45iwefli11b8bhbq/CellPhonetest.csv?rlkey=ux8hcgfrb7dagm1lirmhszlxz&st=4gb6yu3q&dl=1")If you look at the train dataset you have loaded, the
dataset should have 1000 rows and 119 columns. The first column is our Y
variable brand, and the remaining 118 columns are features
about the text created from the LIWC.
As a reminder, the LIWC is a tool that allows us access to multiple lexicons that we can use to create features about text data. For instance, how much of the review is written in past tense? How much involves discussions of economics? How long are the sentences, and what is the tone like? The list of possible features is extensive!
If you are curious about what each feature represents, you can look at the list on page 12 of this document. This details each of the features created by the LIWC and gives examples of the types of words in each of the lexicons it uses to create these features.
Model 1: Perception
Our client thinks that one feature that might be important is the percent of words in a review that are related to perception. These are words about how a phone feels, sounds, looks, etc. In other words, these are words about how a person physically interacts with the device.
Percepetion= the percent of words in a text that have to do with the sensory experiences (hearing, feeling, touching, smelling, etc.)
They ask us to build a model using this as a feature.
Recall that for multinomial regression, we use:
# Load the library
library(nnet)
library(broom)
# Build the model
Model1_Perception <- multinom( Y ~ X , data = dataset, trace = FALSE)
# Print out the coefficients
knitr::kable( tidy(Model1_Perception) ) Question 1
Adapt the code above to fit a multinomial regression model for \(Y\) = brand with \(X\) = the percent of words in a text related to perception. Show the formatted coefficient table as the answer for this question.
Question 2
What is the baseline for brand? How do you know?
Question 3
Write down the trained model using appropriate notation, rounding to 3 decimal places. Remember, you should have more than one line!!
Hint 1: Put the following in the white space in your
Markdown file and adapt. Make sure you change SUB1 and
SUB2.
$$log \left( \frac{\hat{\pi}_{i(SUB1)}}{\hat{\pi}_{i(SUB2)}} \right) = $$
Question 4
Interpret the slope in the Samsung component of the model in terms of the relative risk.
Question 5
Interpret the slope in the Motorola component of the model in terms of the relative risk.
Question 6
Suppose 5% of words in an article are about perception (so
Perception = 5). Compute and interpret the relative risk of
being a Samsung review versus Apple review in this scenario.
Hint 1: Your interpretation should say something like “The predicted X of being written about brand A is 2 times higher than the predicted X of being written about brand B.”
Hint 2: A lot of people don’t like interpreting when we have something like \(\hat{\pi}_{i(A)} = .65 \hat{\pi}_{i(B)}\). If this is you, remember you can rewrite this as \(\hat{\pi}_{i(B)} = 1/.65 \hat{\pi}_{i(A)} = 1.53\hat{\pi}_{i(A)}\) and interpret in this form!
Question 7
Suppose 25% of words in an article are about perception (so
Perception = 25). Compute and interpret the relative risk
of being a Motorola review versus Apple review in this scenario.
Hint 1: Your interpretation should say something like “The predicted X of being written about brand A is 2 times higher than the predicted X of being written about brand B.”
Hint 2: A lot of people don’t like interpreting when we have something like \(\hat{\pi}_{i(A)} = .65 \hat{\pi}_{i(B)}\). If this is you, remember you can rewrite this as \(\hat{\pi}_{i(B)} = 1/.65 \hat{\pi}_{i(A)} = 1.53\hat{\pi}_{i(A)}\) and interpret in this form!
The kind of interpretation work we have done in the previous two questions is useful. However, especially when we are working with a client, it is extremely valuable to be able to visualize the relationships that our model is describing. In other words, we would like to be able to make a plot that shows how the probability of being written about each brand changes as the percent of perception words changes.
We can do this in R, but the code involved is a little tricky, so I built a function that will do it for us. To teach R the function, copy and paste the following into a chunk and press play. DO NOT CHANGE ANYTHING ABOUT THIS FUNCTION.
plot_multnomial <- function(data, model, Y, X, Xname, xlab){
if(length(coefficients(model)[1,])==2){
predictions <- predict( model, type ="probs")
data[, Y] <-as.factor(data[,Y])
J = length(levels(data[,Y]))
holder <- data.frame("group" = NA, "x" = NA, "Probability"=NA)
a = 1
for(i in 1:nrow(data)){
for(j in 1:J){
holder[a,1] <- levels(data[,Y])[j]
holder[a,2] <- data[i,X]
holder[a,3] <- predictions[i,j]
a = a + 1
}
}
g1 <- ggplot( holder, aes(x, Probability, col= group)) +
geom_line() +
labs(x = xlab)
}
if(length(coefficients(model)[1,])>2){
suppressMessages(library(pdp))
suppressMessages(library(ggplot2))
data[ , Y] <-as.factor(data[,Y])
toplot1 <- data.frame(partial(model, Xname, which.class = 1, plot = FALSE, prob = TRUE))
toplot2 <- data.frame(partial(model, Xname, which.class = 2, plot = FALSE, prob = TRUE))
toplot3 <- data.frame(partial(model, Xname, which.class = 3, plot = FALSE, prob = TRUE))
toplot1$response <- levels(data[,Y])[1]
toplot2$response <- levels(data[,Y])[2]
toplot3$response <- levels(data[,Y])[3]
hold <- rbind(toplot1,toplot2,toplot3)
hold <-data.frame(hold)
hold$response <- as.factor(hold$response)
g1 <- ggplot(hold, aes(x = hold[,1], yhat, col = response)) + geom_line() +
labs(x = xlab, y = "Probability")
}
g1
}To use this function, adapt the following:
data: replace with the name of your data set.model: replace with the name of your model.Y: replace with the number of the column in your data set when \(Y\) is.X: replace with the number of the column in your data set when \(X\) is. For perception, this is 96.Xname: replace with the name of your \(X\) column. Make sure you put it in quotes, for example:"Perception"xlab: replace with the label you want for the x axis label. Make sure you put it in quotes, for example:"The x axis label".
Question 8
Adapt the code above to create a plot that shows how the probability of being written about each brand changes as the percent of perception words changes. Show the plot.
Question 9
Recall that we have a client who thought that the percent of perception words might be useful for determining brand. Based on the plot, describe in 2-3 sentences the relationship between the percent of perception words and brand.
Question 10
Choose a different feature (anything except Perception).
State which feature you choose, build a multinomial regression model for
brand using that feature, and then adapt the code above Question 8 to
visualize the relationship between that feature and brand.
As an answer to this question, show the plot and describe the relationship between \(X\) and brand shown in the plot.
In addition to describing the relationships in the data, if we want to find predicted probabilities from a multinomial regression model for a row \(i\) in the data set, we can use:
Question 11
Row 20 in the data set has 0% perception words. What are the predicted probabilities of being from each brand?
Do these probabilities match what you see in the plot in Question 8? Explain.
Model 2: Full Multinomial Model
Recall that the client asked us to build a model that could predict which brand of phone each review is about. So far, we have only been working with one feature, but when we move into prediction it makes a lot more sense to use all the features we have access too!
We have 118 available to us, so let’s use them all. Adding every feature we have access to is called making a full model.
This model will have a LOT of coefficients, so it won’t be super useful to look at a table of coefficients. However, it should be useful for their other goal of predicting which brand each review is about.
To make predictions on the test using multinomial regression, we use the code:
# Make predictions
predictions <- predict(Model2_Full, type = "class", newdata = test)
# Create a confusion matrix
holder <- table( predictions, test$brand )
rownames(holder) <- paste("Predicted", rownames(holder))
colnames(holder) <- paste("True", colnames(holder))
knitr::kable( holder )We can also use the pretty confusion matrix code we did with logistic regression!!
Question 12
What is the accuracy for Samsung?
Naive Bayes
Because the client asked us to do prediction, it makes sense to try more than one approach. In practice, we often try multiple predictive approaches. Now that we have tried multinomial, let’s try Naive Bayes!
Let’s start off with just two features to remind ourselves how this algorithm works, and then we will see how to run the whole algorithm using R.
Let \(X_1\) = 1 if the positive
sentiment score (emo_pos) is greater than 5, and \(X_2\) = 1 if the review contains at least
one exclamation point.
Let’s use Naive Bayes to find the probability of being about an Apple phone if the positive sentiment score is 10 and there are 3 exclamation points.
Recall that for Naive Bayes, we find our probabilities using:
\[P(y_i = A ~ | ~ x_{i1} ~and~ x_{i2} ) = \frac{P(y_i = A) \times P(x_{i1}~|~A) \times P(x_{i2}~|~A)}{P(x_{i1} ~and~ x_{i2})}\]
Question 13
What values should we use for \(x_{i1}\) and \(x_{i2}\)?
Question 14
What is \(P(x_{i1} ~and~ x_{i2})\)? Feel free to leave your answer in fraction form, and show the table you used to get the information needed to compute this.
Hint: In R, we create a table using this template:
table( variable1, variable2)
Question 15
What is \(P(y_i = A)\)? Feel free to leave your answer in fraction form, and show the table you used to get the information needed to compute this.
Hint: In R, we create a table using this template:
table( data$variable)
Question 16
What is \(P(x_{i1} ~ | y_i = A)\)? Feel free to leave your answer in fraction form, and show the table you used to get the information needed to compute this.
Question 17
What is \(P(x_{i2} ~ | y_i = A)\)? Feel free to leave your answer in fraction form, and show the table you used to get the information needed to compute this.
Question 18
What is \(P(y_i = A ~ | ~ x_{i1} ~and~ x_{i2} )\)?
Hint: Remember you can use R as a calculator! Just inset a chunk and
type in what you need. The * symbol is multiplication in
R.
I know this is long, but it is important to do a few times to make sure we feel comfortable with what Naive Bayes is actually doing. In practice, it is MUCH more efficient to use R to help with the computations.
To run Naive Bayes in R, we need the naivebayes
library:
Remember: If your computer ever tells you a library is not found, this means you need to install the package from Tools.
Since we are using computing now, let’s go back to using all the features rather than just \(X_1\) and \(X_2\). The code we use to make predictions with Naive Bayes is then:
# Train Naive Bayes
nb <- naive_bayes( Y ~ . , data= ... )
# Make predictions
yhat <- predict(nb , type = "class", newdata = ...)Question 19
Fill in Y, and the ... in the code above to
(1) train the Naive Bayes model on the training data using all the
features and (2) make predictions on the test data. Just type “done” as
the answer to this question.
Comparing Models
At this point, we have predictions from multinomial regression:
# Create a confusion matrix
holder <- table( predictions, test$brand )
rownames(holder) <- paste("Predicted", rownames(holder))
colnames(holder) <- paste("True", colnames(holder))
knitr::kable( holder )and from Naive Bayes:
# Create a confusion matrix
holder <- table( yhat, test$brand )
rownames(holder) <- paste("Predicted", rownames(holder))
colnames(holder) <- paste("True", colnames(holder))
knitr::kable( holder )Question 21
Just looking at the two confusion matrices, is it easy to see which is predicting better?
When it comes time to compare different predictive approaches, it is helpful if we have some metric, meaning some number, we can use to compare them. We could use the accuracy, but this tends to not work as well unless all our options for \(Y\) have roughly same number of rows.
Question 22
Do all our options for \(Y\) have roughly same number of rows in the training data?
In situations where the classes are not balanced, we reach for a tool called the Macro F1-score.
A standard F1-score is computed as
\[F1 = \frac{TP}{TP+.5(FP + FN)}\]
For example, the F1-score for Apple is computed as
\[F1_{Apple} = \frac{TP_{Apple}}{TP_{Apple}+.5(FP_{Apple} + FN_{Apple})}\]
where
- \(TP_{Apple}\) = the number of Apple reviews that are correctly identified
- \(FP_{Apple}\) = the number of reviews that are predicted to be Apple but are not
- \(FN_{Apple}\) = the number of reviews that are Apple but are predicted to be something else.
Question 23
What is the F1-score for Samsung for Naive Bayes? Show your work!
It is important to note that F1-scores are between 0 and 1, and the higher, the better. This means an F1-score of .9 indicates a strong predictive performance, while something like .2 does not. Beyond this, we do not intepret F1-scores.
To get the Macro F1-score, all we do is average together the F1-scores for each of the 3 brands. As a note, neither the Macro F1-score nor standard F1-scores are interpretable. All we do is compare them, and the higher, the better!
Like the F1-scores, Macro F1-scores are between 0 and 1, and higher values indicate better prediction.
Question 24
For Naive Bayes, the F1 score for Apple is .3549 and the F1 score for Motorola is .4481. What is the Macro F1-score for Naive Bayes?
When we are doing prediction, looking for a higher Macro F1-score can be a tool to determine which model is doing better at prediction overall.
We just saw that computing the Macro F1-score by hand can take a
while. Luckily, the caret package has a built in.
library(caret)
# Make sure R knows brand is categorical
test$brand <- factor(test$brand)
# Build the confusion matrix
CM <- confusionMatrix(data = predicted, reference = actual, mode = "everything")
# Pull out the F1-scores
class_f1_scores <- CM$byClass[, "F1"]
# Compute the Macro F1 Score
mean(class_f1_scores)Question 25
Adapt the code above (just replace predicted and
actual with the predictions and true value of \(Y\) for our test data) to find the Macro
F1-score for multinomial. State the value.
Question 26
At this point, would you recommend Naive Bayes or Multinomial for prediction? Explain your choice.
Before you submit!
Change the chunk at the top of your document from
knitr::opts_chunk$set(echo = TRUE)
to
knitr::opts_chunk$set(echo = FALSE, message = FALSE, warning = FALSE)