Sentiment Analysis

A simple Sentiment Analysis example using a Naive Bayes Classifier. See http://burakkanber.com/blog for details.

by Umar

HTML

<script src="http://burakkanber.com/bayes/negative.js"></script>
<script src="http://burakkanber.com/bayes/positive.js"></script>
<script src="http://burakkanber.com/bayes/PorterStemmer1980.min.js"></script>
<script src="http://burakkanber.com/bayes/bayes.js"></script>
<body>
    <p>Training progress: <span id="trainingProgressValue">0</span>%</p>
    <div class="progress-wrapper">
        <div class="progress" id="trainingProgressBar"></div>
    </div>
    
    <p>Test results: <span id="testResultsValue">0</span>% accuracy</p>
    <div class="progress-wrapper">
        <div class="progress" id="testResultsBar"></div>
    </div>
    
    <p>Test your own:</p>
    <textarea id="testBox" placeholder="eg: The director is a master at manupulating your emotions, making you laugh and cry."></textarea>
    <button id="testButton">Guess Sentiment</button>
    <p id="testResult" style="display:none;">Guess: <span id="testResultLabel"></span> (<span id="testResultProbability"></span>% probability)</p>
</body>

CSS

body, textarea {
    font-family: Helvetica, Arial, sans-serif;
    width: 300px;
    margin: 10px auto;
    font-size: 13px;
}
.progress-wrapper {
    border: 1px solid #CCC;
    height: 15px;
    width: 100%;
}
.progress {
    background: #DDD;
    height: 100%;
    width: 0%;
}

textarea, button {
    border: 1px solid #CCC;
}

textarea {
    padding: 10px;
    resize: none;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    margin-top: 0;
}

button {
    background: white;
    padding: 5px;
    cursor: pointer;
}

JavaScript

/*
The following is not free software. You may use it for educational purposes, but you may not redistribute or use it commercially.
(C) All Rights Reserved, Burak Kanber 2013
*/

// Define a couple of global variables so we can easily inspect data points we guessed incorrectly on.
var incorrectNegs = [];
var incorrectPos = [];

// A list of negation terms that we'll use to flag nearby tokens
var negations = new RegExp("^(never|no|nothing|nowhere|noone|none|not|havent|hasnt|hadnt|cant|couldnt|shouldnt|wont|wouldnt|dont|doesnt|didnt|isnt|arent|aint)$");

// Use 85% of our data set for training, the remaining 15% will be used for testing.
var length = negatives.length;
var split = Math.floor(0.85 * length);

// Don't spit out console.log stuff during training and guessing. 
Bayes.debug = false;

// Close-proximity negation-marked unigram ("eMSU")
Bayes.tokenizer = function (text) {
    // Standard unigram tokenizer; lowercase, strip special characters, split by whitespace
    text = Bayes.unigramTokenizer(text);
    // Step through our array of tokens
    for (var i = 0, len = text.length; i < len; i++) {
        // If we find a negation word, add an exclamation point to the word preceding and following it.
        if (text[i].match(negations)) {
            if (typeof text[i + 1] !== 'undefined') text[i + 1] = "!" + text[i + 1];
            if (typeof text[i - 1] !== 'undefined') text[i - 1] = "!" + text[i - 1];
        }
    }
    // Porter Stemmer; this reduces entropy a bit
    text = text.map(function (t) { return stemmer(t); });
    return text;
};

// Set the storage engine to in-memory; this example has too much data for localStorage.
Bayes.storage = Storage;

// Runs a single training and testing experiment.
function go() {

    // Start from scratch.
    var correct = 0;
    var incorrect = 0;
    var skipped = 0;
    var trainingBar = document.getElementById("trainingProgressBar");
    var trainingVal = document.getElementById("trainingProgressValue");
 ...