Python 用cycle()循环迭代,cycle()
函数重复循环一组值,可用它循环数据集标识符对数据集进行分组。
还可以用它解决简单的fizz-buzz问题,关于该问题的多种解法可参考http://rosettacode.org/wiki/FizzBuzz,基于它的一些有趣变体可参考https://projecteuler.net/problem=1。
可以利用cycle()
函数生成一系列True
和False
值,如下所示:
m3 = (i == 0 for i in cycle(range(3)))
m5 = (i == 0 for i in cycle(range(5)))
返回结果是无限长的布尔值序列:[True, False, False, True, False, False, ...]
或[True, False, False, False, False, True, False, False, False, False, ...]
。
如果用zip()
处理有限个数值序列和上面两个标识序列,可以得到一个三元组序列,第一部分是数值,另外两个是分别代表是否为3的倍数或5的倍数的标识值。注意这里要引入一个有限的可迭代对象来生成目标数据的上限。这样的一系列值及其标识值如下:
multipliers = zip(range(10), m3, m5)
这样就得到了一个生成器对象,可以用list(multipliers)
查看其中包含的结果值,如下所示:
[(0, True, True), (1, False, False), (2, False, False), ..., (9, True, False)]
这样就可以拆解三元组了,用一个过滤器选出倍数值,舍弃其他数值:
total = sum(i
for i, *multipliers in multipliers
if any(multipliers)
)
for
从句将每个元组拆分成两部分:数值i
和标识值multipliers
,如果标识值含真值,则保留该数值,否则将其舍弃。
该函数在EDA中很有用。
我们经常要处理大型数据集的样本,在最初的清洗和建模阶段,应使用小数据集,然后在更大的数据集上进行测试。使用cycle()
函数可以方便从大型数据集中选取记录。给定总体数据大小 N_p 与样本集大小 N_s,可算出循环体的大小。
假设用csv
模块解析数据,则可以轻松生成子数据集,已知循环体大小cycle_size
和两个打开的文件source_file
和target_file
,生成子数据集的方法如下:
chooser = (x == 0 for x in cycle(range(cycle_size)))
rdr = csv.reader(source_file)
wtr = csv.writer(target_file)
wtr.writerows(
row for pick, row in zip(chooser, rdr) if pick
)
首先基于拣选因子cycle_size
和cycle()
函数生成拣选函数。比如总体数据集大小为10 000 000,拣选数据集大小为1000,即选取了1/10 000的数据。这里我们假设打开数据文件时,这些代码都嵌在with
语句中。
接着用基于cycle()
函数的生成器表达式和取自CSV读取器的源数据文件过滤数据。由于用chooser()
函数和写数据函数都是非严格的,这类处理消耗内存很少。
稍后会介绍如何使用compress()
、filter()
和islice()
函数实现相同的功能。
用这个方法还能将非标准CSV文件转换为标准CSV文件。只要数据解析器返回格式一致的元组,并通过写文件方法定义好consumer
函数,就能用简单的脚本实现许多清洗和过滤操作。