public lognormalEM(int cluster, File dataFile, File resFile) throws FileNotFoundException, IOException { //vZRXgN^BĂ̒ʂ̓f[^t@CƏo͐t@Cw肷B
		List<Double> dataList = new ArrayList<Double>();
		
		stopWatch("Reading: " + dataFile.toString());
		/* RTO̕1sڂɃIWiTweetURLĂ̂ŁAf[^2sڂB
		 * ẴItZbgw肵ĂƁB
		 */

		InputStreamReader isr = new InputStreamReader(new FileInputStream(dataFile));
		BufferedReader br = new BufferedReader(isr);
		String head = br.readLine(); //擪s
		
		String line = new String();
		while((line = br.readLine()) != null) {//f[^Xgɓǂݍ݁Bnullit@CjŃuCNB
			try {
				StringTokenizer st = new StringTokenizer(line, ",");
				dataList.add(Double.parseDouble(st.nextToken()));
			} catch(NumberFormatException e) { //DoubleɃp[XłȂςȒl烊^[ĂB
				e.printStackTrace();
				br.close();
				isr.close();
				stopWatch("Unexpected Data Type. Aborting.");
				return;
			}
		}
		br.close();
		isr.close();
		
		int size = 0;
		for(int i=0; i<dataList.size(); i++) if(dataList.get(i) <= upperMax) size++;
		if (size < 100) { //1TԈȓRT100Ȃ甲B኱ꂷ
			stopWatch("Disqualified. Aborting.");
			return;
		}
		//double[] data = new double[dataList.size()];
		double[] data = new double[size];
		int dataMin = Integer.MAX_VALUE;
		int dataMax = 0;
		int dataIndex = 0;
		for(int i=0; i<dataList.size(); i++){ //ŃXgzɈڂւAȍ~͂̔z񂩂f[^QƂBdoublev~eBu^Ȃ̂ł傤ǂ\bhȂ炵
			if (dataList.get(i) <= upperMax) {//gpf[^Ɍōi
				data[dataIndex] = dataList.get(i);
				//data[dataIndex] = dataList.get(i) + lowerOffset;
				if (data[dataIndex] < dataMin) dataMin = (int)data[dataIndex];
				if (data[dataIndex] > dataMax) dataMax = (int)data[dataIndex];
				dataIndex++;
			}
		}
		dataList.clear();
		
		//NX^
		int[] initCluster = new int[size];
		if(cluster > 0) initCluster = kmeans(cluster, data, dataMin, dataMax, maxIter);
		else if(cluster == 0) {
			initCluster = kleinberg(cluster, data, dataMin, dataMax, maxIter);
			cluster = kleinbergCluster;
		}
		stopWatch("Processing EM for " + cluster + " cluster..");
		
		//p[^̏
		double[] weight = new double[cluster];
		double[] mean = new double[cluster];
		double[] var = new double[cluster];
		
		for (int k=0; k<cluster; k++) {
			weight[k] = 0.0;
			mean[k] = 0.0;
			var[k] = 0.0;
			
		}
		int[] dataNum = new int[cluster];
		for(int i=0; i<size; i++){
			int index = initCluster[i];
			dataNum[index]++;
			weight[index]++;
			/*if(data[i] >= 1) mean[index] += Math.log(data[i]);   //!!!
			else mean[index] += Math.log(altDelay);*/
			mean[index] += Math.log(data[i]);
		}
		for(int k=0; k<cluster; k++) {
			if(dataNum[k]==0) continue;
			weight[k] /= (double)size;
			mean[k] /= (double)dataNum[k];
		}
		for(int i=0; i<size; i++) {
			int index = initCluster[i];
			double gap = Math.log(data[i]) - mean[index];
			/*if(data[i] >= 1) gap = Math.log(data[i]) - mean[index];
			else gap = Math.log(altDelay) - mean[index];*/
			var[index] += gap*gap;
		}
		for(int k=0; k<cluster; k++) {
			var[k] /= (double)dataNum[k];
		}
		
		//Ce[^
		double[][] eAff = new double[size][cluster];
		final double cnst = Math.sqrt(2.0*Math.PI);
		ArrayList<Double> likelihoodSeries = new ArrayList<Double>();
		for(int itr=0; itr<maxIter; itr++){
			
			//EXebv
			double[] denom = new double[size];
			for(int i=0; i<size; i++){
				denom[i] = 0.0;
				for(int k=0; k<cluster; k++){
					try {
						if(var[k]==0) throw new Exception();
						/*else if(data[i] == 0){
							double gap = Math.log(altDelay) - mean[k];
							eAff[i][k] = weight[k] * Math.exp(-0.5*gap*gap/var[k])/(cnst*Math.sqrt(var[k]))/altDelay;
						}*/else {
							double gap = Math.log(data[i]) - mean[k];
							eAff[i][k] = weight[k] * Math.exp(-0.5*gap*gap/var[k])/(cnst*Math.sqrt(var[k]))/data[i];
						}
					} catch (Exception e) { //sK؂ȕUNX^catch
						e.printStackTrace();
						stopWatch("Some cluster doesn't have sufficient variance.");
						return;
					}
					denom[i] += eAff[i][k];
				}
				for(int k=0; k<cluster; k++){
					eAff[i][k] /= denom[i];
				}
			}
			
			//MXebv
			double[] sumAff = new double[cluster];
			for(int k=0; k<cluster; k++){
				weight[k] = 0.0;
				sumAff[k] = 0.0;
				mean[k] = 0.0;
				var[k] = 0.0;
				
				for(int i=0; i<size; i++){
					sumAff[k] += eAff[i][k];
					/*if(data[i]!=0) mean[k] += Math.log(data[i])*eAff[i][k];
					else mean[k] += Math.log(altDelay)*eAff[i][k];*/
					mean[k] += Math.log(data[i])*eAff[i][k];
				}
				weight[k] = sumAff[k]/(double)size;
				mean[k] /= sumAff[k];
				
				for(int i=0; i<size; i++){
					double gap = Math.log(data[i]) - mean[k];
					var[k] += gap*gap*eAff[i][k];
					/*if(data[i]!=0) {
						double gap = Math.log(data[i]) - mean[k];
						var[k] += gap*gap*eAff[i][k];
					}else{
						double gap = Math.log(altDelay) - mean[k];
						var[k] += gap*gap*eAff[i][k];
					}*/
				}
				
				var[k] /= sumAff[k];
				
				try{
					if(Double.isNaN(weight[k]) || Double.isNaN(var[k])){
						System.out.println(k);
						throw new Exception();
					}
				}catch(Exception e){
					e.printStackTrace();
					return;
				}
			}
			
			//ޓx
			double maxLikelihood = 0.0;
			for(int i=0; i<size; i++){
				double dataLikelihood = 0.0;
				for (int k=0; k<cluster; k++){
					/*double delay = data[i];
					if (delay < 1) delay = altDelay;
					double gap = Math.log(delay) - mean[k];
					double denomK = Math.sqrt(2 * Math.PI * var[k]) * delay;*/
					double gap = Math.log(data[i]) - mean[k];
					double denomK = Math.sqrt(2 * Math.PI * var[k]) * data[i];
					dataLikelihood += weight[k] * Math.exp(-0.5 * gap * gap / var[k]) / denomK;
				}
				maxLikelihood += Math.log(dataLikelihood);
			}
			if(itr % 10 == 0){
				likelihoodSeries.add(maxLikelihood);
				//stopWatch("\tLikelihood:\t" + maxLikelihood);
			}
		}
		
		
		stopWatch("Writing: " + resFile.toString());
		//ʏo
		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(resFile));
		BufferedWriter bw = new BufferedWriter(osw);
		bw.write(head);
		bw.newLine();
		
		//ߎȐvbgEo
		int range = dataMax - dataMin;
		int pitch = 10*60;
		int resol = range/pitch;
		for (int r=0; r<resol; r++) {
			double plot = 0.0;
			double subPlot = 0.0;
			int time = dataMin + pitch*r;
			bw.write(String.format("%d", time));
			for (int k=0; k<cluster; k++) {
				subPlot = weight[k] * lognormal(time, mean[k], var[k]);
				bw.write(String.format(",%f", subPlot));
				plot += subPlot;
			}
			bw.write(String.format(",%f", plot));
			bw.newLine();
		}
		bw.newLine();
		
		//NX^o
		for(int k=0; k<cluster; k++) {
			bw.write(String.format("#Cluster No.%d", k));
			bw.newLine();
			bw.write(String.format("weight: %f", weight[k]));
			bw.newLine();
			bw.write(String.format("mean: %f", mean[k]));
			bw.newLine();
			bw.write(String.format("variance: %f", var[k]));
			bw.newLine();
			bw.newLine();
		}
		
		//ޓxڏo
		for(int i=0; i<likelihoodSeries.size(); i++){
			bw.write(likelihoodSeries.get(i).toString());
			bw.newLine();
		}
		bw.close();
		osw.close();
		
		//criteriono
		if (criterion == AIC) AIC(cluster, size, data, mean, var, weight, resFile);
		else if (criterion == BIC) BIC(cluster, size, data, mean, var, weight, resFile);
	}