Как быстрее выбрать подсписки в Mathematica? - PullRequest
2 голосов
/ 21 января 2012

Мой вопрос звучит более обобщенно, но у меня есть конкретный пример.У меня есть список данных в форме:

plotDataAll={{DateList1, integerValue1}, {DateList2, integerValue2}...}

Даты отсортированы в хронологическом порядке, то есть plotDataAll[[2,1]] является более поздним временем, чем plotDataAll[[1,1]].

Я хочу создавать графики определенных периодов, 24 часа назад, 1 неделю назад и т. Д. Для этого мне нужна только часть данных.Вот как я получил то, что хотел:

mostRecentDate=Max[Map[AbsoluteTime, plotDataAll[[All,1]]]];
plotDataLast24h=Select[plotDataAll,AbsoluteTime[#[[1]]]>(mostRecentDate-86400.)&];
plotDataLastWeek=Select[plotDataAll,AbsoluteTime[#[[1]]]>(mostRecentDate-604800.)&];
plotDataLastMonth=Select[plotDataAll,AbsoluteTime[#[[1]]]>(mostRecentDate-2.592*^6)&];
plotDataLast6M=Select[plotDataAll,AbsoluteTime[#[[1]]]>(mostRecentDate-1.5552*^7)&];

Затем я использовал DateListPlot для построения графика данных.Это становится медленным, если вам нужно сделать это для многих наборов данных.
Что приходит мне в голову, если бы я мог найти индекс первого элемента в списке, который удовлетворяет условию даты, потому что он отсортирован в хронологическом порядке, остальные также должны удовлетворять условию.Итак, я бы сказал:

plotDataLast24h=plotDataAll[[beginningIndexThatSatisfiesLast24h;;Length[plotDataAll]]

Но как мне получить индекс первого элемента, который удовлетворяет условию?

Если у вас есть более быстрый способ сделать это, поделитесь своим ответом,Кроме того, если у вас есть простое, более быстрое, но неоптимальное решение, это тоже хорошо.

РЕДАКТИРОВАТЬ:
Данные времени не равны регулярным интервалам.

Ответы [ 2 ]

2 голосов
/ 21 января 2012

То, что вы хотите избежать, это проверка всех значений в таблице данных. Поскольку данные являются последовательными, вы можете просто начать проверку со спины и остановиться, когда найдете правильный индекс.

Схематично:

tab = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
i = j = Length@tab;
While[tab[[i]] > 5, --i]; 
tab[[i ;; j]]
-> {5, 6, 7, 8, 9}

sustitute > 5 для того, что вы хотите проверить. У меня не было времени проверить это прямо сейчас, но в вашем случае, например,

maxDate=AbsoluteTime@plotDataAll[[-1,1]]; (* no need to find Max if data is sequential*)

i24h = iWeek = iMonth = iMax = Length@plotDataAll;
While[AbsoluteTime@plotDataAll[[i24h,1]] > maxDate-86400.,--i24h];
While[AbsoluteTime@plotDataAll[[iWeek,1]] > maxDate-604800.,--iWeek];
While[AbsoluteTime@plotDataAll[[iMonth,1]] > maxDate-2.592*^6.,--iMonth];
While[AbsoluteTime@plotDataAll[[i6Month,1]] > maxDate-1.5552*^7.,--i6Month];

Тогда, например,

DateListPlot@plotDataAll[[i24h;;iMax]]

Если вы хотите начать где-нибудь в середине plotDataAll, просто используйте While, чтобы сначала найти начальную точку, и установите iMax и maxDate соответственно.

Для больших наборов данных это может быть один из немногих случаев, когда конструкция цикла лучше встроенных функций MMA. Это, однако, может быть моим собственным невежеством, и если кто-то здесь знает о встроенной функции MMA, которая делает такого рода сравнение «останов, когда найдено совпадение» лучше, чем While.

РЕДАКТИРОВАТЬ: Сравнение сроков

Я немного поиграл с Майком и моим решением и сравнил его с методом ОП. Вот код игрушки, который я использовал для каждого решения

tab = Range@1000000;

(* My solution *)
i = j = tab[[-1]];
While[tab[[i]] > j - 24, --i];
tab[[i ;; j]]

(* Mike's solution *)
tmp = tab[[-1]] - 24;
Pick[tab, Sign[tab[[All]] - tmp], 1]

(* Enedene's solution *)
j = tab[[-1]];
Select[tab, # > (j - 24) &]

Вот результаты (OS X, MMA 8.0.4, Core2Duo 2.0 ГГц)

Timing differences of solutions

Как вы можете видеть, решение Майка имеет определенное преимущество перед решением енедена, но, как я и предполагал изначально, недостатком использования встроенных функций, таких как Pick, является то, что они по-прежнему выполняют сравнительную проверку всех элементов в списке, которые в этом случае крайне лишний. Мое решение имеет постоянное время из-за того, что ненужные проверки не выполняются.

2 голосов
/ 21 января 2012

Если ваши данные с регулярными интервалами, вы должны знать, сколько элементов составляют день, неделю и т. Д., И использовать Part.

plotDataAll2[[knownIndex;;-1]]

или более конкретно, если данные были почасовыми.:

plotDataAll2[[-25;;-1]]

даст вам последние 24 часа.Если интервал нерегулярный, используйте Select или Pick.К сожалению, функции даты и времени в Mma ужасно медленные.Если вы собираетесь делать много вычислений даты и времени, лучше сделать преобразование в AbsoluteTime только один раз, а затем работать с этим.Вы также заметите, что ваши DateListPlot отображаются намного быстрее, если вы используете AbsoluteTime.

plotDataAll2=plotDataAll;
plotDataAll2[[All,1]]=AbsoluteTime/@plotDataAll2[[All,1]];
mostRecentDate=plotDataAll2[[-1,1]]

На моем компьютере Pick примерно в 3 раза быстрее, но могут быть другие улучшения, которые вы можете сделать, чтобыкод ниже:

selectInterval[data_, interval_] := (tmp = data[[-1, 1]] - interval; 
  Select[data, #[[1]] > tmp &])

pickInterval[data_, interval_] := (tmp = data[[-1, 1]] - interval; 
  Pick[data, Sign[data[[All, 1]] - tmp], 1])

Чтобы найти данные за последнюю неделю:

Timing[selectInterval[plotDataAll2, 604800]]
Timing[pickInterval[plotDataAll2, 604800]]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...