package hex; import water.*; import water.api.DocGen; import water.fvec.createInteractions; import water.fvec.Frame; import water.util.Log; import water.util.RString; import java.util.Arrays; /** * Create new factors that represent interactions of the given factors */ public class Interaction extends Job { static final int API_WEAVER=1; // This file has auto-gen'd doc & json fields static public DocGen.FieldDoc[] DOC_FIELDS; // Initialized from Auto-Gen code. @API(help = "Input data frame", required = true, filter = Default.class, json=true) public Frame source; @API(help = "Column indices (0-based) of factors for which interaction is to be computed", filter=colsNamesIdxFilter.class, displayName="Interaction columns") public int[] factors = new int[0]; class colsNamesIdxFilter extends MultiVecSelect { public colsNamesIdxFilter() {super("source", MultiVecSelectType.NAMES_THEN_INDEXES); } } @API(help = "Whether to create pairwise quadratic interactions between factors (otherwise create one higher-order interaction). Only applicable if there are 3 or more factors.", required = false, filter = Default.class, json=true) public boolean pairwise = false; @API(help = "Max. number of factor levels in pair-wise interaction terms (if enforced, one extra catch-all factor will be made)", required = true, filter = Default.class, lmin = 1, lmax = Integer.MAX_VALUE, json=true) public int max_factors = 100; @API(help = "Min. occurrence threshold for factor levels in pair-wise interaction terms", required = true, filter = Default.class, lmin = 1, lmax = Integer.MAX_VALUE, json=true) public int min_occurrence = 1; long _time; @Override public Response serve() { try { source.read_lock(self()); // if (max_factors < 1) throw new IllegalArgumentException("max_factors must be >1."); if (factors.length == 0) throw new IllegalArgumentException("factors must be non-empty."); if (pairwise && factors.length < 3) Log.info("Ignoring the pairwise option, requires 3 or more factors."); for (int v: factors) { if (!source.vecs()[v].isEnum()) { throw new IllegalArgumentException("Column " + source.names()[v] + " is not a factor."); } } if (destination_key == null) { String target = source._key.toString() + ".interaction."; target += "C" + factors[0]; for (int i=1; i<factors.length; ++i) { target += "_C" + factors[i]; } destination_key = Key.make(target); } Timer time = new Timer(); final createInteractions in = new createInteractions(this); H2O.submitTask(in); in.join(); _time = time.time(); Log.info(report()); return Response.done(this); } catch( Throwable t ) { return Response.error(t); } finally { source.unlock(self()); } } @Override public boolean toHTML( StringBuilder sb ) { Frame fr = UKV.get(dest()); if (fr==null) { return false; } RString aft = new RString("<a href='Inspect2.html?src_key=%$key'>%key</a>"); aft.replace("key", destination_key.toString()); DocGen.HTML.section(sb, report() + "<br/>Frame '" + aft.toString() + "' contains the interaction feature(s)."); return true; } private String report() { Frame res = UKV.get(dest()); if (!pairwise) return "Created interaction feature " + res.names()[0] + " (order: " + factors.length + ") with " + res.lastVec().domain().length + " factor levels" + " in" + PrettyPrint.msecs(_time, true); else return "Created " + res.numCols() + " pair-wise interaction features " + Arrays.deepToString(res.names()) + " (order: 2) in" + PrettyPrint.msecs(_time, true); } }