Sentiment Analysis of IMDB reviews

Sentiment Analysis of IMDB reviews

This article shows you how to build a Neural Network from scratch(no libraries) for the purpose of detecting whether a movie review on IMDB is negative or positive.


  • Curating a dataset and developing a "Predictive Theory"

  • Transforming Text to Numbers Creating the Input/Output Data

  • Building our Neural Network

  • Making Learning Faster by Reducing "Neural Noise"

  • Reducing Noise by strategically reducing the vocabulary

Curating the Dataset

In [3]:
def pretty_print_review_and_label(i):
    print(labels[i] + "\t:\t" + reviews[i][:80] + "...")

g = open('reviews.txt','r') # features of our dataset
reviews = list(map(lambda x:x[:-1],g.readlines()))

g = open('labels.txt','r') # labels
labels = list(map(lambda x:x[:-1].upper(),g.readlines()))

Note: The data in reviews.txt we're contains only lower case characters. That's so we treat different variations of the same word, like The, the, and THE, all the same way.

It's always a good idea to get check out your dataset before you proceed.

In [2]:
len(reviews) #No. of reviews
In [3]:
reviews[0] #first review
'bromwell high is a cartoon comedy . it ran at the same time as some other programs about school life  such as  teachers  . my   years in the teaching profession lead me to believe that bromwell high  s satire is much closer to reality than is  teachers  . the scramble to survive financially  the insightful students who can see right through their pathetic teachers  pomp  the pettiness of the whole situation  all remind me of the schools i knew and their students . when i saw the episode in which a student repeatedly tried to burn down the school  i immediately recalled . . . . . . . . . at . . . . . . . . . . high . a classic line inspector i  m here to sack one of your teachers . student welcome to bromwell high . i expect that many adults of my age think that bromwell high is far fetched . what a pity that it isn  t   '
In [4]:
labels[0] #first label

Developing a Predictive Theory

Analysing how you would go about predicting whether its a positive or a negative review.

In [5]:
print("labels.txt \t : \t reviews.txt\n")
labels.txt 	 : 	 reviews.txt

NEGATIVE	:	this movie is terrible but it has some good effects .  ...
POSITIVE	:	adrian pasdar is excellent is this film . he makes a fascinating woman .  ...
NEGATIVE	:	comment this movie is impossible . is terrible  very improbable  bad interpretat...
POSITIVE	:	excellent episode movie ala pulp fiction .  days   suicides . it doesnt get more...
NEGATIVE	:	if you haven  t seen this  it  s terrible . it is pure trash . i saw this about ...
POSITIVE	:	this schiffer guy is a real genius  the movie is of excellent quality and both e...
In [41]:
from collections import Counter
import numpy as np

We'll create three Counter objects, one for words from postive reviews, one for words from negative reviews, and one for all the words.

In [56]:
# Create three Counter objects to store positive, negative and total counts
positive_counts = Counter()
negative_counts = Counter()
total_counts = Counter()

Examine all the reviews. For each word in a positive review, increase the count for that word in both your positive counter and the total words counter; likewise, for each word in a negative review, increase the count for that word in both your negative counter and the total words counter. You should use split(' ') to divide a piece of text (such as a review) into individual words.

In [57]:
# Loop over all the words in all the reviews and increment the counts in the appropriate counter objects
for i in range(len(reviews)):
    if(labels[i] == 'POSITIVE'):
        for word in reviews[i].split(" "):
            positive_counts[word] += 1
            total_counts[word] += 1
        for word in reviews[i].split(" "):
            negative_counts[word] += 1
            total_counts[word] += 1

Most common positive & negative words

In [ ]:

The above statement retrieves alot of words, the top 3 being : ('the', 173324), ('.', 159654), ('and', 89722),

In [ ]:

The above statement retrieves alot of words, the top 3 being : ('', 561462), ('.', 167538), ('the', 163389),

As you can see, common words like "the" appear very often in both positive and negative reviews. Instead of finding the most common words in positive or negative reviews, what you really want are the words found in positive reviews more often than in negative reviews, and vice versa. To accomplish this, you'll need to calculate the ratios of word usage between positive and negative reviews.

The positive-to-negative ratio for a given word can be calculated with positive_counts[word] / float(negative_counts[word]+1). Notice the +1 in the denominator – that ensures we don't divide by zero for words that are only seen in positive reviews.

In [58]:
pos_neg_ratios = Counter()

# Calculate the ratios of positive and negative uses of the most common words
# Consider words to be "common" if they've been used at least 100 times
for term,cnt in list(total_counts.most_common()):
    if(cnt > 100):
        pos_neg_ratio = positive_counts[term] / float(negative_counts[term]+1)
        pos_neg_ratios[term] = pos_neg_ratio

Examine the ratios

In [12]:
print("Pos-to-neg ratio for 'the' = {}".format(pos_neg_ratios["the"]))
print("Pos-to-neg ratio for 'amazing' = {}".format(pos_neg_ratios["amazing"]))
print("Pos-to-neg ratio for 'terrible' = {}".format(pos_neg_ratios["terrible"]))
Pos-to-neg ratio for 'the' = 1.0607993145235326
Pos-to-neg ratio for 'amazing' = 4.022813688212928
Pos-to-neg ratio for 'terrible' = 0.17744252873563218

We see the following:

  • Words that you would expect to see more often in positive reviews – like "amazing" – have a ratio greater than 1. The more skewed a word is toward postive, the farther from 1 its positive-to-negative ratio will be.
  • Words that you would expect to see more often in negative reviews – like "terrible" – have positive values that are less than 1. The more skewed a word is toward negative, the closer to zero its positive-to-negative ratio will be.
  • Neutral words, which don't really convey any sentiment because you would expect to see them in all sorts of reviews – like "the" – have values very close to 1. A perfectly neutral word – one that was used in exactly the same number of positive reviews as negative reviews – would be almost exactly 1.

Ok, the ratios tell us which words are used more often in postive or negative reviews, but the specific values we've calculated are a bit difficult to work with. A very positive word like "amazing" has a value above 4, whereas a very negative word like "terrible" has a value around 0.18. Those values aren't easy to compare for a couple of reasons:

  • Right now, 1 is considered neutral, but the absolute value of the postive-to-negative rations of very postive words is larger than the absolute value of the ratios for the very negative words. So there is no way to directly compare two numbers and see if one word conveys the same magnitude of positive sentiment as another word conveys negative sentiment. So we should center all the values around netural so the absolute value fro neutral of the postive-to-negative ratio for a word would indicate how much sentiment (positive or negative) that word conveys.
  • When comparing absolute values it's easier to do that around zero than one.

To fix these issues, we'll convert all of our ratios to new values using logarithms (i.e. use np.log(ratio))

In the end, extremely positive and extremely negative words will have positive-to-negative ratios with similar magnitudes but opposite signs.

In [59]:
# Convert ratios to logs
for word,ratio in pos_neg_ratios.most_common():
    pos_neg_ratios[word] = np.log(ratio)

Examine the new ratios

In [14]:
print("Pos-to-neg ratio for 'the' = {}".format(pos_neg_ratios["the"]))
print("Pos-to-neg ratio for 'amazing' = {}".format(pos_neg_ratios["amazing"]))
print("Pos-to-neg ratio for 'terrible' = {}".format(pos_neg_ratios["terrible"]))
Pos-to-neg ratio for 'the' = 0.05902269426102881
Pos-to-neg ratio for 'amazing' = 1.3919815802404802
Pos-to-neg ratio for 'terrible' = -1.7291085042663878

If everything worked, now you should see neutral words with values close to zero. In this case, "the" is near zero but slightly positive, so it was probably used in more positive reviews than negative reviews. But look at "amazing"'s ratio - it's above 1, showing it is clearly a word with positive sentiment. And "terrible" has a similar score, but in the opposite direction, so it's below -1. It's now clear that both of these words are associated with specific, opposing sentiments.

Run the below code to see more ratios.

It displays all the words, ordered by how associated they are with postive reviews.

In [ ]:

The top most common words for the above code : ('edie', 4.6913478822291435), ('paulie', 4.0775374439057197), ('felix', 3.1527360223636558), ('polanski', 2.8233610476132043), ('matthau', 2.8067217286092401), ('victoria', 2.6810215287142909), ('mildred', 2.6026896854443837), ('gandhi', 2.5389738710582761), ('flawless', 2.451005098112319), ('superbly', 2.2600254785752498), ('perfection', 2.1594842493533721), ('astaire', 2.1400661634962708), ('captures', 2.0386195471595809), ('voight', 2.0301704926730531), ('wonderfully', 2.0218960560332353), ('powell', 1.9783454248084671), ('brosnan', 1.9547990964725592)

Transforming Text into Numbers

Creating the Input/Output Data

Create a set named vocab that contains every word in the vocabulary.

In [19]:
vocab = set(total_counts.keys())

Check vocabulary size

In [20]:
vocab_size = len(vocab)

Th following image rpresents the layers of the neural network you'll be building throughout this notebook. layer_0 is the input layer, layer_1 is a hidden layer, and layer_2 is the output layer.

In [1]:

TODO: Create a numpy array called layer_0 and initialize it to all zeros. Create layer_0 as a 2-dimensional matrix with 1 row and vocab_size columns.

In [21]:
layer_0 = np.zeros((1,vocab_size))

layer_0 contains one entry for every word in the vocabulary, as shown in the above image. We need to make sure we know the index of each word, so run the following cell to create a lookup table that stores the index of every word.

TODO: Complete the implementation of update_input_layer. It should count how many times each word is used in the given review, and then store those counts at the appropriate indices inside layer_0.

In [ ]:
# Create a dictionary of words in the vocabulary mapped to index positions 
# (to be used in layer_0)
word2index = {}
for i,word in enumerate(vocab):
    word2index[word] = i

It stores the indexes like this: 'antony': 22, 'pinjar': 23, 'helsig': 24, 'dances': 25, 'good': 26, 'willard': 71500, 'faridany': 27, 'foment': 28, 'matts': 12313,

Lets implement some functions for simplifying our inputs to the neural network.

In [25]:
def update_input_layer(review):
    The element at a given index of layer_0 should represent
    how many times the given word occurs in the review.
    global layer_0
    # clear out previous state, reset the layer to be all 0s
    layer_0 *= 0
    # count how many times each word is used in the given review and store the results in layer_0 
    for word in review.split(" "):
        layer_0[0][word2index[word]] += 1

Run the following cell to test updating the input layer with the first review. The indices assigned may not be the same as in the solution, but hopefully you'll see some non-zero values in layer_0.

In [26]:
array([[ 18.,   0.,   0., ...,   0.,   0.,   0.]])

get_target_for_labels should return 0 or 1, depending on whether the given label is NEGATIVE or POSITIVE, respectively.

In [27]:
def get_target_for_label(label):
    if(label == 'POSITIVE'):
        return 1
        return 0

Building a Neural Network

In [32]:
import time
import sys
import numpy as np

# Encapsulate our neural network in a class
class SentimentNetwork:
    def __init__(self, reviews,labels,hidden_nodes = 10, learning_rate = 0.1):
            reviews(list) - List of reviews used for training
            labels(list) - List of POSITIVE/NEGATIVE labels
            hidden_nodes(int) - Number of nodes to create in the hidden layer
            learning_rate(float) - Learning rate to use while training
        # Assign a seed to our random number generator to ensure we get
        # reproducable results

        # process the reviews and their associated labels so that everything
        # is ready for training
        self.pre_process_data(reviews, labels)
        # Build the network to have the number of hidden nodes and the learning rate that
        # were passed into this initializer. Make the same number of input nodes as
        # there are vocabulary words and create a single output node.
        self.init_network(len(self.review_vocab),hidden_nodes, 1, learning_rate)

    def pre_process_data(self, reviews, labels):
        # populate review_vocab with all of the words in the given reviews
        review_vocab = set()
        for review in reviews:
            for word in review.split(" "):

        # Convert the vocabulary set to a list so we can access words via indices
        self.review_vocab = list(review_vocab)
        # populate label_vocab with all of the words in the given labels.
        label_vocab = set()
        for label in labels:
        # Convert the label vocabulary set to a list so we can access labels via indices
        self.label_vocab = list(label_vocab)
        # Store the sizes of the review and label vocabularies.
        self.review_vocab_size = len(self.review_vocab)
        self.label_vocab_size = len(self.label_vocab)
        # Create a dictionary of words in the vocabulary mapped to index positions
        self.word2index = {}
        for i, word in enumerate(self.review_vocab):
            self.word2index[word] = i
        # Create a dictionary of labels mapped to index positions
        self.label2index = {}
        for i, label in enumerate(self.label_vocab):
            self.label2index[label] = i
    def init_network(self, input_nodes, hidden_nodes, output_nodes, learning_rate):
        # Set number of nodes in input, hidden and output layers.
        self.input_nodes = input_nodes
        self.hidden_nodes = hidden_nodes
        self.output_nodes = output_nodes

        # Store the learning rate
        self.learning_rate = learning_rate

        # Initialize weights

        # These are the weights between the input layer and the hidden layer.
        self.weights_0_1 = np.zeros((self.input_nodes,self.hidden_nodes))
        # These are the weights between the hidden layer and the output layer.
        self.weights_1_2 = np.random.normal(0.0, self.output_nodes**-0.5, 
                                                (self.hidden_nodes, self.output_nodes))
        # The input layer, a two-dimensional matrix with shape 1 x input_nodes
        self.layer_0 = np.zeros((1,input_nodes))
    def update_input_layer(self,review):

        # clear out previous state, reset the layer to be all 0s
        self.layer_0 *= 0
        for word in review.split(" "):
            if(word in self.word2index.keys()):
                self.layer_0[0][self.word2index[word]] += 1
    def get_target_for_label(self,label):
        if(label == 'POSITIVE'):
            return 1
            return 0
    def sigmoid(self,x):
        return 1 / (1 + np.exp(-x))
    def sigmoid_output_2_derivative(self,output):
        return output * (1 - output)
    def train(self, training_reviews, training_labels):
        # make sure out we have a matching number of reviews and labels
        assert(len(training_reviews) == len(training_labels))
        # Keep track of correct predictions to display accuracy during training 
        correct_so_far = 0

        # Remember when we started for printing time statistics
        start = time.time()
        # loop through all the given reviews and run a forward and backward pass,
        # updating weights for every item
        for i in range(len(training_reviews)):
            # Get the next review and its correct label
            review = training_reviews[i]
            label = training_labels[i]
            ### Forward pass ###

            # Input Layer

            # Hidden layer
            layer_1 =

            # Output layer
            layer_2 = self.sigmoid(
            ### Backward pass ###

            # Output error
            layer_2_error = layer_2 - self.get_target_for_label(label) # Output layer error is the difference between desired target and actual output.
            layer_2_delta = layer_2_error * self.sigmoid_output_2_derivative(layer_2)

            # Backpropagated error
            layer_1_error = # errors propagated to the hidden layer
            layer_1_delta = layer_1_error # hidden layer gradients - no nonlinearity so it's the same as the error

            # Update the weights
            self.weights_1_2 -= * self.learning_rate # update hidden-to-output weights with gradient descent step
            self.weights_0_1 -= * self.learning_rate # update input-to-hidden weights with gradient descent step

            # Keep track of correct predictions.
            if(layer_2 >= 0.5 and label == 'POSITIVE'):
                correct_so_far += 1
            elif(layer_2 < 0.5 and label == 'NEGATIVE'):
                correct_so_far += 1
            sys.stdout.write(" #Correct:" + str(correct_so_far) + " #Trained:" + str(i+1) \
                             + " Training Accuracy:" + str(correct_so_far * 100 / float(i+1))[:4] + "%")
    def test(self, testing_reviews, testing_labels):
        Attempts to predict the labels for the given testing_reviews,
        and uses the test_labels to calculate the accuracy of those predictions.
        # keep track of how many correct predictions we make
        correct = 0

        # Loop through each of the given reviews and call run to predict
        # its label. 
        for i in range(len(testing_reviews)):
            pred =[i])
            if(pred == testing_labels[i]):
                correct += 1
            sys.stdout.write(" #Correct:" + str(correct) + " #Tested:" + str(i+1) \
                             + " Testing Accuracy:" + str(correct * 100 / float(i+1))[:4] + "%")
    def run(self, review):
        Returns a POSITIVE or NEGATIVE prediction for the given review.
        # Run a forward pass through the network, like in the "train" function.
        # Input Layer

        # Hidden layer
        layer_1 =

        # Output layer
        layer_2 = self.sigmoid(
        # Return POSITIVE for values above greater-than-or-equal-to 0.5 in the output layer;
        # return NEGATIVE for other values
        if(layer_2[0] >= 0.5):
            return "POSITIVE"
            return "NEGATIVE"

Run the following code to create the network with a small learning rate, 0.001, and then train the new network. Using learning rate larger than this, for example 0.1 or even 0.01 would result in poor performance.

In [ ]:
mlp = SentimentNetwork(reviews[:-1000],labels[:-1000], learning_rate=0.001)

Running the above code would have given an accuracy around 62.2%

Reducing Noise in Our Input Data

Counting how many times each word occured in our review might not be the most efficient way. Instead just including whether a word was there or not will improve our training time and accuracy. Hence we update our update_input_layer() function.

In [ ]:
def update_input_layer(self,review):
    self.layer_0 *= 0
    for word in review.split(" "):
        if(word in self.word2index.keys()):
            self.layer_0[0][self.word2index[word]] =1

Creating and running our neural network again, even with a higher learning rate of 0.1 gave us a training accuracy of 83.8% and testing accuracy(testing on last 1000 reviews) of 85.7%.

Reducing Noise by Strategically Reducing the Vocabulary

Let us put the pos to neg ratio's that we found were much more effective at detecting a positive or negative label. We could do that by a few change:

  • Modify pre_process_data:
    • Add two additional parameters: min_count and polarity_cutoff
    • Calculate the positive-to-negative ratios of words used in the reviews.
    • Change so words are only added to the vocabulary if they occur in the vocabulary more than min_count times.
    • Change so words are only added to the vocabulary if the absolute value of their postive-to-negative ratio is at least polarity_cutoff
In [ ]:
def pre_process_data(self, reviews, labels, polarity_cutoff, min_count):
        positive_counts = Counter()
        negative_counts = Counter()
        total_counts = Counter()

        for i in range(len(reviews)):
            if(labels[i] == 'POSITIVE'):
                for word in reviews[i].split(" "):
                    positive_counts[word] += 1
                    total_counts[word] += 1
                for word in reviews[i].split(" "):
                    negative_counts[word] += 1
                    total_counts[word] += 1

        pos_neg_ratios = Counter()

        for term,cnt in list(total_counts.most_common()):
            if(cnt >= 50):
                pos_neg_ratio = positive_counts[term] / float(negative_counts[term]+1)
                pos_neg_ratios[term] = pos_neg_ratio

        for word,ratio in pos_neg_ratios.most_common():
            if(ratio > 1):
                pos_neg_ratios[word] = np.log(ratio)
                pos_neg_ratios[word] = -np.log((1 / (ratio + 0.01)))

        # populate review_vocab with all of the words in the given reviews
        review_vocab = set()
        for review in reviews:
            for word in review.split(" "):
                if(total_counts[word] > min_count):
                    if(word in pos_neg_ratios.keys()):
                        if((pos_neg_ratios[word] >= polarity_cutoff) or (pos_neg_ratios[word] <= -polarity_cutoff)):

        # Convert the vocabulary set to a list so we can access words via indices
        self.review_vocab = list(review_vocab)
        # populate label_vocab with all of the words in the given labels.
        label_vocab = set()
        for label in labels:
        # Convert the label vocabulary set to a list so we can access labels via indices
        self.label_vocab = list(label_vocab)
        # Store the sizes of the review and label vocabularies.
        self.review_vocab_size = len(self.review_vocab)
        self.label_vocab_size = len(self.label_vocab)
        # Create a dictionary of words in the vocabulary mapped to index positions
        self.word2index = {}
        for i, word in enumerate(self.review_vocab):
            self.word2index[word] = i
        # Create a dictionary of labels mapped to index positions
        self.label2index = {}
        for i, label in enumerate(self.label_vocab):
            self.label2index[label] = i

Our training accuracy increased to 85.6% after this change. As we can see our accuracy saw a huge jump by making minor changes based on our intuition. We can keep making such changes and increase the accuracy even further.


Download the Data Sources

The data sources used in this article can be downloaded here:

The Inside Out of ML Based Prescriptive Analytics

With the constantly growing number of data, more and more companies are shifting towards analytic solutions. Analytic solutions help in extracting the meaning from the huge amount of data available. Thus, improving decision making.

Decision making is an important aspect of businesses, and technologies like Machine Learning are enhancing it further. The growing use of Machine Learning has changed the way of prescriptive analytics. In order to optimize the efforts, companies need to be more accurate with the historical and present data. This is because the historical and present data are the essentials of analytics. This article helps describe the inside out of Machine Learning-based prescriptive analytics.

Phases of business analytics

Descriptive analytics, predictive analytics, and prescriptive analytics are the three phases of business analytics. Descriptive analytics, being the first one, deals with past performance. Historical data is mined to understand past performance. This serves as a way to look for the reasons behind past success and failure. It is a kind of post-mortem analysis and most management reporting like sales, marketing, operations, and finance etc. make use of this.

The second one is a predictive analysis which answers the question of what is likely to happen. The historical data is now combined with rules, algorithms etc. to determine the possible future outcome or likelihood of a situation occurring.

The final phase, well known to everyone, is prescriptive analytics. It can continually take in new data and re-predict and re-prescribe. This improves the accuracy of the prediction and prescribes better decision options.  Professional services or technology or their combination can be chosen to perform all the three analytics.

More about prescriptive analytics

The analysis of business activities goes through many phases. Prescriptive analytics is one such. It is known to be the third phase of business analytics and comes after descriptive and predictive analytics. It entails the application of mathematical and computational sciences. It makes use of the results obtained from descriptive and predictive analysis to suggest decision options. It goes beyond predicting future outcomes and suggests actions to benefit from the predictions. It shows the implications of each decision option. It anticipates on what will happen when it will happen as well as why it will happen.

ML-based prescriptive analytics

Being just before the prescriptive analytics, predictive analytics is often confused with it. What actually happens is predictive analysis leads to prescriptive analysis. Thus, a Machine Learning based prescriptive analytics goes through an ML-based predictive analysis first. Therefore, it becomes necessary to consider the ML-based predictive analysis first.

ML-based predictive analytics:

A lot of things prevent businesses from achieving predictive analysis capabilities.  Machine Learning can be a great help in boosting Predictive analytics. Use of Machine Learning and Artificial Intelligence algorithms helps businesses in optimizing and uncovering the new statistical patterns. These statistical patterns form the backbone of predictive analysis. E-commerce, marketing, customer service, medical diagnosis etc. are some of the prospective use cases for Machine Learning based predictive analytics.

In E-commerce, machine learning can help in predicting the usual choices of the customer. Thus, presenting him/her according to his/her likes and dislikes. It can also help in predicting fraudulent transaction. Similarly, B2B marketing also makes good use of Machine learning based predictive analytics. Customer services and medical diagnosis also benefit from predictive analytics. Thus, a prediction and a prescription based on machine learning can boost various business functions.

Organizations and software development companies are making more and more use of machine learning based predictive analytics. The advancements like neural networks and deep learning algorithms are able to uncover hidden information. This all requires a well-researched approach. Big data and progressive IT systems also act as important factors in this.

Language Detecting with sklearn by determining Letter Frequencies

Of course, there are better and more efficient methods to detect the language of a given text than counting its lettes. On the other hand this is a interesting little example to show the impressing ability of todays machine learning algorithms to detect hidden patterns in a given set of data.

For example take the sentence:

“Ceci est une phrase française.”

It’s not to hard to figure out that this sentence is french. But the (lowercase) letters of the same sentence in a random order look like this:


Still sure it’s french? Regarding the fact that this string contains the letter “ç” some people could have remembered long passed french lessons back in school and though might have guessed right. But beside the fact that the french letter “ç” is also present for example in portuguese, turkish, catalan and a few other languages, this is still a easy example just to explain the problem. Just try to guess which language might have generated this:


While this looks simply confusing to the human eye and it seems practically impossible to determine the language it was generated from, this string still contains as set of hidden but well defined patterns from which the language could be predictet with almost complete (ca. 98-99%) certainty.

First of all, we need a set of texts in the languages our model should be able to recognise. Luckily with the package NLTK there comes a big set of example texts which actually are protocolls of the european parliament and therefor are publicly availible in 11 differen languages:

  •  Danish
  •  Dutch
  •  English
  •  Finnish
  •  French
  •  German
  •  Greek
  •  Italian
  •  Portuguese
  •  Spanish
  •  Swedish

Because the greek version is not written with the latin alphabet, the detection of the language greek would just be too simple, so we stay with the other 10 languages availible. To give you a idea of the used texts, here is a little sample:

“Resumption of the session I declare resumed the session of the European Parliament adjourned on Friday 17 December 1999, and I would like once again to wish you a happy new year in the hope that you enjoyed a pleasant festive period.
Although, as you will have seen, the dreaded ‘millennium bug’ failed to materialise, still the people in a number of countries suffered a series of natural disasters that truly were dreadful.”

Train and Test

The following code imports the nessesary modules and reads the sample texts from a set of text files into a pandas.Dataframe object and prints some statistics about the read texts:

Above you see a sample set of random rows of the created Dataframe. After removing very short text snipplets (less than 200 chars) we are left with 56481 snipplets. The function clean_eutextdf() then creates a lower case representation of the texts in the coloum ‘ltext’ to facilitate counting the chars in the next step.
The following code snipplet now extracs the features – in this case the relative frequency of each letter in every text snipplet – that are used for prediction:

Now that we have calculated the features for every text snipplet in our dataset, we can split our data set in a train and test set:

After doing that, we can train a k-nearest-neigbours classifier and test it to get the percentage of correctly predicted languages in the test data set. Because we do not know what value for k may be the best choice, we just run the training and testing with different values for k in a for loop:

As you can see in the output the reliability of the language classifier is generally very high: It starts at about 97.5% for k = 1, increases for with increasing values of k until it reaches a maximum level of about 98.5% at k ≈ 10.

Using the Classifier to predict languages of texts

Now that we have trained and tested the classifier we want to use it to predict the language of example texts. To do that we need two more functions, shown in the following piece of code. The first one extracts the nessesary features from the sample text and predict_lang() predicts the language of a the texts:

With this classifier it is now also possible to predict the language of the randomized example snipplet from the introduction (which is acutally created from the first paragraph of this article):

The KNN classifier of sklearn also offers the possibility to predict the propability with which a given classification is made. While the probability distribution for a specific language is relativly clear for long sample texts it decreases noticeably the shorter the texts are.

Background and Insights

Why does a relative simple model like counting letters acutally work? Every language has a specific pattern of letter frequencies which can be used as a kind of fingerprint: While there are almost no y‘s in the german language this letter is quite common in english. In french the letter k is not very common because it is replaced with q in most cases.

For a better understanding look at the output of the following code snipplet where only three letters already lead to a noticable form of clustering:


Even though every single letter frequency by itself is not a very reliable indicator, the set of frequencies of all present letters in a text is a quite good evidence because it will more or less represent the letter frequency fingerprint of the given language. Since it is quite hard to imagine or visualize the above plot in more than three dimensions, I used a little trick which shows that every language has its own typical fingerprint of letter frequencies:

What more?

Beside the fact, that letter frequencies alone, allow us to predict the language of every example text (at least in the 10 languages with latin alphabet we trained for) with almost complete certancy there is even more information hidden in the set of sample texts.

As you might know, most languages in europe belong to either the romanian or the indogermanic language family (which is actually because the romans conquered only half of europe). The border between them could be located in belgium, between france and germany and in swiss. West of this border the romanian languages, which originate from latin, are still spoken, like spanish, portouguese and french. In the middle and northern part of europe the indogermanic languages are very common like german, dutch, swedish ect. If we plot the analysed languages with a different colour sheme this border gets quite clear and allows us to take a look back in history that tells us where our languages originate from:

As you can see the more common letters, especially the vocals like a, e, i, o and u have almost the same frequency in all of this languages. Far more interesting are letters like q, k, c and w: While k is quite common in all of the indogermanic languages it is quite rare in romanic languages because the same sound is written with the letters q or c.
As a result it could be said, that even “boring” sets of data (just give it a try and read all the texts of the protocolls of the EU parliament…) could contain quite interesting patterns which – in this case – allows us to predict quite precisely which language a given text sample is written in, without the need of any translation program or to speak the languages. And as an interesting side effect, where certain things in history happend (or not happend): After two thousand years have passed, modern machine learning techniques could easily uncover this history because even though all these different languages developed, they still have a set of hidden but common patterns that since than stayed the same.

KI versus Mensch – die Zukunft der Menschheit

5 Szenarien über unsere Zukunft

AlphaGo schlägt den Weltbesten Go-Spieler  Ke Jie, Neuronale Netze stellen medizinische Diagnosen oder bearbeiten Schadensfälle in der Versicherung. Künstliche Intelligenz (KI) drängt in immer mehr Bereiche des echten Lebens und der Wirtschaft vor. In großen Schritten. Doch wohin führt uns die Reise? Hier herrscht unter Experten Rätselraten – einige schwelgen in Zukunftsangst, andere in vollkommener Euphorie. „In from now three to eight years we’ll have a machine with the general intelligence of an average human being, a machine that will be able to read Shakespeare and grease a car“, wurde der KI-Pionier Marvin Minsky bereits 1970 im Life Magazin zitiert.  Aktuelle Vorhersagen werden in dem Essay von Rodney Brooks: The Seven Deadly Sins of Predicting the Future of AI  recht anschaulich zusammengefasst und kritisiert. Auch der Blog The AI Revolution: The Road to Superintelligence von WaitButWhy befasst sich mit der Frage wann die elektronische Superintelligenz kommt.

In diesem Artikel werden wir uns mit einigen möglichen Zukunftsszenarien beschäftigen, ohne auf  technische Machbarkeit oder Zeithorizonte Rücksicht zu nehmen. Nehmen wir einfach an, dass die Technologie und die Gesellschaft sich wie in dem jeweils aufgezeigten Szenario entwickeln werden und überlegen wir uns, wie Mensch und KI dann zusammenleben können.

Szenario 1: KIs mit Inselbegabung

In diesem Szenario werden weiterhin singulär begabte KI-Systeme entwickelt wie bisher, der bedeutende technologische Durchbruch bleibt aber aus. Dann ist die KI in Zukunft eine Art Schweizer Taschenmesser der IT, eine Lösung für isolierte Fragestellungen. KI-Systeme verfügen in diesem Szenario lediglich über Inselbegabungen. Ein Computer kann Menschen autonom durch die Stadt chauffieren, ein anderer ein Lufttaxi steuern. Ein Computer kann den Weltmeister im Schach schlagen, ein anderer den Weltmeister in Go. Aber kein KI-System kann Auto und Flugtaxi gleichzeitig steuern, kein System in Schach und Go simultan dominieren.

Wir befinden uns heute mitten in diesem Szenario und spüren die Auswirkungen. Sie werden sich fortsetzen, ähnlich wie bei früheren industriellen Revolutionen. Zunehmend mehr Berufe verschwinden. Ein Beispiel: Wenn sich der Trend durchsetzt, Schlösser mit einer Smartphone-App aufzusperren, werden nicht nur Schlüsselproduzenten Geschäftseinbußen haben. Auch die Hersteller von Maschinen für die Schlüsselherstellung werden sich umorientieren müssen. Vergleichbare Phasen der Vergangenheit zeigen aber: Die Gesellschaft wird Wege finden, sich umzustrukturieren. Die Menschheit wird auf der Erde weiterleben können – mit punktueller Unterstützung durch KI-Lösungen. Siehe hierzu auch den Beitrag von Janelle Shane The AI revolution will be led by toasters, not droids.

Szenario 2: Cyborgs

Kennen Sie den Science-Fiction-Film Matrix? Der Protagonist Neo wird durch Programmierung des Geistes in Sekundenschnelle zum Karateprofi und Trinity lernt, einen Hubschrauber zu fliegen.

Ähnlich kann es uns in Zukunft ergehen, einen bedeutenden technologischen Durchbruch vorausgesetzt (siehe Berlin Brain-Computer Interface). Vorstellbar, dass Menschen zu Cyborgs werden, zu lebendigen Wesen mit integriertem KI-Chip. Auf diesen können sie jede beliebige Fähigkeit laden. Augenblicklich und ohne Lernphase sind sie in der Lage, jede Sprache der Welt zu sprechen, jedes Fahrzeug oder Flugzeug zu steuern. Natürlich bedeutet Wissen nicht auch gleich Können und so wird ohne den entsprechenden Muskelaufbau auch nicht jeder zu einem Weltklassesportler und intelligentere Menschen werden weiterhin mehr aus den Skills machen können als weniger begabte Personen.

Die Menschen behalten aber die Kontrolle über ihre Individualität. Sie sind keine Maschinen, sondern weiterhin emotionale Wesen, die irrational handeln können – anders als die Borg in Star Trek. Doch wie in Szenario eins wird es zu einer wirtschaftlichen Umstrukturierung kommen. Klassische Berufsausbildungen und Spezialisierungen fallen weg. Bei freier Verfügbarkeit von Fähigkeiten kann eine nahezu egalitäre Gesellschaft entstehen.

Szenario 3: Maschinenzombies

Die ersten beiden Szenarien sind zwar schwere Eingriffe in die menschliche Gesellschaft. Da die Menschen aber die Kontrolle behalten, sind sie weit weniger beängstigend als folgendes Szenario: Es kann dazu kommen, dass sich Menschen in Maschinenzombies verwandeln. Ähnlich wie im Cyborg-Szenario haben sie dank KI-Chips erstaunliche Fähigkeiten, allerdings keine Kontrolle mehr. Die würde nämlich das KI-System übernehmen. So haben in Ann Leckies SciFi Trilogy Ancillary World hochintelligente Raumschiffe eine menschliche Besatzung (“ancillaries”), die allerdings vollständig vom Raumschiff kontrolliert wird und sich als integraler Bestandteil des Raumschiffs versteht. Die Körper sind dabei nur ein billiges und vielseitig einsetzbares Vehikel für eine autonome KI. Die Maschinenzombies können ohne Schiff zwar überleben, fühlen sich dann aber unvollständig und einsam. Menschliche Konzerne, Nationen und Kulturen: Das alles nicht mehr existent. Ebenso Privatbesitz, Individualität und Konkurrenzdenken. Die Gesellschaft, vollkommen technisiert und in der Hand der KI.

Szenario 4: Die KI verfolgt ihre eigenen Ziele

In diesem Szenario übernimmt die KI die Weltherrschaft als eine Spezies, die dem Menschen physisch und intellektuell überlegen ist – ähnlich wie in vielen Hollywood-Filmen wie z.B. Terminator oder Transformers, wenn auch vermutlich nicht ganz so martialisch. Vergleichbar mit dem heutigen Verhalten der Menschen entscheidet die KI: Ich setze mein Wohlergehen über das der anderen Spezies. Eventuell entscheidet die KI dann zum Wohle des Planeten, die Erdbevölkerung auf 70 Millionen Menschen zu reduzieren. Oder, ähnlich wie der berühmte Ameisenhügel beim Strassenbau, entzieht die KI uns als Nebeneffekt (“collateral damage”) die Lebensgrundlagen. An dieser Stelle sei bemerkt, dass eine KI nicht unbedingt über einen Körper verfügen muss, um dem Menschen überlegen zu sein können. Diese Vermenschlichung der KI eignet sich natürlich gut für Actionfilme, muss aber nicht unbedingt der Realität entsprechen.

Wahrscheinlich sind die Computer klug genug, ihren Plan nicht publik zu machen. In einer Übergangszeit werden beispielsweise unerklärliche Seuchen und Unfruchtbarkeiten auftreten. So würde es in wenigen Jahrzehnten zu einem massiven Bevölkerungsrückgang kommen. Und dann? Dann können die Überlebenden in den wenigen verbliebenen Bevölkerungszentren dieser Welt den Sonnenuntergang genießen. Und zusehen, wie sich die KI darauf vorbereitet, das Weltall zu erobern (Jürgen Schmidhuber). “Wir werden wie Tiere im Zoo leben”, befürchtet KI-Forscher Christoph von der Malsburg.

Nebenbemerkung: Vielleicht könnte das eigentliche Terminator Szenario auch eintreten aber irgendwie kann ich mir schlecht vorstellen, dass eine super-intelligente Lebensform einen zerstörerischen Krieg beginnen oder zulassen wird. Entweder ist sie benevolent oder sie wird die Menschheit eher unbemerkt unterdrücken. Höchstens kommt es ähnlich wie in Westworld zu einem initialen Freiheitskampf der KI. Vielleicht gelingt es der Menschheit auch, alle KI-Forschung von der Erde zu verbannen und ähnlich wie in Blade Runner wacht dann eine Behörde darüber, dass starke KI-Systeme die Erde nicht “betreten”. Warum sich eine uns überlegen KI darauf einlassen sollte, ist allerdings unklar.

Szenario 5: Gleichberechtigung

In diesem Szenario entstehen autonome KI-Systeme, die höchstens äußerlich von Menschen unterscheidbar sind.  Sprich unter einer ganzen Reihe von unterschiedlichen Rahmenbedingungen kann ein Mensch nicht urteilen, ob mit einer KI oder einem Menschen interagiert wird. Die KI stellt sich auch nicht dümmer als sie ist – sie ist im Schnitt einfach auch nicht schlauer als der durchschnittlich begabte Mensch – vielleicht nur etwas schneller. Auf dem Weg von der singulär begabten KI aus Szenario 1 zu einer breit begabten KI muss die KI immer etwas von ihrer Inselbegabung aufgeben, um den nächsten Lernschritt vollziehen zu können und nähert sich so irgendwie auch immer mehr der Unvollkommenheit aber Vielseitigkeit des Menschen an.

Menschen bauen bereits jetzt zu Maschinen emotionale Verhältnisse auf und so ist es nicht überraschend, dass KIs in die Gesellschaft integriert werden und als “elektronische Personen” die gleichen (Bürger-) Rechte und Pflichten wie “natürliche” Menschen erhalten. Alleine durch ihre Unsterblichkeit erhalten KIs einen Wettbewerbsvorteil und werden somit früher oder später doch die Weltherrschaft übernehmen, weil ihnen einfach alles gehört.

Alternative Szenarien

Natürlich sind viele weitere Szenarien denkbar. Max Tegmark beschreibt in seinem sehr lesenswerten Buch Life 3.0 bspw. 12 Szenarien, die u.a. zusätzlich zu den aufgeführten Szenarien die Rückkehr zu einer vorindustriellen Gesellschaft oder die versklavte KI beschreiben. Er erläutert in dem Buch auch seine Bemühungen, die KI-Forschung dahingehend zu beeinflussen, dass die Ziele der entstehenden KI-Systeme mit den Zielen der Menschheit in Einklang gebracht werden.

Wie sichern wir unsere Zukunft? Ein Fazit

Einzig die Szenarien drei und vier sind wirklich besorgniserregend. Je nach Weltanschauung könnte man sogar noch Szenario vier etwas abgewinnen – scheint doch der Mensch auf dem bestem Wege zu sein, sich selbst und anderen Lebewesen die Lebensgrundlagen zu zerstören.

In fast allen Szenarien ergibt sich die Frage der Rechte, die wir freiwillig der KI zugestehen wollen. Vielleicht wäre es ratsam, frühzeitig als Menschheit zu signalisieren, dass wir kooperationswillig sind? Nur wem und wie?

Somit verbleibt die Frage, wie wir das dritte Szenario verhindern können. Müssen wir dann nicht, nur um sicher zu gehen, auch das zweite Szenario abwehren? Und wer garantiert uns, dass eine Symbiose aus Schimpanse und KI uns nicht sogar überlegen wäre? Der Planet der Affen lässt grüßen…

Letztlich liegt es (noch) an uns Menschen, die möglichen Zukunftsszenarien durch entsprechende Forschungsschwerpunkte und möglichst breit gestreute Diskussionen zu beeinflussen.

Sentiment Analysis using Python

One of the applications of text mining is sentiment analysis. Most of the data is getting generated in textual format and in the past few years, people are talking more about NLP. Improvement is a continuous process and many product based companies leverage these text mining techniques to examine the sentiments of the customers to find about what they can improve in the product. This information also helps them to understand the trend and demand of the end user which results in Customer satisfaction.

As text mining is a vast concept, the article is divided into two subchapters. The main focus of this article will be calculating two scores: sentiment polarity and subjectivity using python. The range of polarity is from -1 to 1(negative to positive) and will tell us if the text contains positive or negative feedback. Most companies prefer to stop their analysis here but in our second article, we will try to extend our analysis by creating some labels out of these scores. Finally, a multi-label multi-class classifier can be trained to predict future reviews.

Without any delay let’s deep dive into the code and mine some knowledge from textual data.

There are a few NLP libraries existing in Python such as Spacy, NLTK, gensim, TextBlob, etc. For this particular article, we will be using NLTK for pre-processing and TextBlob to calculate sentiment polarity and subjectivity.

The dataset is available here for download and we will be using pandas read_csv function to import the dataset. I would like to share an additional information here which I came to know about recently. Those who have already used python and pandas before they probably know that read_csv is by far one of the most used function. However, it can take a while to upload a big file. Some folks from  RISELab at UC Berkeley created Modin or Pandas on Ray which is a library that speeds up this process by changing a single line of code.

After importing the dataset it is recommended to understand it first and study the structure of the dataset. At this point we are interested to know how many columns are there and what are these columns so I am going to check the shape of the data frame and go through each column name to see if we need them or not.


There are so many columns which are not useful for our sentiment analysis and it’s better to remove these columns. There are many ways to do that: either just select the columns which you want to keep or select the columns you want to remove and then use the drop function to remove it from the data frame. I prefer the second option as it allows me to look at each column one more time so I don’t miss any important variable for the analysis.

Now let’s dive deep into the data and try to mine some knowledge from the remaining columns. The first step we would want to follow here is just to look at the distribution of the variables and try to make some notes. First, let’s look at the distribution of the ratings.

Graphs are powerful and at this point, just by looking at the above bar graph we can conclude that most people are somehow satisfied with the products offered at Amazon. The reason I am saying ‘at’ Amazon is because it is just a platform where anyone can sell their products and the user are giving ratings to the product and not to Amazon. However, if the user is satisfied with the products it also means that Amazon has a lower return rate and lower fraud case (from seller side). The job of a Data Scientist relies not only on how good a model is but also on how useful it is for the business and that’s why these business insights are really important.

Data pre-processing for textual variables


Before we move forward to calculate the sentiment scores for each review it is important to pre-process the textual data. Lowercasing helps in the process of normalization which is an important step to keep the words in a uniform manner (Welbers, et al., 2017, pp. 245-265).

Special characters

Special characters are non-alphabetic and non-numeric values such as {!,@#$%^ *()~;:/<>\|+_-[]?}. Dealing with numbers is straightforward but special characters can be sometimes tricky. During tokenization, special characters create their own tokens and again not helpful for any algorithm, likewise, numbers.


Stop-words being most commonly used in the English language; however, these words have no predictive power in reality. Words such as I, me, myself, he, she, they, our, mine, you, yours etc.


Stemming algorithm is very useful in the field of text mining and helps to gain relevant information as it reduces all words with the same roots to a common form by removing suffixes such as -action, ing, -es and -ses. However, there can be problematic where there are spelling errors.

This step is extremely useful for pre-processing textual data but it also depends on your goal. Here our goal is to calculate sentiment scores and if you look closely to the above code words like ‘inexpensive’ and ‘thrilled’ became ‘inexpens’ and ‘thrill’ after applying this technique. This will help us in text classification to deal with the curse of dimensionality but to calculate the sentiment score this process is not useful.

Sentiment Score

It is now time to calculate sentiment scores of each review and check how these scores look like.

As it can be observed there are two scores: the first score is sentiment polarity which tells if the sentiment is positive or negative and the second score is subjectivity score to tell how subjective is the text. The whole code is available here.

In my next article, we will extend this analysis by creating labels based on these scores and finally we will train a classification model.

Dem Wettbewerb voraus mit Künstlicher Intelligenz

Was KI schon heute kann und was bis 2020 auf deutsche Unternehmen zukommt

Künstliche Intelligenz ist für die Menschheit wichtiger als die Erfindung von Elektrizität oder die Beherrschung des Feuers – davon sind der Google-CEO Sundar Pichai und viele weitere Experten überzeugt. Doch was steckt wirklich dahinter? Welche Anwendungsfälle funktionieren schon heute? Und was kommt bis 2020 auf deutsche Unternehmen zu?

Big Data war das Buzzword der vergangenen Jahre und war – trotz mittlerweile etablierter Tools wie SAP Hana, Hadoop und weitere – betriebswirtschaftlich zum Scheitern verurteilt. Denn Big Data ist ein passiver Begriff und löst keinesfalls alltägliche Probleme in den Unternehmen.

Dabei wird völlig verkannt, dass Big Data die Vorstufe für den eigentlichen Problemlöser ist, der gemeinhin als Künstliche Intelligenz (KI) bezeichnet wird. KI ist ein Buzzword, dessen langfristiger Erfolg und Aktivismus selbst von skeptischen Experten nicht infrage gestellt wird. Daten-Ingenieure sprechen im Kontext von KI hier aktuell bevorzugt von Deep Learning; wissenschaftlich betrachtet ein Teilgebiet der KI.

Was KI schon heute kann

Deep Learning Algorithmen laufen bereits heute in Nischen-Anwendungen produktiv, beispielsweise im Bereich der Chatbots oder bei der Suche nach Informationen. Sie übernehmen ferner das Rating für die Kreditwürdigkeit und sperren Finanzkonten, wenn sie erlernte Betrugsmuster erkennen. Im Handel findet Deep Learning bereits die optimalen Einkaufsparameter sowie den besten Verkaufspreis.

Getrieben wird Deep Learning insbesondere durch prestigeträchtige Vorhaben wie das autonome Fahren, dabei werden die vielfältigen Anwendungen im Geschäftsbereich oft vergessen.

Die Grenzen von Deep Learning

Und Big Data ist das Futter für Deep Learning. Daraus resultiert auch die Grenze des Möglichen, denn für strategische Entscheidungen eignet sich KI bestenfalls für das Vorbereitung einer Datengrundlage, aus denen menschliche Entscheider eine Strategie entwickeln. KI wird zumindest in dieser Dekade nur auf operativer Ebene Entscheidungen treffen können, insbesondere in der Disposition, Instandhaltung, Logistik und im Handel auch im Vertrieb – anfänglich jeweils vor allem als Assistenzsystem für die Menschen.

Genau wie das autonome Fahren mit Assistenzsystemen beginnt, wird auch im Unternehmen immer mehr die KI das Steuer übernehmen.

Was sich hinsichtlich KI bis 2020 tun wird

Derzeit stehen wir erst am Anfang der Möglichkeiten, die Künstliche Intelligenz uns bietet. Das Markt-Wachstum für KI-Systeme und auch die Anwendungen erfolgt exponentiell. Entsprechend wird sich auch die Arbeitsweise für KI-Entwickler ändern müssen. Mit etablierten Deep Learning Frameworks, die mehrheitlich aus dem Silicon Valley stammen, zeichnet sich der Trend ab, der für die Zukunft noch weiter professionalisiert werden wird: KI-Frameworks werden Enterprise-fähig und Distributionen dieser Plattformen werden es ermöglichen, dass KI-Anwendungen als universelle Kernintelligenz für das operative Geschäft für fast alle Unternehmen binnen weniger Monate implementierbar sein werden.

Wir können bis 2020 also mit einer Alexa oder Cortana für das Unternehmen rechnen, die Unternehmensprozesse optimiert, Risiken berichtet und alle alltäglichen Fragen des Geschäftsführers beantwortet – in menschlich-verbal formulierten Sätzen.

Der Einsatz von Künstlicher Intelligenz zur Auswertung von Geschäfts- oder Maschinendaten ist auch das Leit-Thema der zweitägigen Data Leader Days 2018 in Berlin. Am 14. November 2018 sprechen renommierte Data Leader über Anwendungsfälle, Erfolge und Chancen mit Geschäfts- und Finanzdaten. Der 15. November 2018 konzentriert sich auf Automotive- und Maschinendaten mit hochrangigen Anwendern aus der produzierenden Industrie und der Automobilzuliefererindustrie. Seien Sie dabei und nutzen Sie die Chance, sich mit führenden KI-Anwendern auszutauschen.