async function getNormalizedDatasets(
    count, featureMeans, featureStddevs, labelMean, labelStddev,
    validationSplit, evaluationSplit) {
  tf.util.assert(
      validationSplit > 0 && validationSplit < 1,
      () => `validationSplit is expected to be >0 and <1, ` +
            `but got ${validationSplit}`);
  tf.util.assert(
      evaluationSplit > 0 && evaluationSplit < 1,
      () => `evaluationSplit is expected to be >0 and <1, ` +
            `but got ${evaluationSplit}`);
  tf.util.assert(
      validationSplit + evaluationSplit < 1,
      () => `The sum of validationSplit and evaluationSplit exceeds 1`);

  const dataset = tf.data.csv(HOUSING_CSV_URL, {
    columnConfigs: {
      [labelColumn]: {
        isLabel: true
      }
    }
  });

  const featureValues = [];
  const labelValues = [];
  const indices = [];
  const iterator = await dataset.iterator();
  for (let i = 0; i < count; ++i) {
    const {value, done} = await iterator.next();
    if (done) {
      break;
    }
    featureColumns.map(feature => {
      featureValues.push(
          (value.xs[feature] - featureMeans[feature]) /
          featureStddevs[feature]);
    });
    labelValues.push((value.ys[labelColumn] - labelMean) / labelStddev);
    indices.push(i);
  }

  const xs = tf.tensor2d(featureValues, [count, featureColumns.length]);
  const ys = tf.tensor2d(labelValues, [count, 1]);

  // Set random seed to fix shuffling order and therefore to fix the
  // training, validation, and evaluation splits.
  Math.seedrandom('1337');
  tf.util.shuffle(indices);

  const numTrain = Math.round(count * (1 - validationSplit - evaluationSplit));
  const numVal = Math.round(count * validationSplit);
  const trainXs = xs.gather(indices.slice(0, numTrain));
  const trainYs = ys.gather(indices.slice(0, numTrain));
  const valXs = xs.gather(indices.slice(numTrain, numTrain + numVal));
  const valYs = ys.gather(indices.slice(numTrain, numTrain + numVal));
  const evalXs = xs.gather(indices.slice(numTrain + numVal));
  const evalYs = ys.gather(indices.slice(numTrain + numVal));

  return {trainXs, trainYs, valXs, valYs, evalXs, evalYs};

}
Get a dataset with the features and label z-normalized,
the dataset is split into three xs-ys tensor pairs: for training,
validation and evaluation.

@param {number} count Number of rows in the CSV dataset, computed beforehand.
@param {{[feature: string]: number}} featureMeans Arithmetic means of the
  features. Use for normalization.
@param {[feature: string]: number} featureStddevs Standard deviations of the
  features. Used for normalization.
@param {number} labelMean Arithmetic mean of the label. Used for
  normalization.
@param {number} labelStddev Standard deviation of the label. Used for
  normalization.
@param {number} validationSplit Validation spilt, must be >0 and <1.
@param {number} evaluationSplit Evaluation split, must be >0 and <1.
@returns An object consisting of the following keys:
  trainXs {tf.Tensor} training feature tensor
  trainYs {tf.Tensor} training label tensor
  valXs {tf.Tensor} validation feature tensor
  valYs {tf.Tensor} validation label tensor
  evalXs {tf.Tensor} evaluation feature tensor
  evalYs {tf.Tensor} evaluation label tensor.