使用Java访问数据集的最快方法是什么?

时间:2011-04-16 02:42:44

标签: java machine-learning

我有一个大文件,有180万行数据,我需要能够读取我正在编写的机器学习程序。数据目前是CSV文件,但显然我可以根据需要将其放在数据库或其他结构中 - 它不需要定期更新。

我目前使用的代码如下。我首先将数据导入数组列表,然后将其传递给表模型。这是非常缓慢的,目前只花了六分钟执行前10,000行,这是不可接受的,因为我需要能够经常测试不同的算法数据。

我的程序只需要访问数据的每一行,因此不需要将整个数据集保存在RAM中。我最好不要从数据库中读取数据,还是有更好的方法逐行读取CSV文件但是更快?

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

public class CSVpaser {

public static TableModel parse(File f) throws FileNotFoundException {
    ArrayList<String> headers = new ArrayList<String>();
    ArrayList<String> oneDdata = new ArrayList<String>();
    //Get the headers of the table.
    Scanner lineScan = new Scanner(f);
    Scanner s = new Scanner(lineScan.nextLine());
    s.useDelimiter(",");
    while (s.hasNext()) {
        headers.add(s.next());
    }

    //Now go through each line of the table and add each cell to the array list
    while (lineScan.hasNextLine()) {
       s =  new Scanner(lineScan.nextLine());
       s.useDelimiter(", *");
       while (s.hasNext()) {
           oneDdata.add(s.next());
       }
    }
    String[][] data = new String[oneDdata.size()/headers.size()][headers.size()];
    int numberRows = oneDdata.size()/headers.size();

    // Move the data into a vanilla array so it can be put in a table.
    for (int x = 0; x < numberRows; x++) {
        for (int y = 0; y < headers.size(); y++) {
            data[x][y] = oneDdata.remove(0);
        }
    }

    // Create a table and return it
    return new DefaultTableModel(data, headers.toArray());


}

更新: 根据我在答案中收到的反馈,我已经重写了代码,它现在运行3秒而不是6分钟(10,000行),这意味着整个文件只有10分钟......但是对于如何加速的任何进一步的建议我们将不胜感激:

       //load data file
    File f = new File("data/primary_training_short.csv");
    Scanner lineScan = new Scanner(f);
    Scanner s = new Scanner(lineScan.nextLine());
    s.useDelimiter(",");

    //now go through each line of the results
    while (lineScan.hasNextLine()) {
       s =  new Scanner(lineScan.nextLine());
       s.useDelimiter(", *");
       String[] data = new String[NUM_COLUMNS];

       //get the data out of the CSV file so I can access it
       int x = 0;
       while (s.hasNext()) {
           data[x] = (s.next());
           x++;
       }
       //insert code here which is excecuted each line
   }

4 个答案:

答案 0 :(得分:5)

data[x][y] = oneDdata.remove(0);

那将是非常低效的。每次从ArrayList中删除第一个条目时,所有其他条目都需要向下移动。

您至少需要创建自定义TableModel,因此您不必复制数据两次。

如果要将数据保存在数据库中,请在网上搜索ResultSet TableModel。

如果要将其保留为CSV格式,则可以使用ArrayList作为TableModel的数据存储。因此,您的扫描程序代码会将数据直接读入ArrayList。有关此类解决方案,请参阅List Table Model。或者您可能想要使用Bean Table Model

当然真正的问题是谁将有时间浏览所有1.8M记录?所以你真的应该使用数据库并使用查询逻辑来过滤从数据库返回的行。

  

我的程序只需要访问数据的每一行,因此不需要将整个数据集保存在RAM中

那么为什么要在JTable中显示它?这意味着整个数据将存储在内存中。

答案 1 :(得分:3)

Sqllite是一个非常轻量级的文件数据库,据我所知,是解决问题的最佳解决方案。

查看java这个非常好的驱动程序。我将它用于我的一个NLP项目,它的效果非常好。

答案 2 :(得分:0)

这就是我所理解的:您的要求是对加载的数据执行某些算法,并且在运行时也是如此

  • 加载一组数据
  • 执行一些计算
  • 加载另一组数据
  • 执行更多计算,依此类推,直到我们到达CSV结尾

由于两组数据和算法/计算之间没有关联,你在数据上做的是一个自定义逻辑(SQL中没有内置函数),这意味着你可以用Java做到这一点即使不使用任何数据库,这应该是最快的。

但是如果你在两组数据上执行的逻辑/计算在SQL中有一些等效的功能,并且有一个单独的数据库运行良好的硬件(更多的内存/ CPU),执行整个逻辑SQL中的过程/函数可以更好地执行。

答案 3 :(得分:0)

您可以使用opencsv软件包,它们的CSV阅读器可以迭代大型CSV文件,您还应该使用Naive Bayes,线性回归等在线学习方法来处理大型数据。