2016-10-23 6 views
2

私は日付のベクトルを 'dd-MM-YYYY'の形で持っています。それらの日付のそれぞれから、 'dd-MM-YYYY hh:mm:ss。'の形式で一連の日付時刻を生成したいと思います。これらの日付時刻は、ある開始時刻から開始され、n分だけ増分され、与えられた終了時刻に終了する。Matlab日付のベクトルを使用して、日付と時刻のシーケンスのベクトル化された実装

私はこれを二重ループで行うことができますが、十分に小さい時間増分で、与えられた入力日付の十分大きなベクトルで長い時間がかかります。処理時間を短縮するためにこれを何らかの方法でベクトル化できますか?

このサンプルスクリプトは、1分増分を使用して60日間しか使用できませんが、最終データには数千ものデータが含まれます。ループを有する

マイスクリプト:

%% ===== StackOverFlow Question ================ 
tic 
% Create an Arbritrary Vector of Dates 
sDates = (datetime([1991,11,01]) + caldays(0:60))'; 

% Remove Weekends from Dates 
sDates = sDates(weekday(sDates)>1 &weekday(sDates)<7); 

% Outer Loop to go through LIST OF DATES 
for theDate =1:size(sDates,1) 
    [y,m,d] = ymd(sDates(theDate)); % Get y,m,d of each date in list 

    % START and END Time to create date time sequence each     
    % t1 and t2 are synced to each day in the date vector 
    t1 = datetime(y,m,d,08,30,00); t2 = datetime(y,m,d,15,00,00); 

    % Inner Loop to go through each increment of time 
    NDX=0; 
    for theMin =t1 : minutes(1) : t2 %Scroll through Minutes 
     NDX=NDX+1; 

     % Store each minute/increment into another vector 
     % Final Desired Vector 
     x_tDate(NDX,1)=theMin; 
    end 
end 
toc 

------------------------------- EDIT ---より迅速な処理--------------- 私はそれをもっと速くする方法を考え出しました。 OUTER-LOOPはまだそこにありますが、私はINNER-LOOPをベクトル化する方法を考え出しました。したがって、その内部は、大きなループの反復ごとに約390回、大きなループの反復ごとに1回まで実行されることから削減されます。しかし、さらに簡素化できるかどうか疑問に思っていますか?

%% ===== StackOverFlow Question ================ 
tic 
% Create an Arbritrary Vector of Dates 

sDates = (datetime([1991,11,01]) + caldays(0:60))'; 

% Remove Weekends from Dates 
sDates = sDates(weekday(sDates)>1 &weekday(sDates)<7); 

% Outer Loop to go through LIST OF DATES 

newDates=datetime([],[],[],[],[],[]); %Initialize dateTime Place holder 

for theDate =1:size(sDates,1) 
    [y,m,d] = ymd(sDates(theDate)); % Get y,m,d of each date in list 

    % START and END Time to create date time sequence each day listed in Date  
    % t1 and t2 are synced to each day in the date vector 
    t1 = datetime(y,m,d,08,30,00); t2 = datetime(y,m,d,15,00,00); 

    temp=t1 :minutes(1) :t2; 
    newDates=[newDates temp]; 

end 
newDates = newDates'; 

toc 

答えて

1

日付/時刻に行うための操作が多数ある場合、私はあなたパフォーマンスをしたい、私はdatenumの使用を検討することを勧めます。この形式では、各時刻/日付は単なる数値に過ぎず、複雑なオブジェクト(例えば、datetime)を扱わなければならない場合よりも高速な計算が可能です。

計算量が多い場合は、いつでもdatetimeオブジェクトに変換できます。

ここでは、あなたの例と同じ日付ベクトルを生成する(より速く)方法があります。理解すべき主な機能は、datenumbsxfunです。

私はそれぞれの行を作成したので少し分かりやすく、一時的な変数を使用して分かりやすく表示しています。

%% Create the vector of days 
% Initial parameters 
StartDate = datenum(1991,11,01) ;   % first day 
nDaysFromStart = 60 ;      % number of days 
EndDate  = StartDate + nDaysFromStart ; % last day to consider 
dowStart = weekday(StartDate) ;    % "day of week" number 
dowEnd = weekday(EndDate) ; 
% now create an array containing an integer multiple of 7 (days) 
daysarray = (0-dowStart+1):(nDaysFromStart+7-dowEnd) ; 
% reshape it [7xN] to trim the days of the week we don't want 
daysarray = reshape(daysarray,7,[]) ; 
dowToRemove = [1 7] ;    % remove Sunday (1) and Saturday (7) 
daysarray(dowToRemove,:) = [] ; 
% Now remove the extra days created at start and end. Note that this 
% operation will also reshape the 2d array into a 1d vector. 
daysarray(daysarray<0 | daysarray>nDaysFromStart) = [] ; 
% Now add the real start date to all elements of the vector 
daysarray = daysarray + StartDate ; 

%% Create the vector of minutes for any given day 
step = 1/24/60 ;    % portion of a day that represent a minute 
start = datenum(0,0,0,8,30,0) ; % start time for each day 
stop = datenum(0,0,0,15,00,00) ;% end time for each day 
dailyvec = (start:step:stop).' ; 

%% Use bsxfun to create the complete arrays 
alldates = bsxfun(@plus,daysarray,dailyvec) ; 

%% Eventually, convert to "datetime" objects if you prefer to work with them 
allNewDates = datetime(alldates(:) , 'ConvertFrom','datenum') ; 

、これまでにさまざまな方法を迅速にベンチマーク:

benchmark


とのコードしたい場合はわずか数行に低減することができるすべてのベンチマーク(tic/tocの代わりにtimeitを使用)、私のコードもちょっと圧縮してください:

function t = bench_datevec_generation() 

%  nDaysToGenerate = [10:10:100 200:100:900] ; 
    nDaysToGenerate = [10:10:60] ; 

    t = zeros(numel(nDaysToGenerate),3) ; 
    for k=1:numel(nDaysToGenerate) 
     nDays = nDaysToGenerate(k) ; 
     f1 = @() genDateTime_loop(nDays); 
     f2 = @() genDateTime_vectorized(nDays); 
     f3 = @() genDatenum(nDays); 

     t(k,1) = timeit(f1) ; 
     t(k,2) = timeit(f2) ; 
     t(k,3) = timeit(f3) ; 
     fprintf('Measuring time for nDays=%d\n',nDays) 
    end 

end 

function newDates = genDateTime_loop(nDays) 
    sDates = (datetime([1991,11,01]) + caldays(0:nDays)).'; 
    % Remove Weekends from Dates 
    sDates = sDates(weekday(sDates)>1 &weekday(sDates)<7); 
    % Outer Loop to go through LIST OF DATES 
    newDates=datetime([],[],[],[],[],[]); %Initialize dateTime Place holder 

    for theDate =1:size(sDates,1) 
     [y,m,d] = ymd(sDates(theDate)); % Get y,m,d of each date in list 

     % START and END Time to create date time sequence each day listed in Date  
     % t1 and t2 are synced to each day in the date vector 
     t1 = datetime(y,m,d,08,30,00); t2 = datetime(y,m,d,15,00,00); 

     temp=t1 :minutes(1) :t2; 
     newDates=[newDates temp]; 
    end 
    newDates = newDates.' ; 
end 

function newDates = genDateTime_vectorized(nDays) 
    sDates = (datetime([1991,11,01]) + caldays(0:nDays))'; 

    % Remove Weekends from Dates 
    sDates = sDates(weekday(sDates)>1 &weekday(sDates)<7); 
    [Y,M,D] = ymd(sDates); 

    % Get y,m,d of first (or any) date in list to build the the h,m,s time range 
    [y,m,d] = ymd(sDates(1)); 
    t1 = datetime(y,m,d,08,30,00); t2 = datetime(y,m,d,15,00,00); 
    temp = (t1:minutes(1):t2)'; 
    [h,m,s]=hms(temp); 

    newDates = datetime([repelem([Y M D], length(temp), 1) repmat([h m s], [length(sDates) 1])]); 
    % repmat() to REPLICATE the TIME MATRIX, length(sDates) times along the rows 
    % repelem() to REPEAT EACH ELEMENT OF the DATE MATRIX, length(temp) times along the rows 
end 

function newDates = genDatenum(nDays) 
    % Initial parameters 
    StartDate = datenum(1991,11,01) ;   % first day 
    % now create an array containing an integer multiple of 7 (days) 
    daysarray = reshape((0-weekday(StartDate)+1):(nDays+7-weekday(StartDate+nDays)),7,[]) ; 
    dowToRemove = [1 7] ; 
    daysarray(dowToRemove,:) = [] ; 
    daysarray(daysarray<0 | daysarray>nDays) = [] ; 
    daysarray = daysarray + StartDate ; 

    % Create the vector of minutes for any given day 
    step = 1/24/60 ;    % portion of a day that represent a minute 
    start = datenum(0,0,0,8,30,0) ; % start time for each day 
    stop = datenum(0,0,0,15,00,00) ;% end time for each day 
    dailyvec = (start:step:stop).' ; 

    % Use bsxfun to create the complete arrays 
    alldates = bsxfun(@plus,daysarray,dailyvec) ; 

    % Eventually, convert to "datetime" objects if you prefer to work with them 
    newDates = datetime(alldates(:) , 'ConvertFrom','datenum') ; 
end 
1

として、多くの場合、MATLABに、コードをスピードアップする簡単な方法は、(あなたが内部ループで行ったように)それをベクトル化し、すでに最適化された機能に依存することです。ここでは、データ文字列を扱っていますが、実際には数字で作業し、最後にのみデータ文字列に変換するほうが簡単です。

ここには、約8倍から10倍のスピードアップをもたらす単純なコードがあります。私はMatlabのコード最適化の専門家ではないでしょう。おそらくさらに進化するかもしれません。

tic 
% Create an Arbritrary Vector of Dates 

sDates = (datetime([1991,11,01]) + caldays(0:60))'; 

% Remove Weekends from Dates 
sDates = sDates(weekday(sDates)>1 &weekday(sDates)<7); 
[Y,M,D] = ymd(sDates); 

% Get y,m,d of first (or any) date in list to build the the h,m,s time range 
[y,m,d] = ymd(sDates(1)); 
t1 = datetime(y,m,d,08,30,00); t2 = datetime(y,m,d,15,00,00); 
temp = (t1:minutes(1):t2)'; 
[h,m,s]=hms(temp); 

newDates = datetime([repelem([Y M D], length(temp), 1) repmat([h m s], [length(sDates) 1])]); 
% repmat() to REPLICATE the TIME MATRIX, length(sDates) times along the rows 
% repelem() to REPEAT EACH ELEMENT OF the DATE MATRIX, length(temp) times along the rows 

toc 
関連する問題