Java math DescriptiveStatistics删除值

时间:2012-08-29 13:49:26

标签: java statistics esper

我是Java的新手,并且一直在使用Esper CEP引擎。然而,这个问题与Esper无关,它更像是一个Java问题。

首先,我的班级: -

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;

import com.espertech.esper.epl.agg.AggregationSupport;
import com.espertech.esper.epl.agg.AggregationValidationContext;

public class CustomPercentiles extends AggregationSupport {
    private List<Double> numbers = new ArrayList<Double>();

    public CustomPercentiles(){
        super();
    }

    public void clear() {
        numbers.clear();
    }

    public void enter(Object arg0) {
        Double value = (Double) (double) (Integer) arg0;
        if (value > 0){
            //Not interested in < 1
            numbers.add(value);         
        }
    }

    public void leave(Object arg0) {
        Double value = (Double) (double) (Integer) arg0;
        if (value > 0){
            //Not interested in < 1
            numbers.remove(value);          
        }
    }

    public Object getValue() {
        DescriptiveStatistics stats = new DescriptiveStatistics();
        Map<String, Integer> result = new HashMap<String, Integer>();
        for (Double number:numbers.subList(0, numbers.size())){
            stats.addValue(number);     
        }
        result.put("median", (int) stats.getPercentile(50));
        result.put("pct90", (int) stats.getPercentile(90));
        result.put("pct10", (int) stats.getPercentile(10));
        result.put("mean", (int) stats.getMean());
        result.put("std", (int) stats.getStandardDeviation());

        return result ;
    }

    public Class getValueType() {
        return Object.class;
    }

    @Override
    public void validate(AggregationValidationContext arg0) {
        // TODO Auto-generated method stub
    }

}

基本上,Esper会根据逻辑不相关的方式调用enter(value)并保留(value)。它调用getValue()来获得计算结果。

由于我想计算百分位数,我需要所有可用的数字来处理它。为此,我将其存储在名为numbers的全局列表中,并在getValue()中将所有数字放入DescriptiveStatistics实例中,然后处理我需要的统计信息。

我的假设是,每次将列表作为新的DescriptiveStatistics对象时,都需要进行排序。有什么方法可以将类似DescriptiveStatistics的对象维护为我的全局对象吗?

我使用ArrayList和DescriptiveStatistics作为我的全局对象的唯一原因是DescriptiveStatistics没有remove方法。即我无法按值删除对象。

实际上,在任何给定时间都有数百个此类的实例运行,并且每1至10秒调用每个实例的getValue()。我目前没有任何性能问题,但我正在寻找一些优化帮助以避免将来出现问题。

替代解释: -

我在这里做的是保留一个数字列表。 Esper会多次调用enter()和leave()方法来告诉我列表中应该保留哪些数字。在我的情况下,这是基于时间的聚合。我告诉esper我想根据最近1分钟的数字进行计算。

So on 00:00:00 esper calls enter(10)
my numbers becomes [10]
So on 00:00:05 esper calls enter(15)
my numbers becomes [10, 15]
So on 00:00:55 esper calls enter(10)
my numbers becomes [10, 15, 10]
So on 00:01:00 esper calls leave(10)
my numbers becomes [15, 10]
So on 00:01:05 esper calls leave(15)
my numbers becomes [15]

现在,在这段时间内,getValue()可能已被多次调用。每次调用时,都应根据当前数字内容返回计算。

getValue()计算第10,第50和第90百分位数。为了计算百分位数,DescriptiveStatistics需要对数字进行排序。 (100个数字的第10个百分位将是排序后的第10个数字。)。

所以我正在寻找一种能够从DescriptiveStatistics实例中取出任何仲裁号的方法。或者要求推荐其他一些可以给我中位数和百分位数的图书馆,同时能够在知道价值的同时从列表中取出一个数字。

DescriptiveStatistics有一个removeMostRecentValue(),但这不是我想要做的。

1 个答案:

答案 0 :(得分:0)

据我了解,您要求使用DescriptiveStatistics - 类作为列表,而不是“数字”。这意味着,您希望动态添加和删除DescriptiveStatistics变量中的数字。

据我所知,没有比你现在所做的更好的方法。

在再次计算百分位数之前,您确定需要使用该功能从列表中删除特定号码吗?这不一定是新的数字吗?

听起来有点像你想学习更多Java的基础知识。

无论如何,由于我无法真正为您提供问题的合格答案,我认为我至少会帮助您纠正一些代码,以遵循更好的做法:

public class CustomPercentiles extends AggregationSupport {
    private List<Double> numbers = new ArrayList<Double>();

    //Methods that are inherited from super-classes and interfaces
    //should have the "@Override" annotation,
    //both for the compiler to check if it really is inherited,
    //but also to make it more clear which methods are new in this class.
    @Override    
    public void clear() {
        numbers.clear();
    }

    @Override
    public void enter(Object value) {
        double v = (double) value;
        if (v > 0){
            numbers.add(v);            
        }
    }

    @Override
    public void leave(Object value) {
        double v = (double) value;
        if (v > 0){
            numbers.remove(v);            
        }
    }

    @Override
    public Object getValues() {
        DescriptiveStatistics stats = new DescriptiveStatistics();
        Map<String, Integer> result = new HashMap<String, Integer>();
        //It is unnecessary to call number.subList(0, numbers.size())
        //since it will just return the entire list.
        for (Double number : numbers){
            stats.addValue(number);        
        }
        result.put("median", (int) stats.getPercentile(50));
        result.put("pct90", (int) stats.getPercentile(90));
        result.put("pct10", (int) stats.getPercentile(10));
        result.put("mean", (int) stats.getMean());
        result.put("std", (int) stats.getStandardDeviation());

        return result ;
    }

    //Judgning from the API of AggregationSupport,
    //I would say this method should return Double.class
    //(it basically seems like a bad way of implementing generics).
    //Are you sure it should return Object.class?
    public Class getValueType() {
        return Object.class;
    }

    @Override
    public void validate(AggregationValidationContext arg0) {
        // TODO Auto-generated method stub
    }

}