docs: @Override
      public void sortByLabel() {
          Map<Integer, Queue<DataSet>> map = new HashMap<>();
          List<DataSet> data = asList();
          int numLabels = numOutcomes();
          int examples = numExamples();
          for (DataSet d : data) {
              int label = d.outcome();
              Queue<DataSet> q = map.get(label);
              if (q == null) {
                  q = new ArrayDeque<>();
                  map.put(label, q);
              }
              q.add(d);
          }
  
          for (Map.Entry<Integer, Queue<DataSet>> label : map.entrySet()) {
              log.info("Label " + label + " has " + label.getValue().size() + " elements");
          }
  
          //ideal input splits: 1 of each label in each batch
          //after we run out of ideal batches: fall back to a new strategy
          boolean optimal = true;
          for (int i = 0; i < examples; i++) {
              if (optimal) {
                  for (int j = 0; j < numLabels; j++) {
                      Queue<DataSet> q = map.get(j);
                      if (q == null) {
                          optimal = false;
                          break;
                      }
                      DataSet next = q.poll();
                      //add a row; go to next
                      if (next != null) {
                          addRow(next, i);
                          i++;
                      } else {
                          optimal = false;
                          break;
                      }
                  }
              } else {
                  DataSet add = null;
                  for (Queue<DataSet> q : map.values()) {
                      if (!q.isEmpty()) {
                          add = q.poll();
                          break;
                      }
                  }
  
                  addRow(add, i);
  
              }
  
  
          }
  
  
      }