#matlab #date #performance
#matlab #Дата #Производительность
Вопрос:
Кто-нибудь знает более быстрый способ преобразовать строку даты (2010-12-12 12: 21: 12.123) в число?
Комментарии:
1. Под числом вы подразумеваете временную метку, такую как часто используемые «секунды с начала эпохи»?
Ответ №1:
Часто в качестве инструкции используется профилирование встроенных функций Matlab и извлечение только интересующей внутренней функциональности.
В вашем конкретном случае,
dtstr2dtnummx({'2010-12-12 12:21:12.123'},'yyyy-MM-dd HH:mm:ss')
в 3 раза быстрее (занимает 30% времени), чем:
datenum({'2010-12-12 12:21:12.123'},'yyyy-mm-dd HH:MM:SS')
где dtstr2dtnummx — это внутренняя функция (C:Program Files Matlab R2011a toolbox matlab timefun private dtstr2dtnummx.mexw32 на моем компьютере с Windows).
Чтобы получить доступ к этой внутренней функции, просто добавьте ее папку в путь Matlab с помощью addpath
функции или скопируйте файл dtstr2dtnummx.mexw32 в другую папку, которая уже находится в вашем пути Matlab.
Обратите внимание, что формат строки отличается между dtstr2dtnummx и datenum, поэтому будьте осторожны!
Для тех, кому интересно, в папке выше содержатся другие интересные функции преобразования дат, так что изучайте и наслаждайтесь!
Примечание 5/5/2011: теперь я опубликовал статью, которая расширяет этот ответ на http://undocumentedmatlab.com/blog/datenum-performance /
Комментарии:
1. К сожалению, вы не можете добавить частные каталоги Matlab в path, поэтому для пользователей, у которых нет возможности скопировать файл в свой текущий каталог, это решение не будет работать.
2. Для пояснения, пользователи могут не иметь возможности добавить файл, содержащий
dtstr2dtnummx
, в свой текущий каталог из-за проблем с авторскими правами.3. @Ricardo — Я не думаю, что здесь есть какая-либо проблема с авторским правом. Я считаю, что у вас есть право использовать любую внутреннюю функцию при покупке лицензии Matlab.
4. Когда я посещал учебную сессию несколько месяцев назад, сотрудники Mathworks убеждали меня не делать этого при создании автономных приложений Matlab. Отсюда мои колебания.
5. Я бы отнесся к их призывам с такой же серьезностью, как к призывам Apple не рутировать iPhone или к призывам Ford не настраивать свои автомобили вручную. У вас есть выбор, и вам решать, использовать его или нет.
Ответ №2:
Часто вам нужно использовать системный подход. У меня была очень похожая проблема, когда я извлекал тысячи дат из базы данных. Оказывается, что многие современные базы данных (я пробовал Postgres, Sql server и Oracle) могут выполнять преобразование из своих представлений даты в представления даты Matlab на несколько порядков быстрее, чем текст в datenum на стороне matlab. Если эти данные поступают из базы данных, подумайте о преобразовании на стороне базы данных!!
Ответ №3:
Предположительно, если вас волнует время, затрачиваемое на преобразование дат, вы конвертируете многие из них. Даже если не учитывать оптимизацию JIT в последних версиях matlab, вы получите гораздо более быстрые результаты при вызове
datenum(cellarrayofdates, 'yyyy-mm-dd HH:MM:SS');
чем
for i=1:length(cellarrayofdates); datenum(cellarrayofdates{i}, 'yyyy-mm-dd HH:MM:SS'); end
Если вы еще этого не делаете, начните с этого, поскольку это позволяет matlab сократить накладные расходы на определение вашего формата даты для каждого вызова функции.
Ответ №4:
Я понимаю, что этот вопрос устарел. Однако мне удалось создать функцию, которая примерно в 30-40 раз быстрее datenum. Примечание: Существуют незначительные недостатки, зависящие от использования. Если кто-нибудь хочет, чтобы я это исправил, просто дайте мне знать.
Выполняется с 1 792 379 строками:
- дата — 11,463186 секунды
- datenumjck — 0,300503 секунды
Просто прочитайте ваш файл с помощью textscan и интерпретируйте дату и время как двойные и введите вместе с форматом даты в мою функцию.
Пример:
Предположим, что данные формируются следующим образом:
Data,2016-03-03,16:15:50;686,0.000000,-0.009500
Data,2016-03-03,16:15:50;696,0.000000,0.006500
Data,2016-03-03,16:15:50;706,0.000000,0.004500
Data,2016-03-03,16:15:50;716,0.000000,-0.006000
Считывание данных:
fileID = fopen('myFile.csv','r');
formatSpec = '%*s %f %f %f %f %f %f %f %*[^n]'; % Ignore first string, save
% date and time as doubles
% ignore all other data
data = textscan(fileID,formatSpec,'delimiter',',t/:;-.\ ');
fclose(fileID);
Укажите формат даты и используйте datenumjck():
dateFormat = 'yyyy-mm-dd,HH:MM:SS;FFF';
numDate = datenumjck(data,dateFormat);
Код:
function num = datenumjck(data, dateFormat)
n = size(data{1});
dateFormat = textscan(dateFormat,'%s','delimiter',',/:;-.\');
dateFormat = dateFormat{1};
k = find(strcmp('yyyy', dateFormat),1);
if ~isempty(k)
y = data{k};
elseif ~isempty(find(strcmp('yy', dateFormat),1))
y = data{find(strcmp('yy', dateFormat),1)};
else
y = zeros(n);
end
k = find(strcmp('mm', dateFormat),1);
if ~isempty(k)
m = data{k};
elseif ~isempty(find(strcmp('mmm', dateFormat),1))
month = cellfun(@strfind,...
repmat({'janfebmaraprmayjunjulaugsepoctnovdec'},...
size(data),lower(data(find(strcmp('mmm', dateFormat),1)))));
m = (month 2)/3;
else
m = zeros(n);
end
k = find(strcmp('dd', dateFormat),1);
if ~isempty(k)
d = data{k};
else
d = zeros(n);
end
k = find(strcmp('HH', dateFormat),1);
if ~isempty(k)
H = data{k};
else
H = zeros(n);
end
k = find(strcmp('MM', dateFormat),1);
if ~isempty(k)
M = data{k};
else
M = zeros(n);
end
k = find(strcmp('SS', dateFormat),1);
if ~isempty(k)
S = data{k};
else
S = zeros(n);
end
k = find(strcmp('FFF', dateFormat),1);
if ~isempty(k)
F = data{k};
else
F = zeros(n);
end
ms = [0,31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
num = zeros(n);
for k = 1:n
num(k) = y(k)*365 ms(m(k)) d(k) floor(y(k)/4)...
- floor(y(k)/100) floor(y(k)/400) (mod(y(k),4)~=0)...
- (mod(y(k),100)~=0) (mod(y(k),400)~=0)...
(H(k)*3600 M(k)*60 S(k) F(k)/1000)/86400 1;
end