private String generateCSVData() {
    StringBuilder sb = new StringBuilder();
    for (Region r : data_points) {
      boolean first = true;
      for (Feature f : this.features) {
        if (!first) {
          sb.append(",");
        } else {
          first = false;
        }
        if (r.getAttribute(f.getName()) == null) {
          AuToBIUtils.debug("missing attribute:" + f.getName() + " on word:" +
              r.toString());

          // Weka's arff standard uses the question mark (?) to indicate missing values
          sb.append("?");
        } else {
          String value = r.getAttribute(f.getName()).toString();
          if (value.length() == 0) {
            AuToBIUtils.warn("Empty value for attribute:" + f.getName() + " on " + r);
          }
          sb.append(value);
        }
        if (f.isNominal() || (f.getNominalValues() != null && f.getNominalValues().size() > 0)) {
          f.addNominalValue(r.getAttribute(f.getName()).toString());
        }
      }

      sb.append("\n");
    }
    return sb.toString();
  }