繁体   English   中英

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

[英]What's the fastest way to access a dataset with Java?

我有一个大文件,其中包含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
   }
data[x][y] = oneDdata.remove(0);

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

您至少要创建一个自定义TableModel,这样就不必两次复制数据。

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

如果要将其保持为CSV格式,则可以将ArrayList用作TableModel的数据存储。 因此,您的扫描程序代码会将数据直接读取到ArrayList中。 请参阅“ 列表表模型”以获取一种此类解决方案。 或者您可能想使用Bean Table Model

当然,真正的问题是谁将有时间浏览所有180万条记录? 因此,您实际上应该使用数据库并具有查询逻辑来过滤从数据库返回的行。

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

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

Sqllite是一个基于数据库的轻量级文件,据我说,这是解决您问题的最佳解决方案。

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

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

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

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

但是,如果您在两组数据上执行的逻辑/计算在SQL中具有等效功能,并且有一个单独的数据库运行良好的硬件(即更多的内存/ CPU),则可以通过Procedure / SQL中的功能可能会更好。

您可以使用opencsv包,它们的CSVReader可以遍历大型CSV文件,您还应该使用在线学习方法(如NaiveBayes,LinearRegression)处理此类大型数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM