我有一个事件数据集(特定的推文),我试图进行分区/离散化。到目前为止,以下代码似乎工作正常(假设有100个分箱):
HOUR = timedelta(hours=1)
start = datetime.datetime(2009,01,01)
z = [dt + x*HOUR for x in xrange(1, 100)]
然而,我在python docs遇到了这个命运的路线'这使得使用zip(*[iter(s)]*n)
'将数据系列聚类成n长度组成为可能。 zip惯用语确实有用 - 但我无法理解(例如*
运算符是什么?)。我怎么能用来使我的代码更漂亮?我猜这意味着我应该制作一个生成器/可迭代的时间yields
在一个小时的毕业时间?
答案 0 :(得分:5)
文档中的表达式如下所示:
zip(*[iter(s)]*n)
这相当于:
it = iter(s)
zip(*[it, it, ..., it]) # n times
[...]*n
重复列表n
次,这会产生一个包含n
对同一迭代器的引用的列表。
这又等于:
it = iter(s)
zip(it, it, ..., it) # turning a list into positional parameters
列表前的*
将列表元素转换为函数调用的位置参数。
现在,当调用zip时,它从左到右开始调用迭代器以获取应该组合在一起的元素。由于所有参数都引用相同的迭代器,因此产生初始序列的第一个n
元素。然后,对结果列表中的第二个组继续该过程,依此类推。
结果与您构建这样的列表(从左到右评估)相同:
it = iter(s)
[(it.next(), it.next(), ..., it.next()), (it.next(), it.next(), ..., it.next()), ...]
答案 1 :(得分:5)
我将尝试用更简单的例子解释zip(*[iter(s)]*n)
:
假设你有列表s = [1, 2, 3, 4, 5, 6]
iter(s)
会为您提供一个listiterator
对象,每当您要求元素时,该对象将从s
生成下一个数字。
[iter(s)] * n
为其提供了 n 次iter(s)
的列表,例如[iter(s)] * 2 = [<listiterator object>, <listiterator object>]
- 这里的关键是这些是对相同迭代器对象的2个引用,而不是2个不同的迭代器对象。
zip
接受许多序列并返回一个元组列表,其中每个元组包含来自每个序列的 ith 元素。例如zip([1,2], [3,4], [5,6]) = [(1, 3, 5), (2, 4, 6)]
其中(1, 3, 5)
是传递给zip
和(2, 4, 6)
的参数的第一个元素,是传递给zip
的参数中的第二个元素。
*
前面的*[iter(s)]*n
会将[iter(s)]*n
从列表转换为传递给zip
的多个参数。因此,如果n
为2,我们会得到zip(<listiterator object>, <listiterator object>)
zip
将从其每个参数中请求下一个元素,但因为它们都是对同一个迭代器的引用,这将导致(1, 2)
,它会再次执行相同的操作,从而导致(3, 4)
并再次产生(5, 6)
,然后没有更多的元素,所以它停止。因此结果为[(1, 2), (3, 4), (5, 6)]
。这是将数据系列聚类成n长组,如上所述。