All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.sandia.cognition.statistics.method.ConvexReceiverOperatingCharacteristic Maven / Gradle / Ivy

There is a newer version: 4.0.1
Show newest version
/*
 * File:                ConvexReceiverOperatingCharacteristic.java
 * Authors:             Kevin R. Dixon
 * Company:             Sandia National Laboratories
 * Project:             Cognitive Foundry
 * 
 * Copyright Sep 2, 2011, Sandia Corporation.
 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
 * license for use of this work by or on behalf of the U.S. Government.
 * Export of this program may require a license from the United States
 * Government. See CopyrightHistory.txt for complete details.
 * 
 */

package gov.sandia.cognition.statistics.method;

import gov.sandia.cognition.annotation.PublicationReference;
import gov.sandia.cognition.annotation.PublicationReferences;
import gov.sandia.cognition.annotation.PublicationType;
import gov.sandia.cognition.evaluator.Evaluator;
import gov.sandia.cognition.statistics.method.ReceiverOperatingCharacteristic.DataPoint;
import gov.sandia.cognition.util.AbstractCloneableSerializable;
import gov.sandia.cognition.util.ObjectUtil;
import java.util.ArrayList;


/**
 * Computes the convex hull of the Receiver Operating Characteristic (ROC),
 * which a mathematician might call a "concave down" function.
 * curve.
 * @author Kevin R. Dixon
 * @since 3.2.1
 */
@PublicationReferences(
    references={
        @PublicationReference(
            author="Wikipedia",
            title="Concave function",
            type=PublicationType.WebPage,
            year=2011,
            url="http://en.wikipedia.org/wiki/Concave_function"
        )
        ,
        @PublicationReference(
            author="Wikipedia",
            title="Convex hull",
            type=PublicationType.WebPage,
            year=2011,
            url="http://en.wikipedia.org/wiki/Convex_hull"
        )
    }
)
public class ConvexReceiverOperatingCharacteristic 
    extends AbstractCloneableSerializable
    implements Evaluator
{

    /**
     * Convex hull of the ROC curve
     */
    private ArrayList convexHull;

    /** 
     * Creates a new instance of HandHMeasure 
     * @param convexHull
     * Convex hull of the ROC curve
     */
    private ConvexReceiverOperatingCharacteristic(
        ArrayList convexHull )
    {
        this.setConvexHull(convexHull);
    }

    @Override
    public ConvexReceiverOperatingCharacteristic clone()
    {
        ConvexReceiverOperatingCharacteristic clone =
            (ConvexReceiverOperatingCharacteristic) super.clone();
        clone.setConvexHull(
            ObjectUtil.cloneSmartElementsAsArrayList( this.getConvexHull() ) );
        return clone;
    }

    /**
     * Computes the convex hull values using a trapezoid interpolation.
     * @param input
     * falsePositiveRate from which to estimate the truePositiveRate
     * @return
     * TruePositiveRate for the given FalsePositiveRate
     */
    @Override
    public Double evaluate(
        Double input )
    {
        final double falsePositiveRate = input;

        double truePositiveRate = 0.0;
        ArrayList data = this.getConvexHull();
        final int N = data.size();
        for( int i = N-1; i >= 0; i-- )
        {
            ReceiverOperatingCharacteristic.DataPoint value = data.get(i);
            final double x = value.getFalsePositiveRate();

            // No need to interpolate if we're exactly on a point
            if( x == falsePositiveRate )
            {
                truePositiveRate = value.getTruePositiveRate();
                break;
            }
            else if( x < falsePositiveRate )
            {
                if( i < N-1 )
                {
                    ReceiverOperatingCharacteristic.DataPoint right = data.get(i+1);
                    final double run = right.getFalsePositiveRate() - x;
                    final double y = value.getTruePositiveRate();
                    final double rise = right.getTruePositiveRate() - y;
                    final double slope = rise/run;
                    final double delta = falsePositiveRate - x;
                    truePositiveRate = y + delta*slope;
                }
                else
                {
                    truePositiveRate = 1.0;
                }
                break;
            }

        }

        return truePositiveRate;

    }

    /**
     * Computes the convex hull of a ROC curve
     * @param roc
     * ROC curve from which to extract the convex hull
     * @return
     * Convex hull over the ROC curve
     */
    public static ConvexReceiverOperatingCharacteristic computeConvexNull(
        ReceiverOperatingCharacteristic roc )
    {
        ArrayList origRocData =
            roc.getSortedROCData();

        ArrayList convexRoc =
            new ArrayList( origRocData.size() );
        int leftIndex = 0;
        ReceiverOperatingCharacteristic.DataPoint left =
            origRocData.get(leftIndex);
        convexRoc.add( left );

        boolean done = false;
        while( !done )
        {
            // Walk the "right" point toward the "left" point until no points
            // between them are in between on the y-axis
            left = origRocData.get(leftIndex);
            int rightIndex = origRocData.size()-1;

            if( leftIndex >= rightIndex )
            {
                done = true;
                break;
            }

            boolean foundAbove = false;
            while( rightIndex > leftIndex )
            {
                foundAbove = false;
                ReceiverOperatingCharacteristic.DataPoint right =
                    origRocData.get(rightIndex);

                double rise = right.getTruePositiveRate() - left.getTruePositiveRate();
                double run = right.getFalsePositiveRate() - left.getFalsePositiveRate();
                if( run == 0.0 )
                {
                    // If we get here then we've seen nothing but points above
                    // us... that means we're done.
                    foundAbove = false;
                }
                else
                {
                    double slope = rise / run;

                    for( int i = rightIndex-1; i > leftIndex; i-- )
                    {
                        ReceiverOperatingCharacteristic.DataPoint point =
                            origRocData.get(i);

                        double xdiff = point.getFalsePositiveRate() - right.getFalsePositiveRate();

                        // This is y-value the estimated convex hull without this point
                        double yhat = right.getTruePositiveRate() + xdiff * slope;

                        // If "point" is above estimated convex hull, then keep
                        // walking the right point toward the left point
                        if( yhat < point.getTruePositiveRate() )
                        {
                            rightIndex = i;
                            foundAbove = true;
                            break;
                        }

                    }
                }

                // No points were above the convex hull with the (left,right)
                // combo... so we've found the next pair!!
                // The "right" point becomes the next "left" point
                if( !foundAbove )
                {
                    convexRoc.add( right );
                    leftIndex = rightIndex;
                    break;
                }
            }

            leftIndex = rightIndex;

        }

        ConvexReceiverOperatingCharacteristic roch =
            new ConvexReceiverOperatingCharacteristic(convexRoc);
        return roch;

    }

    /**
     * Computes the area under the convex hull
     * @return
     * Area under the convex hull
     */
    public double computeAreaUnderConvexHull()
    {
        return ReceiverOperatingCharacteristic.Statistic.computeAreaUnderCurveTrapezoid(
            this.getConvexHull() );
    }

    /**
     * Getter for convexHull
     * @return
     * Convex hull of the ROC curve
     */
    public ArrayList getConvexHull()
    {
        return this.convexHull;
    }

    /**
     * Setter for convexHull
     * @param convexHull
     * Convex hull of the ROC curve
     */
    protected void setConvexHull(
        ArrayList convexHull)
    {
        this.convexHull = convexHull;
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy