private Instances [] prepareData(Instances originalData, boolean firstTime) throws Exception {
    
    int numAttributes = originalData.numAttributes();
    int classIndex = originalData.classIndex();
    
    // determine attributes that won't be used in the imputation (all missing or all one value or nonnumeric class attribute)
    if (firstTime == true) {
      String unusedAttributeIndices = "";
      m_unusedAtts = new boolean[numAttributes];
      for (int j = 0; j < numAttributes; j++) {
        AttributeStats currentStats = originalData.attributeStats(j);
        if ((classIndex == j && originalData.classAttribute().isNumeric() == false) ||
            currentStats.distinctCount < 2) {
          m_unusedAtts[j] = true;
          unusedAttributeIndices += (j + 2) + ",";
        } else {
          m_unusedAtts[j] = false;
        }
      }
      if (unusedAttributeIndices.contentEquals("") == false) {
        // set up remove filter
        m_unusedAttributeRemover = new Remove();
        m_unusedAttributeRemover.setInvertSelection(false);
        m_unusedAttributeRemover.setAttributeIndices(unusedAttributeIndices);
      }
    }
    
    // preprocess for working with the missing values
    Instances preprocessed = prepareMissing(originalData);
    
    // remove attributes that won't be used
    Instances withClass = new Instances(preprocessed, 0, preprocessed.numInstances()); // to store class values
    if (m_unusedAttributeRemover != null) {
      m_unusedAttributeRemover.setInputFormat(preprocessed);
      preprocessed = Filter.useFilter(preprocessed, m_unusedAttributeRemover);
      preprocessed.setClassIndex(-1);
    }
    
    // if preparing the first time data, set parameters
    if (firstTime == true) {
      m_numAttributes = preprocessed.numAttributes() - 1;
      m_means = new double[m_numAttributes];
      m_stdDevs = new double[m_numAttributes];
      for (int i = 1; i < m_numAttributes + 1; i++) {
        Stats columnStats = preprocessed.attributeStats(i).numericStats;
        columnStats.calculateDerived();
        m_means[i - 1] = columnStats.mean;
        m_stdDevs[i - 1] = columnStats.stdDev;
      }
    }
    
    // standardize data (to avoid rounding errors)
    standardize(preprocessed);
    
    // return array of datasets
    Instances [] data = new Instances[2];
    data[0] = preprocessed;
    data[1] = withClass;
    return data;
  }