将文本文件中的大型矩阵加载到Java数组中

fzwojiic  于 2023-05-12  发布在  Java
关注(0)|答案(4)|浏览(101)

我的数据存储在大型矩阵中,这些矩阵存储在文本文件中,有数百万行和4列逗号分隔的值。(每一列存储一个不同的变量,每一行存储所有四个变量的不同毫秒的数据。)在前十几行中还有一些不相关的标题数据。我需要编写Java代码来将这些数据加载到四个数组中,文本矩阵中的每一列对应一个数组。
Java代码还需要能够判断头何时完成,以便第一个数据行可以被拆分为4个数组的条目。最后,Java代码需要遍历数百万个数据行,重复将每行分解为四个数字的过程,每个数字都输入到数字所在列的适当数组中。
我如何修改下面的代码来实现这一点?我想找到最快的方法来完成数百万行的处理。
下面是我的代码:
MainClass2.java

package packages;

public class MainClass2{
    public static void main(String[] args){
    readfile2 r = new readfile2();
    r.openFile();
    int x1Count = r.readFile();
    r.populateArray(x1Count);
    r.closeFile();  
}
}

readfile2.java

package packages;

import java.io.*;
import java.util.*;

public class readfile2 {
private Scanner scan1;
private Scanner scan2;

public void openFile(){
    try{
        scan1 = new Scanner(new File("C:\\test\\samedatafile.txt"));
        scan1 = new Scanner(new File("C:\\test\\samedatafile.txt"));
    }
    catch(Exception e){
        System.out.println("could not find file");
    }
}
public int readFile(){
    int scan1Count = 0;
    while(scan1.hasNext()){
        scan1.next();
        scan1Count += 1;
    }
    return scan1Count;
}
public double[] populateArray(int scan1Count){
    double[] outputArray1 = new double[scan1Count];
    double[] outputArray2 = new double[scan1Count];
    double[] outputArray3 = new double[scan1Count];
    double[] outputArray4 = new double[scan1Count];
    int i = 0;
    while(scan2.hasNext()){
        //what code do I write here to:
        //  1.) identify the start of my time series rows after the end of the header rows (e.g. row starts with a number AT LEAST 4 digits in length.)
        //  2.) split each time series row's data into a separate new entry for each of the 4 output arrays
        i++;
    }
    return outputArray1, outputArray2, outputArray3, outputArray4;
}
public void closeFile(){
    scan1.close();
    scan2.close();
}
}

以下是典型数据文件的前19行:

text and numbers on first line
1 msec/sample
3 channels
ECG
Volts
Z_Hamming_0_05_LPF
Ohms
dz/dt
Volts
min,CH2,CH4,CH41,
,3087747,3087747,3087747,
0,-0.0518799,17.0624,0,
1.66667E-05,-0.0509644,17.0624,-0.00288295,
3.33333E-05,-0.0497437,17.0624,-0.00983428,
5E-05,-0.0482178,17.0624,-0.0161573,
6.66667E-05,-0.0466919,17.0624,-0.0204402,
8.33333E-05,-0.0448608,17.0624,-0.0213986,
0.0001,-0.0427246,17.0624,-0.0207532,
0.000116667,-0.0405884,17.0624,-0.0229672,

编辑

我测试了Shilaghae的代码建议。似乎起作用了。然而,所有结果数组的长度都与x1Count相同,因此在Shilaghae的模式匹配代码无法放置数字的地方仍保留零。(这是我最初编写代码的结果。
我很难找到零仍然存在的索引,但似乎有很多零除了那些预期的头在哪里。当我绘制temp[1]输出的导数时,我看到了一些尖锐的尖峰,其中temp[1]中的假零可能是。如果我能知道temp[1]、temp[2]和temp[3]中的零在哪里,我就可以修改模式匹配,以更好地保留所有数据。
另外,最好是简单地缩短输出数组,使其不再包含输入文件中头所在的行。然而,我找到的关于可变长度数组的教程只显示了过于简化的示例,如:

int[] anArray = {100, 200, 300, 400};

如果代码不再使用scan 1来生成scan 1Count,则它可能会运行得更快。我不想使用低效的方法来生成可变长度数组,从而降低代码的速度。我也不想在模式匹配无法将输入行拆分为4个数字的情况下跳过时间序列中的数据。我宁愿保留时间序列中的零,这样我就可以找到它们并使用它们来调试模式匹配。
这些事情可以在快速运行的代码中完成吗?

二次编辑

所以呢

"-{0,1}\\d+.\\d+,"

在表达式中重复多次:

"-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,"

是吗

"-{0,1}\\d+.\\d+,"

分解为以下三个语句:

"-{0,1}" means that a minus sign occurs zero or one times, while  

"\\d+." means that the minus sign(or lack of minus sign) is followed by several digits of any value followed by a decimal point, so that finally  

"\\d+," means that the decimal point is followed by several digits of any value?

如果是这样,那么我的数据中的数字如“1.66667E-05”或“-8.06131E-05”怎么办?我刚刚扫描了一个输入文件,(在3+百万个4列行中)它包含638个包含E的数字,其中5个在第一列,633个在最后一列。

ehxuflar

ehxuflar1#

您可以逐行读取文件,并且对于每一行都可以使用正则表达式(http://www.vogella.de/articles/JavaRegularExpressions/article.html)进行控制,前提是该行正好显示4个逗号。如果这一行正好有4个逗号,你可以用String.split来分割这一行,然后填充4个数组,否则你就在下一行传递。

public double[][] populateArray(int scan1Count){
            double[] outputArray1 = new double[scan1Count];
            double[] outputArray2 = new double[scan1Count];
            double[] outputArray3 = new double[scan1Count];
            double[] outputArray4 = new double[scan1Count];

            //Read File Line By Line
            try {
                File tempfile = new File("samedatafile.txt");
                FileInputStream fis = new FileInputStream(tempfile);
                DataInputStream in = new DataInputStream(fis);
                BufferedReader br = new BufferedReader(new InputStreamReader(in));      
                String strLine;
                int i = 0;
                while ((strLine = br.readLine()) != null)   {
                      Pattern pattern = Pattern.compile("-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,-{0,1}\\d+.\\d+,");
                      Matcher matcher = pattern.matcher(strLine);
                      if (matcher.matches()){
                          String[] split = strLine.split(",");              
                          outputArray1[i] = Double.parseDouble(split[0]);
                          outputArray2[i] = Double.parseDouble(split[1]);
                          outputArray3[i] = Double.parseDouble(split[2]);
                          outputArray4[i] = Double.parseDouble(split[3]);
                      }
                      i++;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            double[][] temp = new double[4][];
            temp[0]= outputArray1;
            temp[1]= outputArray2;
            temp[2]= outputArray3;
            temp[3]= outputArray4;
            return temp;
        }
2izufjch

2izufjch2#

可以使用String.split()拆分每一行。
要跳过标题,您可以阅读前N行并丢弃它们(如果您知道有多少行),或者您需要寻找特定的标记-在没有看到数据的情况下很难提供建议。
您可能还需要稍微改变一下方法,因为您目前似乎是根据总行数来调整数组的大小(假设您的Scanner返回行数?)而不是省略标题行的计数。

wkftcu5l

wkftcu5l3#

我会通过简单地尝试将every行解析为四个数字来处理标题的问题,并丢弃解析不起作用的任何行。如果在标题行之后可能有不可解析的行,那么您可以在第一次获得“好”行时设置一个标志,然后报告任何后续的“坏”行。
String.split(...)分割行。这不是绝对最快的方法,但你的程序的CPU时间将花在其他地方。所以这可能不重要

qhhrdooz

qhhrdooz4#

  • (代表问题作者将解决方案移动到答案空间)。*

最后的代码非常简单,只涉及使用string.split()和“,”作为正则表达式。为此,我必须手动删除输入文件中的标题,以便数据只包含用4个逗号分隔的数字的行。
如果有人好奇,最后的工作代码是:

public double[][] populateArray(int scan1Count){
    double[] outputArray1 = new double[scan1Count];
    double[] outputArray2 = new double[scan1Count];
    double[] outputArray3 = new double[scan1Count];
    double[] outputArray4 = new double[scan1Count];
    
    try {
        File tempfile = new File("C:\\test\\mydatafile.txt");
        FileInputStream fis = new FileInputStream(tempfile);
        DataInputStream in = new DataInputStream(fis);
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String strLine;
        int i = 0;
        while ((strLine = br.readLine()) != null)   {
                String[] split = strLine.split(",");
                outputArray1[i] = Double.parseDouble(split[0]);
                outputArray2[i] = Double.parseDouble(split[1]);
                outputArray3[i] = Double.parseDouble(split[2]);
                outputArray4[i] = Double.parseDouble(split[3]);
            i++;
            }
        } catch (IOException e) {
            System.out.println("e for exception is:"+e);
            e.printStackTrace();
            }
        double[][] temp = new double[4][];
        temp[0]= outputArray1;
        temp[1]= outputArray2;
        temp[2]= outputArray3;
        temp[3]= outputArray4;
        return temp;
        }

相关问题