public GaussianNormalizer(ArrayList<EssayInstance> trainingSample, Features base, String baseName, Type type)
		{
		means = new HashMap<Integer,double[]>();
		stddev = new HashMap<Integer,double[]>();
		baseFeature = base;
		this.baseName = baseName;
		
		name = baseName + "_" + type.toString().toLowerCase() + "_norm_task";
		this.type = type;
		
		HashMap<Integer,int[]> docs = new HashMap<Integer,int[]>();
		
		// compute the sums
		for (EssayInstance instance : trainingSample)
			{
			double value = getBaseValue(instance);
			
			if (!means.containsKey(instance.essay_set))
				means.put(instance.essay_set, new double[] { value });
			else
				means.get(instance.essay_set)[0] += value;
			
			if (!docs.containsKey(instance.essay_set))
				docs.put(instance.essay_set, new int[] { 1 });
			else
				docs.get(instance.essay_set)[0]++;
			}

		// now convert to means
		for (Integer task : means.keySet())
			means.get(task)[0] /= docs.get(task)[0];

		// now compute standard deviation
		for (EssayInstance instance : trainingSample)
			{
			double value = getBaseValue(instance);
			
			double dev = means.get(instance.essay_set)[0] - value;
			dev *= dev;
			
			if (!stddev.containsKey(instance.essay_set))
				stddev.put(instance.essay_set, new double[] { dev });
			else
				stddev.get(instance.essay_set)[0] += dev;
			}
		
		// normalize the stddev, root it
		for (Integer task : stddev.keySet())
			stddev.get(task)[0] = Math.sqrt(stddev.get(task)[0] / (docs.get(task)[0] - 1));

		// debugging info
		if (debug)
			{
			List<Integer> tasks = new ArrayList<Integer>(means.keySet());
			Collections.sort(tasks);
			for (Integer task : tasks)
				{
				System.out.println("Feature " + baseName + " for task/essay_set " + task + ":");
				System.out.println("\tx: " + means.get(task)[0]);
				System.out.println("\ts: " + stddev.get(task)[0]);
				}
			}
		}