select, group and manipulate elements in list based on date ranges

1

Question from a beginner. I have data containing dates and values of the format:

    data = {{{2015, 1, 1}, 2}, {{2015, 1, 2}, 3}, {{2015, 2, 1}, 4}, {{2015, 2, 2}, 5}, {{2016, 1, 1}, 6}, {{2016, 1, 2}, 7}}

Aim is to multiply the values of each day in a month, e.g. for January 2015, the result should be 2*3=6, for February 2015 4*5=20 and so on. Ideally, the output would be a list of the format {{January 2015, 6}, {February 2015, 20},etc}, but just a list of the results of the multiplications would be fine.

To group the data by month, I use:

selectElements[list_, start_, end_] := Module[{s = AbsoluteTime@start, 
    e = AbsoluteTime@end},  Select[list, Composition[s <= # <= e &, AbsoluteTime, First]]]

I then create a table multiplying the values of the data grouped by month:

test1 = Table[Times @@ selectElements[data, {y, m, 1}, {y, m, 31}], {y, 2015, 2016}, {m, 1, 12}]

However, this multiplies not only the values, but also the dates themselves giving me:

    {{{{4060225, 1, 2}, 6}, {{4060225, 4, 2}, 20}, 1, 1, 1, 1, 1, 1, 1, 1,1, 1}, {{{4064256, 1, 1}, 42}, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}}

I'm sure there is an easy way to get just the dates and the values I'm interested in (i.e. 6,20,42, ideally with month/year), but so far I couldn't find it. I'd be very grateful for any pointers.

flux

Posted 2017-10-17T11:53:42.640

Reputation: 33

Answers

2

I think this is a simpler variant of @Alan's answer:

GroupBy[
    data,
    Most@*First -> Last,
    Apply[Times]
]

<|{2015, 1} -> 6, {2015, 2} -> 20, {2016, 1} -> 42|>

Carl Woll

Posted 2017-10-17T11:53:42.640

Reputation: 112 778

Thank you very much! – flux – 2017-10-23T15:30:57.710

2

GroupBy[data, Part[First[#], ;; 2] &, Apply[Times, Last /@ #] &]

Alan

Posted 2017-10-17T11:53:42.640

Reputation: 10 893

Thanks so much!

I knew I was overcomplicating things and that there was a much easier and quicker solution.... – flux – 2017-10-17T16:11:31.340

0

TimeSeriesAggregate can also be used, e.g.:

#1[[1, {1, 2}]] -> #2 & @@@TimeSeriesAggregate[data, "Month", Times @@ # &]

yielding:

{{2015, 1} -> 6, {2015, 2} -> 20, {2016, 1} -> 42}

ubpdqn

Posted 2017-10-17T11:53:42.640

Reputation: 53 491

Hi, thanks for your suggestion re using TimeSeriesAggregate. However, when I'm running the exact code you suggest, I get:

`Part specification 3630398400[[1,{1,2}]] is longer than depth of object.

{3630398400[[1, {1, 2}]] -> 6, 3632947200[[1, {1, 2}]] -> 20, 

3661934400[[1, {1, 2}]] -> 42}`

It's probably a matter of me not really understanding something quite basic in your answer... apologies in advance. – flux – 2017-10-23T16:29:18.713