I have a dataset of events (tweets to be specific) that I am trying to bin / discretize. The following code seems to work fine so far (assuming 100 bins):
HOUR = timedelta(hours=1)
start = datetime.datetime(2009,01,01)
z = [dt + x*HOUR for x in xrange(1, 100)]
But then, I came across this fateful line at python docs 'This makes possible an idiom for clustering a data series into n-length groups using zip(*[iter(s)]*n)
'. The zip idiom does indeed work - but I can't understand how (what is the *
operator for instance?). How could I use to make my code prettier? I'm guessing this means I should make a generator / iterable for time that yields
the time in graduations of an HOUR?
I will try to explain zip(*[iter(s)]*n)
in terms of a simpler example:
imagine you have the list s = [1, 2, 3, 4, 5, 6]
iter(s)
gives you a listiterator
object that will yield the next number from s
each time you ask for an element.
[iter(s)] * n
gives you the list with iter(s)
in it n times e.g. [iter(s)] * 2 = [<listiterator object>, <listiterator object>]
- the key here is that these are 2 references to the same iterator object, not 2 distinct iterator objects.
zip
takes a number of sequences and returns a list of tuples where each tuple contains the ith element from each of the sequences. e.g. zip([1,2], [3,4], [5,6]) = [(1, 3, 5), (2, 4, 6)]
where (1, 3, 5)
are the first elements from the parameters passed to zip
and (2, 4, 6)
are the second elements from the parameters passed to zip
.
The *
in front of *[iter(s)]*n
converts the [iter(s)]*n
from being a list into being multiple parameters being passed to zip
. so if n
is 2 we get zip(<listiterator object>, <listiterator object>)
zip
will request the next element from each of its parameters but because these are both references to the same iterator this will result in (1, 2)
, it does the same again resulting in (3, 4)
and again resulting in (5, 6)
and then there are no more elements so it stops. Hence the result [(1, 2), (3, 4), (5, 6)]
. This is the clustering a data series into n-length groups as mentioned.
The expression from the docs looks like this:
zip(*[iter(s)]*n)
This is equivalent to:
it = iter(s)
zip(*[it, it, ..., it]) # n times
The [...]*n
repeats the list n
times, and this results in a list that contains n
references to the same iterator.
This is again equal to:
it = iter(s)
zip(it, it, ..., it) # turning a list into positional parameters
The *
before the list turns the list elements into positional parameters of the function call.
Now, when zip is called, it starts from left to right to call the iterators to obtain elements that should be grouped together. Since all parameters refer to the same iterator, this yields the first n
elements of the initial sequence. Then that process continues for the second group in the resulting list, and so on.
The result is the same as if you had constructed the list like this (evaluated from left to right):
it = iter(s)
[(it.next(), it.next(), ..., it.next()), (it.next(), it.next(), ..., it.next()), ...]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With