/**
   * Reconstruct a parzen window classifier from serialized data.
   *
   * @param model
   * @param classes
   * @return
   */
  @Import(ModelType.CLASSIFIER)
  public static ParzenWindowClassifier newInstance(
      Map<String, Object> model, Map<ClassDescriptor, Map<String, Object>> classes) {

    ParzenWindowClassifier classifier;

    double radius = Double.parseDouble((String) model.get("radius"));
    int dimension = Integer.parseInt((String) model.get("dimension"));
    KernelType type;

    if (((String) model.get("kernel")).equals("normal")) {
      type = KernelType.NORMAL;
    } else {
      type = KernelType.UNIFORM;
    }

    classifier = new ParzenWindowClassifier(radius, type);

    for (ClassDescriptor c : classes.keySet()) {
      double[][] a = (double[][]) classes.get(c).get("vectors");
      List<double[]> l = new ArrayList<double[]>(a.length);

      for (int i = 0; i < a.length; i++) {
        l.add(a[i]);
      }

      // reconstruct covariance matrix
      double[] mean = MaximumLikelihoodEstimation.getMean(l, dimension);
      double[][] cov = MaximumLikelihoodEstimation.getCovariance(l, mean);

      Kernel kernel = type.getKernel(cov, radius);

      classifier.distributions.put(c, new ParzenDistribution(kernel, l));
    }

    return classifier;
  }
  @Override
  protected void doTrain(Map<ClassDescriptor, List<double[]>> data, int dimension) {

    this.dimension = dimension;

    for (ClassDescriptor c : data.keySet()) {
      /*
       * Estimate covariance using ML.
       */
      double[] mean = MaximumLikelihoodEstimation.getMean(data.get(c), dimension);
      double[][] cov = MaximumLikelihoodEstimation.getCovariance(data.get(c), mean);

      Kernel kernel = type.getKernel(cov, radius);

      distributions.put(c, new ParzenDistribution(kernel, data.get(c)));
    }
  }