matlab將多個文件夾下的,多個txt中的行數據合併,速度慢,怎麼優化代碼?(並行計算已測試也很慢)

舉個例子,現在有三個文件夾,1,2,3。每個文件夾下有30個子文件夾。每個子文件夾下有308個txt文檔。每個txt中都是第一行表頭,第二行數據的這種形式。如何快速將每個「子文件夾」下的txt文檔中,數據合併為一個txt,再以文件夾名字來命名?

現有的方法是:

Experiment= "F:201603 Exp";%實驗組是哪個
origin="Experiment result";%xls數據所在父文件夾,下面有3個文件夾
COM="IA";%txt數據所在子文件夾,為本次要匯總的數據
menu=dir([Experiment origin ""]);%3個文件夾下,每個文件夾中有30個子文件夾
for i=1:length(menu)
Team=menu(i,1).name;
ProcessList=dir([Experiment origin "" Team "" COM ""]);%載入每個子文件夾中的文件列表
for j=1:length(ProcessList)
xls=dir([Experiment origin "" Team "" COM "" ProcessList(j,1).name "*.txt"]);%載入ProcessList(j,1)中的txt文件列表
title=ProcessList(j,1).name;
S=[];%設置S為空矩陣,存儲每一組txt的所有數據在其中
for k=1:length(xls)
S1=[];%設置臨時矩陣S1
xlsi=importdata([Experiment origin "" Team "" COM "" ProcessList(j,1).name "" xls(k,1).name]);%載入第i組txt
S1=xlsi.data;
S=[S;S1];%將txt貼到儲存矩陣S的屁股上
end
xlswrite([Experiment origin "" Team "" COM "" title ".xls"],header,"Sheet1","A1");%寫入xls文件,添加表頭在第一行
xlswrite([Experiment origin "" Team "" COM "" title ".xls"],S,"Sheet1","A2");%寫入xls文件,添加數據在第二行
end
end

這麼嵌套for循環,用matlab 2016,很慢。數據存儲在SSD上,本不應該讀寫這麼慢....開啟了parpool,計算效率並沒有提升。

要匯總的txt的數據格式是:

profile report 如下


你可以 profile 一下看看具體慢在哪裡再考慮怎麼改。

沒有你用的文件樣本也沒有 profile 報告僅從你代碼中能看出的東西有限,大概有幾個原因:

一個是用了 xls 保存數據,MATLAB 是調用 Excel 來讀寫 xls 文件的,會比較慢,能不用最好不用,你要合併的數據如果本來是在 txt 中的那麼合併後也完全可以放在 txt (以 csv 格式)。如果一定要用 xls 也最好減少讀寫次數(即每次寫入或讀取儘可能多的數據,而不是多次讀寫需要的數據);

一個是數據的讀取方法你用的 importdata,importdata 兼容性比較好,可以在幾乎不作設置的情況下讀取不同格式的數據,但是代價是性能不太好,而且以前版本還有 bug (而且你是 2016a 還是 2016b?),如果數據格式確定可以用更有針對性的方法讀取;例如比較標準的表格數據的話可以用 readtable;

另一個是合併數據的方法不太好,會動態改變數組的大小,可以考慮讀一個文件就寫一個文件到輸出文件,但是你要用 xls 文件的話顯然會增加讀寫次數,所以如果一定要用 xls 的話不推薦這樣做。如果一定要讀完再輸出的話,應該預分配空間,並且用 cell 存儲。

其實你也可以不做合併直接用 Datastore 和 Tall Arrays 來處理和使用數據


自己看圖,整理大宗量數據當然不要用matlab,用matlab最不擅長的部分搞事情就不要要求速度了,實在不想或者不會js或者Julia的話,同為腳本語言的python也比matlab快個數量級還拐彎,我猜是因為matlab支持的類型複雜同時parse之後可以生成cell,所以很耗時

沒仔細看代碼 大致看了一下,這種根本不涉及保存成.mat格式的情況用感覺VBA也會比matlab快很多,從txt到excel。

不要因為會matlab而啥事都用matlab


這段代碼跑的慢,主要原因在於,你每次循環過程中使用了兩次xlswrite。

那麼來算一下,3個文件夾,30個子文件夾,308個txt,總共27720次循環,也就是需要調用55440次xlswrite。我不確定具體調用的次數是不是正確,但是你不得不承認,你過多調用xlswrite了,會造成運行速度很慢。

解決辦法就是,你每次讀取處理完txt數據之後,都以cell的形式放那,最終for循環都結束,整合成一個cell,就調用一次xlswrite保存到表格中。速度一定不會慢。

以上


不用matlab


別用MATLAB咯


直接讀取文件然後不轉換直接往新文件里寫。

f1=dir("*.txt");

fidout=fopen("新文件名.dat","w");%新建的dat文件寫入

for i=1:length(f1)%循環文件夾下的文件

fid=fopen(f1(i).name);%打開文件

temp=fets(fid);%躲去第一行

f=fread(fid);%讀取文件,讀取了除了第一行之外所有的內容

fclose(fid);

fprintf(fidout,"%s",f);%往目標文件里寫

end%文件夾循環結束

fclose(fidout);

還有一個能獲得文件夾下所有子文件夾的小程序,可以獲得指定路徑下所有的子文件夾路徑,配合 a=uigetdir 會很好用的。

a=uigetdir;b = getfilename( a );

for i=1:length(b)

.......

end

function b = getfilename( a )

%得到a下面所有的子文件夾

f=dir(a);

d={};

temp={};

for i=1:length(f)

if f(i).name(1)=="." %系統自帶的 "." 和 ".." 文件夾會帶來錯誤,應該還要去掉很多種隱藏文件夾,可惜不會。

else

if f(i).isdir

temp1=fullfile(a,f(i).name); %文件夾路徑的拼接

d=[d;temp1]; %所有 a 路徑中 是文件夾的 路徑都存到 d 裡面 如果 d是空的就說明a 路徑下面沒有文件夾

end

end

end

if isempty(d)

b=a;

else

b={};

for i=1:length(d)

b=[b;getfilename(d{i})]; %遞歸,這樣寫很慢,不如 使用MATLAB查找和列出指定目錄及子目錄下的所有文件(轉)_快樂的小豬啦_新浪博客 做的好

end

end

end


shell不好嘛……


以我的理解,你這個需求只需要讀寫字元串就可以了。那麼你可以試試以字元串的形式將數據讀進來,再以字元串的形式寫到目標文件中。

所以你這裡importdata函數和xlswrite函數就是沒有必要的開銷。而且你在循環中使用矩陣的迭代增長S=[S;S1]這應該也是導致速度慢的原因之一。

所以我的建議是只在字元串層面操作。可以使用fgetl函數,這個函數可以每次從文件中讀取一行字元串。對於你的308個txt文件,讀兩次,把第二次的結果拿到,也就是你的數據,然後再用fprintf函數或者fwirte函數寫到那個集中的txt文件里。


一般讀取子文件夾的文件用dirr函數,mathwork官網有源碼。

然後你把所有的txt存到一個矩陣中即可。

然後一次xlswrite即可


同意樓上 @Falccm的回答,強烈建議你使用tall和datastore試試,可以參看這篇文章

知乎專欄


你確認用了並行?沒見到parfor或者spmd啊


我一般用notepad粘貼複製.

notepad處理大文本速度很快


推薦閱讀:

大數據培訓出來就業情況如何?
有沒有data science博士專業,哪個學校比較好,不限國別?
大數據下的城市規劃應用前景怎樣?
2017年,如何理性看待貴陽大數據以及IT行業的發展,生活在貴陽這座城市是怎樣一種體驗?
大公司裡面有人專門負責標註數據嗎?

TAG:MATLAB | 優化 | 並行計算 | 大數據 | 嵌套循環 |