package water.rapids.ast.prims.reducers;
import hex.quantile.Quantile;
import hex.quantile.QuantileModel;
import water.DKV;
import water.Key;
import water.fvec.Frame;
import water.fvec.Vec;
import water.rapids.Env;
import water.rapids.vals.ValNums;
import water.rapids.ast.AstPrimitive;
import water.rapids.ast.AstRoot;
/**
*/
public class AstMedian extends AstPrimitive {
@Override
public String[] args() {
return new String[]{"ary", "method"};
}
@Override
public String str() {
return "median";
}
@Override
public int nargs() {
return 1 + 2;
} // (median fr method)
@Override
public ValNums apply(Env env, Env.StackHelp stk, AstRoot asts[]) {
Frame fr = stk.track(asts[1].exec(env)).getFrame();
boolean narm = asts[2].exec(env).getNum() == 1;
double[] ds = new double[fr.numCols()];
Vec[] vecs = fr.vecs();
for (int i = 0; i < fr.numCols(); i++)
ds[i] = (!vecs[i].isNumeric() || vecs[i].length() == 0 || (!narm && vecs[i].naCnt() > 0)) ? Double.NaN : median(vecs[i], QuantileModel.CombineMethod.INTERPOLATE);
return new ValNums(ds);
}
public static double median(Frame fr, QuantileModel.CombineMethod combine_method) {
// Frame needs a Key for Quantile, might not have one from rapids
Key tk = null;
if (fr._key == null) {
DKV.put(tk = Key.make(), fr = new Frame(tk, fr.names(), fr.vecs()));
}
// Quantiles to get the median
QuantileModel.QuantileParameters parms = new QuantileModel.QuantileParameters();
parms._probs = new double[]{0.5};
parms._train = fr._key;
parms._combine_method = combine_method;
QuantileModel q = new Quantile(parms).trainModel().get();
double median = q._output._quantiles[0][0];
q.delete();
if (tk != null) {
DKV.remove(tk);
}
return median;
}
static double median(Vec v, QuantileModel.CombineMethod combine_method) {
return median(new Frame(v), combine_method);
}
}