загрузка большой матрицы из текстового файла в массивы Java - PullRequest
2 голосов
/ 21 июня 2011

Мои данные хранятся в больших матрицах, которые хранятся в текстовых файлах с миллионами строк и 4 столбцами значений, разделенных запятыми. (В каждом столбце хранится отдельная переменная, а в каждой строке хранятся разные миллисекунды для всех четырех переменных.) В первых дюжинах строк есть также несколько не относящихся к делу данных заголовка. Мне нужно написать код Java для загрузки этих данных в четыре массива, с одним массивом для каждого столбца в матрице TXT. Код 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,

EDIT

Я проверил предложение кода Shilaghae. Вроде работает. Однако длина всех полученных массивов такая же, как у x1Count, поэтому нули остаются в тех местах, где код сопоставления с образцом Shilaghae не может разместить число. (Это результат того, как я изначально написал код.)

У меня были проблемы с поиском индексов, где остаются нули, но, похоже, было намного больше нулей, кроме ожидаемых там, где был заголовок. Когда я изобразил производную от вывода temp [1], я увидел ряд резких пиков, где могут быть ложные нули в temp [1]. Если я скажу, где находятся нули в temp [1], temp [2] и temp [3], я смогу изменить сопоставление с образцом, чтобы лучше сохранить все данные.

Кроме того, было бы неплохо просто сократить выходной массив, чтобы он больше не включал строки, в которых заголовок находился во входном файле. Однако, учебники, которые я нашел относительно массивов переменной длины, показывают только упрощенные примеры, такие как:

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

Код может работать быстрее, если он больше не использует scan1 для создания scan1Count. Я не хочу замедлять код, используя неэффективный метод для создания массива переменной длины. И я также не хочу пропускать данные в своих временных рядах в тех случаях, когда сопоставление с образцом не может разбить входную строку на 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 - в последнем столбце.


ЗАКЛЮЧИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ

Окончательный код был очень простым и просто включал использование 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;
        }

Спасибо за помощь всем. Я собираюсь закрыть эту ветку сейчас, потому что на вопрос был дан ответ.

Ответы [ 3 ]

1 голос
/ 21 июня 2011

Вы можете прочитать строку в строку файла и для каждой строки вы можете управлять с помощью регулярного выражения (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;
        }
0 голосов
/ 21 июня 2011

Я бы справился с проблемой заголовков, просто пытаясь разобрать каждую строку как четыре числа и выбрасывая все строки, где синтаксический анализ не работает. Если после строк заголовка существует вероятность неразборчивых строк, вы можете установить флаг при первом получении «хорошей» строки, а затем сообщить о любых последующих «плохих» строках.

Разбить строки с помощью String.split(...). Это не самый быстрый способ сделать это, но процессорное время вашей программы будет потрачено в другом месте ... так что это, вероятно, не имеет значения.

0 голосов
/ 21 июня 2011

Вы можете разделить каждую строку, используя String.split () .

Чтобы пропустить заголовки, вы можете либо прочитать первые N строк, но и отбросить их (если вы знаете, сколькоесть) или вам нужно будет искать конкретный маркер - трудно посоветовать, не видя ваших данных.

Возможно, вам также придется немного изменить свой подход, поскольку в настоящее время вы, похоже, определяете размеры массивов в соответствии собщее количество строк (при условии, что ваш сканер возвращает строки?), а не количество строк заголовка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...