如何在Mathematica中更快地选择子列表?

时间:2012-01-20 23:29:03

标签: wolfram-mathematica

我的问题听起来更为笼统,但我有一个具体的例子。我有一份表格中的数据清单:

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 个答案:

答案 0 :(得分:2)

如果您的数据是定期的,您应该能够知道一天,一周等多少元素,并使用Part

plotDataAll2[[knownIndex;;-1]]

或更具体地说,如果数据是每小时:

plotDataAll2[[-25;;-1]]

会在最后24小时内给你。如果间距不规则,请使用SelectPick。不幸的是,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]]

答案 1 :(得分:2)

您要避免的是检查数据表中的所有值。由于数据是连续的,您可以从后面开始检查,并在找到正确的索引后停止。

示意性地:

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}

替换> 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首先找到起点,然后恰当地设置iMaxmaxDate

对于大型数据集,这可能是循环结构优于MMA内置函数的少数几个实例之一。然而,这可能是我自己的无知,如果有人在这里知道MMA内置函数,那么这种“匹配发现时停止”的比较优于While

编辑:时间比较

我和迈克和我的解决方案玩了一下,并将其与OP的方法进行了比较。这是我用于每个解决方案的玩具代码

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.0GHz)

Timing differences of solutions

正如你所看到的,Mike的解决方案与enedene的解决方案相比具有明显的优势,但正如我最初推测的那样,使用内置函数(如Pick)的缺点是它们仍然会对所有元素进行比较检查。列表在这种情况下非常多余。由于没有进行不必要的检查,我的解决方案有恒定的时间。