Polarity Score (Sentiment Analysis)

Usage

polarity(text.var, grouping.var = NULL, polarity.frame = qdapDictionaries::key.pol, constrain = FALSE, negators = qdapDictionaries::negation.words, amplifiers = qdapDictionaries::amplification.words, deamplifiers = qdapDictionaries::deamplification.words, question.weight = 0, amplifier.weight = 0.8, n.before = 4, n.after = 2, rm.incomplete = FALSE, digits = 3, ...)

Arguments

text.var
The text variable.
grouping.var
The grouping variables. Default NULL generates one word list for all text. Also takes a single grouping variable or a list of 1 or more grouping variables.
polarity.frame
A dataframe or hash key of positive/negative words and weights.
constrain
logical. If TRUE polarity values are constrained to be between -1 and 1 using the following transformation:
((1 - (1/(1 + exp(polarity)))) * 2) - 1
negators
A character vector of terms reversing the intent of a positive or negative word.
amplifiers
A character vector of terms that increase the intensity of a positive or negative word.
deamplifiers
A character vector of terms that decrease the intensity of a positive or negative word.
question.weight
The weighting of questions (values from 0 to 1). Default 0 corresponds with the belief that questions (pure questions) are not polarized. A weight may be applied based on the evidence that the questions function with polarity.
amplifier.weight
The weight to apply to amplifiers/deamplifiers (values from 0 to 1). This value will multiply the polarized terms by 1 + this value.
n.before
The number of words to consider as valence shifters before the polarized word.
n.after
The number of words to consider as valence shifters after the polarized word.
rm.incomplete
logical. If TRUE text rows ending with qdap's incomplete sentence end mark (|) will be removed from the analysis.
digits
Integer; number of decimal places to round when printing.
...
Other arguments supplied to strip.

Polarity Score (Sentiment Analysis)

Value

Returns a list of: allA dataframe of scores per row with:

  • group.var - the grouping variable
  • wc - word count
  • polarity - sentence polarity score
  • pos.words - words considered positive
  • neg.words - words considered negative
  • text.var - the text variable

groupA dataframe with the average polarity score by grouping variable:

  • group.var - the grouping variable
  • total.sentences - Total sentences spoken.
  • total.words - Total words used.
  • ave.polarity - The sum of all polarity scores for that group divided by number of sentences spoken.
  • sd.polarity - The standard deviation of that group's sentence level polarity scores.
  • stan.mean.polarity - A standardized polarity score calculated by taking the average polarity score for a group divided by the standard deviation.

digitsinteger value od number of digits to display; mostly internal use

Description

polarity - Approximate the sentiment (polarity) of text by grouping variable(s).

Details

The equation used by the algorithm to assign value to polarity of each sentence fist utilizes the sentiment dictionary (Hu and Liu, 2004) to tag polarized words. A context cluster (x_i^T) of words is pulled from around this polarized word (default 4 words before and two words after) to be considered as valence shifters. The words in this context cluster are tagged as neutral (x_i^0), negator (x_i^N), amplifier (x_i^a), or de-amplifier (x_i^d). Neutral words hold no value in the equation but do affect word count (n). Each polarized word is then weighted w based on the weights from the polarity.frame argument and then further weighted by the number and position of the valence shifters directly surrounding the positive or negative word. The researcher may provide a weight c to be utilized with amplifiers/de-amplifiers (default is .8; deamplifier weight is constrained to -1 lower bound). Last, these context cluster (x_i^T) are summed and divided by the square root of the word count (\sqrtn) yielding an unbounded polarity score (C). Note that context clusters containing a comma before the polarized word will only consider words found after the comma.

C=x_i^2/\sqrt(n)

Where:

x_i^T=\sum((1 + c * (x_i^A - x_i^D)) * w(-1)^(\sumx_i^N))

x_i^A=\sum(w_neg * x_i^a)

x_i^D = max(x_i^D', -1)

x_i^D'=\sum(- w_neg * x_i^a + x_i^d)

w_neg= (\sumx_i^N) mod 2

Note

The polarity score is dependent upon the polarity dictionary used. This function defaults to the word polarity dictionary used by Hu, M., & Liu, B. (2004), however, this may not be appropriate for the context of children in a classroom. The user may (is encouraged) to provide/augment the dictionary (see the sentiment_frame function). For instance the word "sick" in a high school setting may mean that something is good, whereas "sick" used by a typical adult indicates something is not right or negative connotation (deixis).

Also note that polarity assumes you've run sentSplit.

References

Hu, M., & Liu, B. (2004). Mining opinion features in customer reviews. National Conference on Artificial Intelligence.

http://www.slideshare.net/jeffreybreen/r-by-example-mining-twitter-for

http://hedonometer.org/papers.html Links to papers on hedonometrics

Examples

## <strong>Not run</strong>: # with(DATA, polarity(state, list(sex, adult))) # (poldat <- with(sentSplit(DATA, 4), polarity(state, person))) # counts(poldat) # scores(poldat) # plot(poldat) # # poldat2 <- with(mraja1spl, polarity(dialogue, # list(sex, fam.aff, died))) # colsplit2df(scores(poldat2)) # plot(poldat2) # plot(scores(poldat2)) # cumulative(poldat2) # # poldat3 <- with(rajSPLIT, polarity(dialogue, person)) # poldat3[["group"]][, "OL"] <- outlier_labeler(scores(poldat3)[, # "ave.polarity"]) # poldat3[["all"]][, "OL"] <- outlier_labeler(counts(poldat3)[, # "polarity"]) # htruncdf(scores(poldat3), 10) # htruncdf(counts(poldat3), 15, 8) # plot(poldat3) # plot(poldat3, nrow=4) # qheat(scores(poldat3)[, -7], high="red", order.b="ave.polarity") # # ## Create researcher defined sentiment.frame # POLKEY <- sentiment_frame(positive.words, negative.words) # POLKEY # c("abrasive", "abrupt", "happy") %hl% POLKEY # # ## ANIMATION # #=========== # (deb2 <- with(subset(pres_debates2012, time=="time 2"), # polarity(dialogue, person))) # # bg_black <- Animate(deb2, neutral="white", current.speaker.color="grey70") # print(bg_black, pause=.75) # # bgb <- vertex_apply(bg_black, label.color="grey80", size=20, color="grey40") # bgb <- edge_apply(bgb, label.color="yellow") # print(bgb, bg="black", pause=.75) # # ## Save it # library(animation) # library(igraph) # library(plotrix) # # loc <- folder(animation_polarity) # # ## Set up the plotting function # oopt <- animation::ani.options(interval = 0.1) # # FUN <- function() { # Title <- "Animated Polarity: 2012 Presidential Debate 2" # Legend <- c(-1.1, -1.25, -.2, -1.2) # Legend.cex <- 1 # lapply(seq_along(bgb), function(i) { # par(mar=c(2, 0, 1, 0), bg="black") # set.seed(10) # plot.igraph(bgb[[i]], edge.curved=TRUE) # mtext(Title, side=3, col="white") # color.legend(Legend[1], Legend[2], Legend[3], Legend[4], # c("Negative", "Neutral", "Positive"), attributes(bgb)[["legend"]], # cex = Legend.cex, col="white") # animation::ani.pause() # }) # } # # FUN() # # ## Detect OS # type <- if(.Platform$OS.type == "windows") shell else system # # saveHTML(FUN(), autoplay = FALSE, loop = TRUE, verbose = FALSE, # ani.height = 500, ani.width=500, # outdir = file.path(loc, "new"), single.opts = # "'controls': ['first', 'play', 'loop', 'speed'], 'delayMin': 0") # # ## Detect OS # type <- if(.Platform$OS.type == "windows") shell else system # # saveHTML(FUN(), autoplay = FALSE, loop = TRUE, verbose = FALSE, # ani.height = 1000, ani.width=650, # outdir = loc, single.opts = # "'controls': ['first', 'play', 'loop', 'speed'], 'delayMin': 0") # # #=====================# # ## Complex Animation ## # #=====================# # library(animation) # library(grid) # library(gridBase) # library(qdap) # library(reports) # library(igraph) # library(plotrix) # library(gridExtra) # # deb2dat <- subset(pres_debates2012, time=="time 2") # deb2dat[, "person"] <- factor(deb2dat[, "person"]) # (deb2 <- with(deb2dat, polarity(dialogue, person))) # # ## Set up the network version # bg_black <- Animate(deb2, neutral="white", current.speaker.color="grey70") # bgb <- vertex_apply(bg_black, label.color="grey80", size=30, label.size=22, # color="grey40") # bgb <- edge_apply(bgb, label.color="yellow") # # ## Set up the bar version # deb2_bar <- Animate(deb2, as.network=FALSE) # # ## Generate a folder # loc2 <- folder(animation_polarity2) # # ## Set up the plotting function # oopt <- animation::ani.options(interval = 0.1) # # # FUN2 <- function(follow=FALSE, theseq = seq_along(bgb)) { # # Title <- "Animated Polarity: 2012 Presidential Debate 2" # Legend <- c(.2, -1.075, 1.5, -1.005) # Legend.cex <- 1 # # lapply(theseq, function(i) { # if (follow) { # png(file=sprintf("%s/images/Rplot%s.png", loc2, i), # width=650, height=725) # } # ## Set up the layout # layout(matrix(c(rep(1, 9), rep(2, 4)), 13, 1, byrow = TRUE)) # # ## Plot 1 # par(mar=c(2, 0, 2, 0), bg="black") # #par(mar=c(2, 0, 2, 0)) # set.seed(20) # plot.igraph(bgb[[i]], edge.curved=TRUE) # mtext(Title, side=3, col="white") # color.legend(Legend[1], Legend[2], Legend[3], Legend[4], # c("Negative", "Neutral", "Positive"), attributes(bgb)[["legend"]], # cex = Legend.cex, col="white") # # ## Plot2 # plot.new() # vps <- baseViewports() # # uns <- unit(c(-1.3,.5,-.75,.25), "cm") # p <- deb2_bar[[i]] + # theme(plot.margin = uns, # text=element_text(color="white"), # plot.background = element_rect(fill = "black", # color="black")) # print(p,vp = vpStack(vps$figure,vps$plot)) # animation::ani.pause() # # if (follow) { # dev.off() # } # }) # # } # # FUN2() # # ## Detect OS # type <- if(.Platform$OS.type == "windows") shell else system # # saveHTML(FUN2(), autoplay = FALSE, loop = TRUE, verbose = FALSE, # ani.height = 1000, ani.width=650, # outdir = loc2, single.opts = # "'controls': ['first', 'play', 'loop', 'speed'], 'delayMin': 0") # # FUN2(TRUE) # # #=====================# # library(animation) # library(grid) # library(gridBase) # library(qdap) # library(reports) # library(igraph) # library(plotrix) # library(gplots) # # deb2dat <- subset(pres_debates2012, time=="time 2") # deb2dat[, "person"] <- factor(deb2dat[, "person"]) # (deb2 <- with(deb2dat, polarity(dialogue, person))) # # ## Set up the network version # bg_black <- Animate(deb2, neutral="white", current.speaker.color="grey70") # bgb <- vertex_apply(bg_black, label.color="grey80", size=30, label.size=22, # color="grey40") # bgb <- edge_apply(bgb, label.color="yellow") # # ## Set up the bar version # deb2_bar <- Animate(deb2, as.network=FALSE) # # ## Set up the line version # deb2_line <- plot(cumulative(deb2_bar)) # # ## Generate a folder # loc2b <- folder(animation_polarity2) # # ## Set up the plotting function # oopt <- animation::ani.options(interval = 0.1) # # # FUN2 <- function(follow=FALSE, theseq = seq_along(bgb)) { # # Title <- "Animated Polarity: 2012 Presidential Debate 2" # Legend <- c(.2, -1.075, 1.5, -1.005) # Legend.cex <- 1 # # lapply(theseq, function(i) { # if (follow) { # png(file=sprintf("%s/images/Rplot%s.png", loc2b, i), # width=650, height=725) # } # ## Set up the layout # layout(matrix(c(rep(1, 9), rep(2, 4)), 13, 1, byrow = TRUE)) # # ## Plot 1 # par(mar=c(2, 0, 2, 0), bg="black") # #par(mar=c(2, 0, 2, 0)) # set.seed(20) # plot.igraph(bgb[[i]], edge.curved=TRUE) # mtext(Title, side=3, col="white") # color.legend(Legend[1], Legend[2], Legend[3], Legend[4], # c("Negative", "Neutral", "Positive"), attributes(bgb)[["legend"]], # cex = Legend.cex, col="white") # # ## Plot2 # plot.new() # vps <- baseViewports() # # uns <- unit(c(-1.3,.5,-.75,.25), "cm") # p <- deb2_bar[[i]] + # theme(plot.margin = uns, # text=element_text(color="white"), # plot.background = element_rect(fill = "black", # color="black")) # print(p,vp = vpStack(vps$figure,vps$plot)) # animation::ani.pause() # # if (follow) { # dev.off() # } # }) # # } # # FUN2() # # ## Detect OS # type <- if(.Platform$OS.type == "windows") shell else system # # saveHTML(FUN2(), autoplay = FALSE, loop = TRUE, verbose = FALSE, # ani.height = 1000, ani.width=650, # outdir = loc2b, single.opts = # "'controls': ['first', 'play', 'loop', 'speed'], 'delayMin': 0") # # FUN2(TRUE) # # ## Increased complexity # ## -------------------- # # ## Helper function to cbind ggplots # cbinder <- function(x, y){ # # uns_x <- unit(c(-1.3,.15,-.75,.25), "cm") # uns_y <- unit(c(-1.3,.5,-.75,.15), "cm") # # x <- x + theme(plot.margin = uns_x, # text=element_text(color="white"), # plot.background = element_rect(fill = "black", # color="black") # ) # # y <- y + theme(plot.margin = uns_y, # text=element_text(color="white"), # plot.background = element_rect(fill = "black", # color="black") # ) # # plots <- list(x, y) # grobs <- list() # heights <- list() # # for (i in 1:length(plots)){ # grobs[[i]] <- ggplotGrob(plots[[i]]) # heights[[i]] <- grobs[[i]]$heights[2:5] # } # # maxheight <- do.call(grid::unit.pmax, heights) # # for (i in 1:length(grobs)){ # grobs[[i]]$heights[2:5] <- as.list(maxheight) # } # # do.call("arrangeGrob", c(grobs, ncol = 2)) # } # # deb2_combo <- Map(cbinder, deb2_bar, deb2_line) # # ## Generate a folder # loc3 <- folder(animation_polarity3) # # # FUN3 <- function(follow=FALSE, theseq = seq_along(bgb)) { # # Title <- "Animated Polarity: 2012 Presidential Debate 2" # Legend <- c(.2, -1.075, 1.5, -1.005) # Legend.cex <- 1 # # lapply(theseq, function(i) { # if (follow) { # png(file=sprintf("%s/images/Rplot%s.png", loc3, i), # width=650, height=725) # } # ## Set up the layout # layout(matrix(c(rep(1, 9), rep(2, 4)), 13, 1, byrow = TRUE)) # # ## Plot 1 # par(mar=c(2, 0, 2, 0), bg="black") # #par(mar=c(2, 0, 2, 0)) # set.seed(20) # plot.igraph(bgb[[i]], edge.curved=TRUE) # mtext(Title, side=3, col="white") # color.legend(Legend[1], Legend[2], Legend[3], Legend[4], # c("Negative", "Neutral", "Positive"), attributes(bgb)[["legend"]], # cex = Legend.cex, col="white") # # ## Plot2 # plot.new() # vps <- baseViewports() # p <- deb2_combo[[i]] # print(p,vp = vpStack(vps$figure,vps$plot)) # animation::ani.pause() # # if (follow) { # dev.off() # } # }) # } # # FUN3() # # type <- if(.Platform$OS.type == "windows") shell else system # # saveHTML(FUN3(), autoplay = FALSE, loop = TRUE, verbose = FALSE, # ani.height = 1000, ani.width=650, # outdir = loc3, single.opts = # "'controls': ['first', 'play', 'loop', 'speed'], 'delayMin': 0") # # FUN3(TRUE) # # ##-----------------------------## # ## Constraining between -1 & 1 ## # ##-----------------------------## # ## The old behavior of polarity constrained the output to be between -1 and 1 # ## this can be replicated via the `constrain = TRUE` argument: # # polarity("really hate anger") # polarity("really hate anger", constrain=TRUE) # # #==================# # ## Static Network ## # #==================# # (poldat <- with(sentSplit(DATA, 4), polarity(state, person))) # m <- Network(poldat) # m # print(m, bg="grey97", vertex.color="grey75") # # print(m, title="Polarity Discourse Map", title.color="white", bg="black", # legend.text.color="white", vertex.label.color = "grey70", # edge.label.color="yellow") # # ## or use themes: # dev.off() # m + qtheme() # m + theme_nightheat # dev.off() # m+ theme_nightheat(title="Polarity Discourse Map") # # #===============================# # ## CUMULATIVE POLARITY EXAMPLE ## # #===============================# # # Hedonometrics # # #===============================# # poldat4 <- with(rajSPLIT, polarity(dialogue, act, constrain = TRUE)) # # polcount <- na.omit(counts(poldat4)$polarity) # len <- length(polcount) # # cummean <- function(x){cumsum(x)/seq_along(x)} # # cumpolarity <- data.frame(cum_mean = cummean(polcount), Time=1:len) # # ## Calculate background rectangles # ends <- cumsum(rle(counts(poldat4)$act)$lengths) # starts <- c(1, head(ends + 1, -1)) # rects <- data.frame(xstart = starts, xend = ends + 1, # Act = c("I", "II", "III", "IV", "V")) # # library(ggplot2) # ggplot() + theme_bw() + # geom_rect(data = rects, aes(xmin = xstart, xmax = xend, # ymin = -Inf, ymax = Inf, fill = Act), alpha = 0.17) + # geom_smooth(data = cumpolarity, aes(y=cum_mean, x = Time)) + # geom_hline(y=mean(polcount), color="grey30", size=1, alpha=.3, linetype=2) + # annotate("text", x = mean(ends[1:2]), y = mean(polcount), color="grey30", # label = "Average Polarity", vjust = .3, size=3) + # geom_line(data = cumpolarity, aes(y=cum_mean, x = Time), size=1) + # ylab("Cumulative Average Polarity") + xlab("Duration") + # scale_x_continuous(expand = c(0,0)) + # geom_text(data=rects, aes(x=(xstart + xend)/2, y=-.04, # label=paste("Act", Act)), size=3) + # guides(fill=FALSE) + # scale_fill_brewer(palette="Set1") # ## <strong>End(Not run)</strong>