項目筆記(二)

之前是十分基礎的各項數據處理,但就是基礎的數據處理,還是在昨天師兄的幫助下,最後完工的。

出現了各種錯誤,各種完全想不到的錯誤。


根據項目真正實施的步驟展開來總結自己的項目,遇到的各種問題,以及當時的解決方案,對解決方案的分析和現在仍然有的困惑。

目的就是對10000行,每行有15*4*101*101個數據,得出10000*15個max(4個101*101矩陣)。解決思路很簡單。

最一開始的思路就是直接放到MATLAB上去跑,但是在讀取數據的時候最少花費了半個小時,然後直接報出了內存超限的錯誤。

所以想到的思路就是應該先將文件進行切割。我對java比較熟,所以就直接用的java。將過程分爲了兩部分,一部分是切割文件,另一部分是遍歷文件,具體處理,求得最大值。


(1)切割文件

對於這部分絕對是一把辛酸淚

。因爲在最一開始的時候下的功夫比較大,源文件總共有16G,肯定不能直接打開,所以無法直接驗證切分是否正確,只能很小心的寫代碼。但是最後的最後,返工了4次,都是因爲最一開始的切分文件發生了錯誤,至今不知道到底錯在了哪裏。但是挑出來了幾個錯誤,感覺比較有意思。



我自認爲這個程序是沒有任何問題的,但是在運行的時候就是會有問題。在前面180次循環是沒有問題的,只要循環查過180,之後寫入的,就會全部是空文件,然後我現在也不知道錯在了哪裏。不過就算不說內存的問題。這個代碼寫的絕對是不好的。首先,在讀取文件的時候。沒有使用buffer。使用buffer會減少IO次數,加快速度,這就是一點缺陷。先放下不明白的問題。在循環180次停掉之後,想的就是重新跑程序,不過是略過前180次。

然後改一下程序,變成這樣:

public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            File file = new File("D:\\forcast\\needed\\train_deal.txt");
            FileReader fr;
            fr = new FileReader(file);
            LineNumberReader lnr = new LineNumberReader(fr);
            String line ;
            int MAX = 10000,unit_length = 10;
            for(int i = 0;i < MAX/unit_length;i++) {
                System.out.println(i);
                if(i<180)
                                      continue;
                                File fileW = new File("D:\\forcast\\trainneededadd\\data"+i+".txt");
                FileWriter frw;
                frw = new FileWriter(fileW);
                int line_num = 0;//設定每一個樣本的行數爲10
                while((line = lnr.readLine())!= null && line_num < unit_length) {
                    


                                        line_num++;




                    frw.write(line + "\r\n");//寫入處理好的數據
                }
                frw.close();
            }
            fr.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        


    }








剛寫完自認爲很完美,但是在師兄師姐處理後續工作的時候,生成圖像,發現這麼180之後和前20個是一樣的。我驚出一身冷汗,趕緊查找代碼。然後意識到一個很嚴重的問題。這段代碼的意思不就是等待循環180次的時候,文件是180的時候,纔開始寫入數據嗎,那麼當然後20個和前20個是一樣的,自然需要修改程序。改成了下面的形式:


public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            File file = new File("D:\\forcast\\needed\\train_deal.txt");
            FileReader fr;
            fr = new FileReader(file);
            LineNumberReader lnr = new LineNumberReader(fr);
            String line ;
            int MAX = 10000,unit_length = 10;
            for(int i = 0;i < MAX/unit_length;i++) {
                System.out.println(i);
                                File fileW = new File("D:\\forcast\\trainneededadd\\data"+i+".txt");
                FileWriter frw;
                frw = new FileWriter(fileW);
                int line_num = 0;//設定每一個樣本的行數爲10
                while((line = lnr.readLine())!= null && line_num < unit_length) {
                    


                                        if(i<180)
                                              continue;


                                         line_num++;
                                         frw.write(line + "\r\n");//寫入處理好的數據
                }
                frw.close();
            }
             fr.close();
            } catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}








這是很自然生成的一種思路。如果不是後20個程序,雖然還進入循環,那我直接就不讓他們寫入文件就可以了呀。並且在查找後面的文件的時候,發現,沒問題,的確是不同的,和前面完全。


但是把結果上傳之後,想着問題難不成就這麼簡單的解決的時候,突然意識到,我不應該用break。這樣的意思是對於前180次循環來說,當每次循環讀完一行之後,直接退出while循環,然後進行下一次for循環。所以我最一開始讀到第180個文件中的第一行,不是原文件的第1801行,而是原文件的第181行。我真個人被華麗麗的驚呆了。剛剛傳上去改正版啊,結果又得接着改正,那沒辦法,接着改吧。也比較好改,就是把break改成continue。但是要注意的是,之前的文件是還會生成的,只是沒有寫入
public static void main(String[] args) {
        // TODO Auto-generated method stub
        try {
            File file = new File("D:\\forcast\\needed\\train_deal.txt");
            FileReader fr;
            fr = new FileReader(file);
            LineNumberReader lnr = new LineNumberReader(fr);
            String line ;
            int MAX = 10000,unit_length = 10;
            for(int i = 0;i < MAX/unit_length;i++) {
                System.out.println(i);
                                File fileW = new File("D:\\forcast\\trainneededadd\\data"+i+".txt");
                FileWriter frw;
                frw = new FileWriter(fileW);
                int line_num = 0;//設定每一個樣本的行數爲10
                while((line = lnr.readLine())!= null && line_num < unit_length) {
                    
                                       line_num++;
                                       if(i<180)
                                             continue;
                    frw.write(line + "\r\n");//寫入處理好的數據
                }
                frw.close();
            }
            fr.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        


    }
然後我覺得,終於沒有問題了。然而只能說我圖樣圖森破。這次師兄師姐都不敢直接用了[笑哭],一個很nice的師兄給我驗證了一下,然後發現驚天大錯誤。我的數據從第10行開始,求得的結果都不對,都不對,都不對。好像說一句,蒼天,把這些數據都收走吧,我再也不想看到他們了。然而,在不想看到之前,怎麼着也得算出來正確的。。。。。。然後對問題就找啊找,找啊找,還是沒找到。直接上師兄的python。到這裏,我只能弱弱的說一句,python大法好。
import numpy as np


infile = open('B.txt', 'r')
lines = infile.readlines()
for i, line in enumerate(lines):  # 2000 sample
    a = np.array(line.split(' '), dtype='uint8')
    b = a.reshape(15, 4, 101 * 101)
    if (i + 1) % 50 == 0:
        print('read sample %d' % (i + 1))
    for j in range(15):  # 15 moments
        temp = b[j][0]
        for k in range(1, 4):  # 4 hights
            temp = np.maximum(b[j][k], temp)
        maxd = temp.reshape(101, 101).T
        np.savetxt('./A/A_%d.txt' % (i * 15 + j + 1), maxd, fmt='%d')


25行,就結束了,就結束了,就結束了。其中還有兩行只是爲了顯示程序執行進度。讓我吃根冰棍兒冷靜一下。


然後我通宵跑完的數據,師兄一個小時搞定了,搞定了。搞定了。整個人如何一個酸爽了得。


然後看程序的邏輯及其清晰。並且我當初作死自信的覺得自己的筆記本一定比服務器快,然而,啪啪打臉。


只能說,在下次寫程序之前,一定要打好腹稿,不是說讓程序多簡單,而是一定要邏輯清晰。我絕對就是因爲邏輯太混亂。導致總是會出現很隱蔽的錯誤。關鍵是現在還沒有排查出來,這就很尷尬了。




我懷疑是內存的問題。或者說我並沒有真正明白自己使用的函數的含義。我試着查找每一行全部數據的個數。如果讀入的數據值正確的話,那麼會輸出612059(我檢測的是中間空格的數量),但是發現有小部分的數據並不是有612059個空格,大概有100個多。拿這個問題就很嚴重了,連讀入的數據都一行沒有讀滿,那之後還如何生成結果。可以最奇怪的就是一樣的函數,原始數據不會有錯誤,但是就是有的可以,可以說是大多數是可以的,但有的就是會出錯。所以就聯想到了緩衝區,內存方面的知識。但是疑惑的就是。我在讀取的過程中並沒有用緩衝區,所以根本不需要flush直接強制輸出數據,就是直接的讀出寫入。但的的確確就是出現問題了。


然後我哥給的建議是使用UTF8進行讀取,但是還是那個問題,並沒有改善。


就是很自然有很變態的從第182個文件開始,就是寫不進去數據了。
然後,因爲我使用的是LineNumberReader,是BufferedReader的子類,特點是可以輸出行號,我就乾脆將讀入的每一行的行號讀取了出來,但是是連續的2000個數字,說明每一行都已經讀出來了,這就更奇怪了。
然後我乾脆打印出來了第1820行的第一個char,發現是的確,真的可以讀出來的。
說明讀取文件是沒有問題的,那只能在寫文件的地方找問題了。
但是在尋找之後,也是沒有問題的。
在經過找各種資料之後,發現並不是函數利用的有問題。
然後又看程序的整體,和網上各種例子進行對比,發現,沒有人會將循環套在while循環的外面。都是最外面先是一個while循環,然後裏面纔會進行各種操作的。然後我就寫了一個新函數進行操作。發現,在循環180次之後,最後的20次起碼不是空的了。
public static void newRead() {
FileInputStream fis;
try {
fis = new FileInputStream("D:\\forcast\\data_new\\CIKM2017_testB\\data_new\\CIKM2017_testB\\testBDeal.txt");
InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
LineNumberReader fr = new LineNumberReader(isr);
String line = null;
int line_index = 0;
int unit_length = 10,max_index = 0;
FileOutputStream fos = null;OutputStreamWriter osw = null;
while((line = fr.readLine())!=null) {
if(line_index==0) {
fos = new FileOutputStream("D:\\forcast\\data_new\\CIKM2017_testB\\data_new\\CIKM2017_testB\\testBsegment\\testBData"+max_index+".txt");
osw = new OutputStreamWriter(fos, "UTF-8");
}
line_index = line_index+1;
if(!line.isEmpty())
osw.write(line + "\r\n");//寫入處理好的數據
else
System.out.println(fr.getLineNumber()+":is empty\n");
if(line_index==unit_length) {
max_index = max_index+1;
line_index = 0;
osw.flush();
osw.close();
}
}
fr.close();


} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}




說明新的程序是正確的。


然後再經歷了之後的操作,然後,發現,竟然和師兄的答案一樣呢,一樣呢


爲啥沒有激動的感覺了。


總結:
遇到項目的時候不要着急,追求快速出結果
不要在不瞭解函數,對象含義的時候直接上手使用
需要先構建程序執行的框架
需要將程序寫的儘量簡潔,邏輯儘量清晰。能看出來,邏輯性不夠強。需要在這方面加強訓練。


(二)選取最大值
在這裏只犯過一個錯誤,但是這一個錯誤就已經很要命了。是這樣的,在全部生成之後,我大概翻閱了一下生成的文件,然後發現了一個奇怪的現象,爲啥15個時刻的文件大小都是一樣的,爲啥,爲啥。然後打開進去看,只能呵呵了,內容也一樣。
先上源程序:


clear ; close all; clc
%==========================================================================
%%Input
% input = load('train_deal.txt');
% Data = input(1:10000,:);
sum = 10;
time = 15;
layer = 4;
row = 101;
colume = 101;
% input = load('needB.txt');
% Need = input(:,1);
needIndex = 1931;
for file_num = 0:199
    textName = ['D:\forcast\data_new\CIKM2017_testA\testDataSeg\testAData' num2str(file_num) '.txt'];
    input = load(textName);
    Data = input(1:sum,:);
    for s = 1:sum
        fprintf('start loop.%d          %d\n',file_num,s);
        
        for t = 1:time            
            fileIndex = (file_num)*sum*time + (s - 1) * time + t;
            textName = ['D:\forcast\data_new\CIKM2017_testA\testAResult\testAResult' num2str(fileIndex) '.txt'];
%             if Need(needIndex,1) == fileIndex
%                 needIndex = needIndex + 1;
                fprintf('%d\n',fileIndex);
                result = zeros(row, colume);
                        index = 1;

                for l = 1:layer
                    for c = 1:colume   %按列檢索
                        for r = 1:row
                            result(r,c) = max(result(r, c), Data(s,index));
                            index = index + 1;
                        end
                    end
                end
                dlmwrite(textName, result, '\t');
%             else
%                 fprintf('exist.%d\n',fileIndex);
%             end
        end
    end
%     fprintf('Program paused. Press enter to continue.\n');
%     pause
end

心酸吶,選個最大值需要這麼多行代碼。然後發現錯誤了嗎。錯誤就在index的位置上啊。因爲index的位置錯了,所以整個代碼的意思就變成了以下行爲循環15次:對每一行前4個矩陣對應位置取最大值。我說怎麼都一樣。都用的最一開始的4個矩陣,當然就都一樣啦。

然後,改吧。

clear ; close all; clc
%==========================================================================
%%Input
% input = load('train_deal.txt');
% Data = input(1:10000,:);
sum = 10;
time = 15;
layer = 4;
row = 101;
colume = 101;
% input = load('needB.txt');
% Need = input(:,1);
needIndex = 1931;
for file_num = 0:199
    textName = ['D:\forcast\data_new\CIKM2017_testA\testDataSeg\testAData' num2str(file_num) '.txt'];
    input = load(textName);
    Data = input(1:sum,:);
    for s = 1:sum
        fprintf('start loop.%d          %d\n',file_num,s);
        index = 1;
        for t = 1:time            
            fileIndex = (file_num)*sum*time + (s - 1) * time + t;
            textName = ['D:\forcast\data_new\CIKM2017_testA\testAResult\testAResult' num2str(fileIndex) '.txt'];
%             if Need(needIndex,1) == fileIndex
%                 needIndex = needIndex + 1;
                fprintf('%d\n',fileIndex);
                result = zeros(row, colume);
                for l = 1:layer
                    for c = 1:colume   %按列檢索
                        for r = 1:row
                            result(r,c) = max(result(r, c), Data(s,index));
                            index = index + 1;
                        end
                    end
                end
                dlmwrite(textName, result, '\t');
%             else
%                 fprintf('exist.%d\n',fileIndex);
%             end
        end
    end
%     fprintf('Program paused. Press enter to continue.\n');
%     pause
end


就這樣,就對了,就這樣。到現在位置,都做對了。

再回想之前的切割文件還是有關節沒有打通。還是說,只要讀取文件的動作不是持續發生的,就是會出錯,也的確,回想一下之前我所寫過的讀文件的操作,的確是最外面一個while,之後有什麼操作都是裏面接着進行的。

只能先這樣了。雖然沒有吧問題全部想明白,但好歹全部解決了。













發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章