def gini_index(groups, classes):
    """Calculate the Gini index for a split dataset.
    A perfect separation results in a Gini score of 0,
    whereas the worst case split that results in
    50/50 classes in each group result in a Gini
    score of 0.5 (for a 2 class problem)

    Args:
        groups: the list of groups representing the data split.
        Each group is comprised of data instances, where the last
        attribute represents the class/label

        classes: the possible class values (labels) included in the domain

    Returns: a float point number representing the Gini index for the given split
    """
    n_instances = sum([len(group) for group in groups])
    gini = 0.0
    for g in groups:
        size = len(g)
        if size == 0:
            continue
        score = 0.0
        # score the group based on the proportion of each class
        for class_val in classes:
            proportion = [row[-1] for row in g].count(class_val) / size
            score += proportion * proportion
        # weight the group score by its relative size
        gini += (1.0 - score) * (size / n_instances)

    return gini