项目笔记(二)

来源:互联网 发布:2016国内旅游数据 编辑:程序博客网 时间:2024/06/05 07:14

之前是十分基础的各项数据处理,但就是基础的数据处理,还是在昨天师兄的帮助下,最后完工的。

出现了各种错误,各种完全想不到的错误。

根据项目真正实施的步骤展开来总结自己的项目,遇到的各种问题,以及当时的解决方案,对解决方案的分析和现在仍然有的困惑。
目的就是对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');%     pauseend


就这样,就对了,就这样。到现在位置,都做对了。

再回想之前的切割文件还是有关节没有打通。还是说,只要读取文件的动作不是持续发生的,就是会出错,也的确,回想一下之前我所写过的读文件的操作,的确是最外面一个while,之后有什么操作都是里面接着进行的。

只能先这样了。虽然没有吧问题全部想明白,但好歹全部解决了。