我正在尝试创建一个索引列表,其索引范围为0
至m - 1
,长度为n
。到目前为止,我已经实现了以下目标:
import numpy as np
m = 7
n = 12
indices = [np.mod(i, m) for i in np.arange(n)]
结果如下:
[0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4]
是否有更快的方法来实现这一目标?
谢谢您的建议。
答案 0 :(得分:3)
您可以使用islice
中的cycle
+ itertools
:
from itertools import islice, cycle
print(list(islice(cycle(range(7)), 12)))
# [0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4]
答案 1 :(得分:2)
只需使用列表推导将往返传递到python。从numpy获得良好的速度就是确保循环保持在numpy内,而不是在python本身内循环。
np.mod(np.arange(n), m)
这是唯一在数字上正确的答案,从某种意义上说,这很明显避免了python中的所有for循环。 (编辑:如其他答案所示,事实证明,它离最快的解决方案还差得很远)
答案 2 :(得分:1)
鉴于您使用的是numpy
,一种方法是使用np.arange
和np.resize
,这将用原始数组的副本填充更大的调整大小数组:
np.resize(np.arange(7), 12)
# array([0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4])
答案 3 :(得分:1)
基于NumPy的np.tile
-
np.tile(np.arange(m),(n+m-1)//m)[:n]
样品运行-
In [58]: m,n = 7,12
In [59]: np.tile(np.arange(m),(n+m-1)//m)[:n]
Out[59]: array([0, 1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4])
如果您正在寻找效率,尤其是在处理大型数据方面,NumPy会做得很好。在本部分中,我们将对在m
和n
之间变化的NumPy解决方案进行计时。
设置:
import numpy as np
def resize(m,n):
return np.resize(np.arange(m), n)
def mod(m,n):
return np.mod(np.arange(n), m)
def tile(m,n):
return np.tile(np.arange(m),(n+m-1)//m)[:n]
在IPython控制台上运行计时代码:
# Setup inputs and timeit those on posted NumPy approaches
m_ar = [10,100,1000]
s_ar = [10,20,50,100,200,500,1000] # scaling array
resize_timings = []
mod_timings = []
tile_timings = []
sizes_str = []
for m in m_ar:
for s in s_ar:
n = m*s+m//2
size_str = str(m) + 'x' + str(n)
sizes_str.append(size_str)
p = %timeit -o -q resize(m,n)
resize_timings.append(p.best)
p = %timeit -o -q mod(m,n)
mod_timings.append(p.best)
p = %timeit -o -q tile(m,n)
tile_timings.append(p.best)
在图上获取结果:
# Use pandas to study results
import pandas as pd
df_data = {'Resize':resize_timings,'Mod':mod_timings,'Tile':tile_timings}
df = pd.DataFrame(df_data,index=sizes_str)
FGSZ = (20,6)
T = 'Timings(s)'
FTSZ = 16
df.plot(figsize=FGSZ,title=T,fontsize=FTSZ).get_figure().savefig("timings.png")
比较所有三个
resize
和基于tile
的计算机似乎运行良好。
比较resize
和tile
让我们只绘制这两个图:
tile
在这两者之间似乎做得更好。
现在,让我们研究与三个不同的m's
相对应的块中的计时:
mod
仅基于小m
和小n
获胜,而m和n的时间大约为5-6 u-sec,但输掉了在大多数其他情况下,正是与之相关的计算在这些情况下将其杀死。
答案 4 :(得分:1)
由于您要求的是最快的速度,因此最好提供一些测试时间。因此,我使用timeit
模块测试了大多数已发布的代码段。
快速定义的函数可简化对timeit的调用。
def list_comp(m, n):
return [np.mod(i, m) for i in np.arange(n)]
def leftover(m, n):
nb_cycles = n//m
leftover = n-m*nb_cycles
indices = list(range(m))*nb_cycles + list(range(leftover))
def islice_cycle(m, n):
return list(islice(cycle(range(m)), n))
def npmod(m, n):
return mod(np.arange(m), n)
def resized(m, n):
return np.resize(np.arange(m), n)
经过测试:
timer = timeit.Timer(stmt="function_name(7, 12)", globals=globals()).repeat(repeat=100, number =10000)
print(f'Min: {min(timer):.6}s,\n Avg: {np.average(timer):.6}s')
结果
| Function | Minimum | Average |
|:---------------|------------:|:------------:|
| list_comp | 0.156117s | 0.160433s |
| islice_cycle | 0.00712442s | 0.00726821s |
| npmod | 0.0118933s | 0.0123122s |
| leftover | 0.00943538s | 0.00964464s |
| resized | 0.0818617s | 0.0851646s |
到目前为止,使用islice
和cycle
的@Austin答案是最快的。 @ T.Lucas慢一点,但是只有一点点,但是对于纯python来说却相当快。
其他答案要慢很多。
答案 5 :(得分:0)
如果您正在寻找速度,这是我发现的更快的方法:
nb_cycles = n//m
leftover = n-m*nb_cycles
indices = list(range(m))*nb_cycles + list(range(leftover))