/*
* Encog(tm) Core v3.4 - Java Version
* http://www.heatonresearch.com/encog/
* https://github.com/encog/encog-java-core
* Copyright 2008-2016 Heaton Research, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* For more information on Heaton Research copyrights, licenses
* and trademarks visit:
* http://www.heatonresearch.com/copyright
*/
package org.encog.ml.data.buffer.codec;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import org.encog.ml.data.buffer.BufferedDataError;
import org.encog.util.EngineArray;
import org.encog.util.csv.CSVFormat;
import org.encog.util.csv.NumberList;
import org.encog.util.csv.ReadCSV;
/**
* A CODEC used to read/write data from/to a CSV data file. There are two
* constructors provided, one is for reading, the other for writing. Make sure
* you use the correct one for your intended purpose.
*
* This CODEC is typically used with the BinaryDataLoader, to load external data
* into the Encog binary training format.
*/
public class CSVDataCODEC implements DataSetCODEC {
/**
* The external CSV file.
*/
private final File file;
/**
* The CSV format to use.
*/
private final CSVFormat format;
/**
* The size of the input data.
*/
private int inputCount;
/**
* The size of the ideal data.
*/
private int idealCount;
/**
* True, if headers are present in the CSV file.
*/
private boolean headers;
/**
* The utility to assist in reading the CSV file.
*/
private ReadCSV readCSV;
/**
* A file used to output the CSV file.
*/
private PrintStream output;
/**
* True, if a significance column is expected.
*/
private boolean expectSignificance;
/**
* Constructor to create CSV from binary..
*
* @param theFile
* The CSV file to create.
* @param theFormat
* The format for that CSV file.
* @param theExpectSignificance
* True, if a significance column is expected.
*/
public CSVDataCODEC(final File theFile, final CSVFormat theFormat,
final boolean theExpectSignificance) {
this.file = theFile;
this.format = theFormat;
this.expectSignificance = theExpectSignificance;
}
/**
* Create a CODEC to load data from CSV to binary.
*
* @param theFile
* The CSV file to load.
* @param theFormat
* The format that the CSV file is in.
* @param theHeaders
* True, if there are headers.
* @param theInputCount
* The number of input columns.
* @param theIdealCount
* The number of ideal columns.
* @param theExpectSignificance
* True, if a significance column is expected.
*/
public CSVDataCODEC(final File theFile, final CSVFormat theFormat,
final boolean theHeaders, final int theInputCount,
final int theIdealCount, final boolean theExpectSignificance) {
this.file = theFile;
this.format = theFormat;
this.inputCount = theInputCount;
this.idealCount = theIdealCount;
this.headers = theHeaders;
this.expectSignificance = theExpectSignificance;
}
/**
* {@inheritDoc}
*/
@Override
public void close() {
if (this.readCSV != null) {
this.readCSV.close();
this.readCSV = null;
}
if (this.output != null) {
this.output.close();
this.output = null;
}
}
/**
* {@inheritDoc}
*/
@Override
public int getIdealSize() {
return this.idealCount;
}
/**
* {@inheritDoc}
*/
@Override
public int getInputSize() {
return this.inputCount;
}
/**
* Prepare to read from the CSV file.
*/
@Override
public void prepareRead() {
if (this.inputCount == 0) {
throw new BufferedDataError("To import CSV, you must use the "
+ "CSVDataCODEC constructor that specifies input and "
+ "ideal sizes.");
}
this.readCSV = new ReadCSV(this.file.toString(), this.headers,
this.format);
}
/**
* Prepare to write to a CSV file.
*
* @param recordCount
* The total record count, that will be written.
* @param inputSize
* The input size.
* @param idealSize
* The ideal size.
*/
@Override
public void prepareWrite(final int recordCount, final int inputSize,
final int idealSize) {
try {
this.inputCount = inputSize;
this.idealCount = idealSize;
this.output = new PrintStream(new FileOutputStream(this.file));
} catch (final IOException ex) {
throw new BufferedDataError(ex);
}
}
/**
* Read one record of data from a CSV file.
*
* @param input
* The input data array.
* @param ideal
* The ideal data array.
* @return True, if there is more data to be read.
*/
@Override
public boolean read(final double[] input, final double[] ideal,
double[] significance) {
if (this.readCSV.next()) {
int index = 0;
for (int i = 0; i < input.length; i++) {
input[i] = this.readCSV.getDouble(index++);
}
for (int i = 0; i < ideal.length; i++) {
ideal[i] = this.readCSV.getDouble(index++);
}
if (this.expectSignificance) {
significance[0] = this.readCSV.getDouble(index++);
} else {
significance[0] = 1.0;
}
return true;
} else {
return false;
}
}
/**
* Write one record of data to a CSV file.
*
* @param input
* The input data array.
* @param ideal
* The ideal data array.
*/
@Override
public void write(final double[] input, final double[] ideal,
double significance) {
if (this.expectSignificance) {
final double[] record = new double[input.length + ideal.length + 1];
EngineArray.arrayCopy(input, record);
EngineArray.arrayCopy(ideal, 0, record, input.length, ideal.length);
record[record.length - 1] = significance;
final StringBuilder result = new StringBuilder();
NumberList.toList(this.format, result, record);
this.output.println(result.toString());
} else {
final double[] record = new double[input.length + ideal.length];
EngineArray.arrayCopy(input, record);
EngineArray.arrayCopy(ideal, 0, record, input.length, ideal.length);
final StringBuilder result = new StringBuilder();
NumberList.toList(this.format, result, record);
this.output.println(result.toString());
}
}
}