/** Builds the model from the files */
  public void extractKeyphrases(Hashtable stems) throws Exception {

    Vector stats = new Vector();

    // Check whether there is actually any data
    if (stems.size() == 0) {
      throw new Exception("Couldn't find any data!");
    }

    FastVector atts = new FastVector(2);
    atts.addElement(new Attribute("doc", (FastVector) null));
    atts.addElement(new Attribute("keyphrases", (FastVector) null));
    Instances data = new Instances("keyphrase_training_data", atts, 0);

    // Extract keyphrases
    Enumeration elem = stems.keys();
    while (elem.hasMoreElements()) {
      String str = (String) elem.nextElement();
      double[] newInst = new double[2];
      try {
        File txt = new File(m_dirName + "/" + str + ".txt");
        Reader is;
        if (!m_encoding.equals("default")) {
          is = new BomStrippingInputStreamReader(new FileInputStream(txt), m_encoding);
        } else {
          is = new BomStrippingInputStreamReader(new FileInputStream(txt));
        }
        StringBuffer txtStr = new StringBuffer();
        int c;
        while ((c = is.read()) != -1) {
          txtStr.append((char) c);
        }
        newInst[0] = (double) data.attribute(0).addStringValue(txtStr.toString());
      } catch (Exception e) {
        if (m_debug) {
          System.err.println("Can't read document " + str + ".txt");
        }
        newInst[0] = Instance.missingValue();
      }
      try {
        File key = new File(m_dirName + "/" + str + ".key");
        Reader is;
        if (!m_encoding.equals("default")) {
          is = new BomStrippingInputStreamReader(new FileInputStream(key), m_encoding);
        } else {
          is = new BomStrippingInputStreamReader(new FileInputStream(key));
        }
        StringBuffer keyStr = new StringBuffer();
        int c;
        while ((c = is.read()) != -1) {
          keyStr.append((char) c);
        }
        newInst[1] = (double) data.attribute(1).addStringValue(keyStr.toString());
      } catch (Exception e) {
        if (m_debug) {
          System.err.println("No keyphrases for stem " + str + ".");
        }
        newInst[1] = Instance.missingValue();
      }
      data.add(new Instance(1.0, newInst));
      m_KEAFilter.input(data.instance(0));
      data = data.stringFreeStructure();
      if (m_debug) {
        System.err.println("-- Document: " + str);
      }
      Instance[] topRankedInstances = new Instance[m_numPhrases];
      Instance inst;
      while ((inst = m_KEAFilter.output()) != null) {
        int index = (int) inst.value(m_KEAFilter.getRankIndex()) - 1;
        if (index < m_numPhrases) {
          topRankedInstances[index] = inst;
        }
      }
      if (m_debug) {
        System.err.println("-- Keyphrases and feature values:");
      }
      FileOutputStream out = null;
      PrintWriter printer = null;
      File key = new File(m_dirName + "/" + str + ".key");
      if (!key.exists()) {
        out = new FileOutputStream(m_dirName + "/" + str + ".key");
        if (!m_encoding.equals("default")) {
          printer = new PrintWriter(new OutputStreamWriter(out, m_encoding));
        } else {
          printer = new PrintWriter(out);
        }
      }
      double numExtracted = 0, numCorrect = 0;
      for (int i = 0; i < m_numPhrases; i++) {
        if (topRankedInstances[i] != null) {
          if (!topRankedInstances[i].isMissing(topRankedInstances[i].numAttributes() - 1)) {
            numExtracted += 1.0;
          }
          if ((int) topRankedInstances[i].value(topRankedInstances[i].numAttributes() - 1)
              == topRankedInstances[i]
                  .attribute(topRankedInstances[i].numAttributes() - 1)
                  .indexOfValue("True")) {
            numCorrect += 1.0;
          }
          if (printer != null) {
            printer.print(topRankedInstances[i].stringValue(m_KEAFilter.getUnstemmedPhraseIndex()));
            if (m_AdditionalInfo) {
              printer.print("\t");
              printer.print(topRankedInstances[i].stringValue(m_KEAFilter.getStemmedPhraseIndex()));
              printer.print("\t");
              printer.print(
                  Utils.doubleToString(
                      topRankedInstances[i].value(m_KEAFilter.getProbabilityIndex()), 4));
            }
            printer.println();
          }
          if (m_debug) {
            System.err.println(topRankedInstances[i]);
          }
        }
      }
      if (numExtracted > 0) {
        if (m_debug) {
          System.err.println("-- " + numCorrect + " correct");
        }
        stats.addElement(new Double(numCorrect));
      }
      if (printer != null) {
        printer.flush();
        printer.close();
        out.close();
      }
    }
    double[] st = new double[stats.size()];
    for (int i = 0; i < stats.size(); i++) {
      st[i] = ((Double) stats.elementAt(i)).doubleValue();
    }
    double avg = Utils.mean(st);
    double stdDev = Math.sqrt(Utils.variance(st));
    System.err.println(
        "Avg. number of correct keyphrases: "
            + Utils.doubleToString(avg, 2)
            + " +/- "
            + Utils.doubleToString(stdDev, 2));
    System.err.println("Based on " + stats.size() + " documents");
    m_KEAFilter.batchFinished();
  }