Java LibSVMFormatReader

„svm-predict“ gibt für die one-class-SVM scheinbar nur die vorhergesagten Labels zurück, nicht aber die Vorhersagewerte für die Daten. Da das auch für die Java-libsvm-Varriante gilt – die ich in der Android-App zu meiner Masterarbeit benutze – hier eine Klasse, die aus einer Datei im libsvm-Format die Daten in der internen libsvm-Datenstruktur zurückgibt (d. h. als svm_node[][]). Damit kann man dann nach Belieben eine der „predict“-Funktionen von libsvm aufrufen und somit auch die Vorhersagewerte erhalten.

Nachdem die Klasse fertig war, habe ich doch noch in der Java-libsvm-Implementierung ähnliche Funktionalität entdeckt (svm_predict.java – predict(BufferedReader, DataOutputStream, svm_model, int) und musste feststellen, dass ich mir mehr Gedanken bei der Regex hätte machen sollen ;). Aber nun ist es fertig und dafür wenigstens alleinstehend ohne „predict“-Funktion drum herum – vielleicht hilft es ja noch jemandem.

import java.io.BufferedReader;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;

import libsvmimpl.libsvm.svm_node;

public class LibSVMFormatReader {

	private BufferedReader libsvmFormatFileReader;
	private svm_node[][] x;
	private double[] y;

	//////////////////
	// Constructors //
	//////////////////
	public LibSVMFormatReader(String libSVMFormatFilename) throws IOException {
		this(new File(libSVMFormatFilename));
	}

	public LibSVMFormatReader(BufferedReader buf) throws IOException {
		this.libsvmFormatFileReader = buf;
		convert();
	}

	public LibSVMFormatReader(File libSVMFormatFile) throws IOException {
		this(new BufferedReader(new InputStreamReader(new FileInputStream(
				libSVMFormatFile))));
	}

	////////////////
	// Converters //
	////////////////
	private void convert() throws IOException {
		ArrayList<svm_node[]> nodeArrayList = new ArrayList<svm_node[]>();
		ArrayList labelsList = new ArrayList();

		String line;
		while ((line = this.libsvmFormatFileReader.readLine()) != null) {
			nodeArrayList.add(devideRow(line));
			labelsList.add(getLabel(line));
		}

		// Copy references 1 by 1:
		svm_node[][] svm_nodeArray = new svm_node[nodeArrayList.size()][];
		double[] labels = new double[labelsList.size()];
		if (labels.length != svm_nodeArray.length) {
			throw new IllegalArgumentException(
					"Converting to Java-libsvm failed: could not find the same number of labels and vectors.");
		}

		for (int i = 0; i < svm_nodeArray.length; i++) {
			svm_nodeArray[i] = nodeArrayList.get(i);
			labels[i] = labelsList.get(i);
		}

		this.x = svm_nodeArray;
		this.y = labels;
	}

	private double getLabel(String line) {
		double ret = Double.NaN;
		try {
			ret = Double.parseDouble(line.split("\\s")[0]);
		} catch (NumberFormatException e) {
			throw new IllegalArgumentException(
					"Could not parse label to double-value.", e);
		} catch (ArrayIndexOutOfBoundsException e) {
			throw new IllegalArgumentException(
					"Could split line into different parts.", e);
		}
		return ret;
	}

	/**
	 * This method takes one row from the libsvm-format and converts it into a
	 * svm_node[]. On error it throws an exception.
	 * 
	 * @param row
	 * @return
	 */
	private svm_node[] devideRow(String row) {
		try {
			svm_node tNode;
			String[] tSplit;
			String tToken;

			ArrayList<svm_node> nodes = new ArrayList<svm_node>();

			// TODO Try out which space or character works finest:
			String[] segs = row.split("\\s");
			for (String string : segs) {
				// Skip first - its the label
				// and make sure there nothing suspicious:
				tToken = string.trim();
				if (tToken.contains(":")) {
					tNode = new svm_node();
					tSplit = tToken.split(":");
					tNode.index = Integer.parseInt(tSplit[0]);
					tNode.value = Double.parseDouble(tSplit[1]);
					nodes.add(tNode);
				}
			}

			// Copy to array 1 by 1:
			svm_node[] svm_nodes = new svm_node[nodes.size()];
			for (int i = 0; i < svm_nodes.length; i++) {
				svm_nodes[i] = nodes.get(i);
			}

			if (svm_nodes.length == 0) {
				throw new IllegalArgumentException(
						"No index-value-pairs found.");
			}

			return svm_nodes;

		} catch (NumberFormatException e) {
			throw new IllegalArgumentException(
					"Could not parse index or value into a number. Please proof your file.",
					e);
		}
	}

	/////////////////
	// getXYZ(...) //
	/////////////////

	public double[] getY() {
		return y;
	}

	public svm_node[][] getX() {
		return x;
	}

	/*
	 * Test-Main ...
	 */
	public static void main(String[] args) {
		try {
			LibSVMFormatReader libSVMFormatReader = new LibSVMFormatReader(
					"/Volumes/Android/BENIGN/LEARNDATA/libsvm/MW/25/BUSINESS_25_MW.libsvmS");
			svm_node[][] nA = libSVMFormatReader.x;
			double[] y = libSVMFormatReader.y;
			for (int i = 0; i < y.length; i++) {
				System.out.print("LABEL: " + y[i] + " ");
				for (svm_node node : nA[i]) {
					System.out.print(node);
				}
				System.out.println();
			}

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
LibSVMFormatReader
LibSVMFormatReader
LibSVMFormatReader.java
4.2 KiB
651 Downloads
Details
LibSVMFormatReader
LibSVMFormatReader
LibSVMFormatReader.java
4.2 KiB
651 Downloads
Details

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.