我有一个包含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>(); //获取表的标题。 Scanner lineScan = new Scanner(f); Scanner s = new Scanner(lineScan.nextLine()); s.useDelimiter(","); while (s.hasNext()) { headers.add(s.next()); } //现在遍历表的每一行,并将每个单元格添加到数组列表中 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(); //将数据移动到一个普通数组中,以便可以放入表中。 for (int x = 0; x < numberRows; x++) { for (int y = 0; y < headers.size(); y++) { data[x][y] = oneDdata.remove(0); } } //创建一个表并返回它 return new DefaultTableModel(data, headers.toArray());}
更新:根据我收到的回答反馈,我重写了代码,现在运行10,000行只需3秒而不是6分钟,这意味着整个文件只需十分钟…但如果有进一步的加速建议,我将不胜感激:
//加载数据文件 File f = new File("data/primary_training_short.csv");
Scanner lineScan = new Scanner(f); Scanner s = new Scanner(lineScan.nextLine()); s.useDelimiter(","); //现在遍历结果的每一行 while (lineScan.hasNextLine()) { s = new Scanner(lineScan.nextLine()); s.useDelimiter(", *"); String[] data = new String[NUM_COLUMNS]; //从CSV文件中提取数据,以便我可以访问它 int x = 0; while (s.hasNext()) { data[x] = (s.next()); x++; } //在这里插入每行执行的代码 }
回答:
data[x][y] = oneDdata.remove(0);
这样做效率非常低。每当你从ArrayList中删除第一个条目时,所有其他条目都需要向下移动。
至少你应该创建一个自定义的TableModel,这样就不必复制数据两次了。
如果你想将数据保存在数据库中,那么请在网上搜索ResultSet TableModel。
如果你想保持CSV格式,那么你可以使用ArrayList作为TableModel的数据存储。因此,你的Scanner代码将直接将数据读取到ArrayList中。请参阅List Table Model以获取一种解决方案。或者你可能想使用Bean Table Model。
当然,真正的问题是谁有时间浏览所有180万条记录?所以你真的应该使用数据库,并有查询逻辑来过滤从数据库返回的行。
我的程序只需要访问每行数据一次,因此没有必要将整个数据集保存在RAM中
那么你为什么要在JTable中显示它呢?这意味着整个数据将在内存中。