重复索引列表

时间:2019-04-18 09:05:25

标签: python list numpy

我正在尝试创建一个索引列表,其索引范围为0m - 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]

是否有更快的方法来实现这一目标?

谢谢您的建议。

6 个答案:

答案 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.arangenp.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会做得很好。在本部分中,我们将对在mn之间变化的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")

结果

比较所有三个

enter image description here

resize和基于tile的计算机似乎运行良好。

比较resizetile

让我们只绘制这两个图:

enter image description here

tile在这两者之间似乎做得更好。

分块学习

现在,让我们研究与三个不同的m's相对应的块中的计时:

enter image description here

enter image description here

enter image description here

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  |  
到目前为止,使用islicecycle

@Austin答案是最快的。 @ T.Lucas慢一点,但是只有一点点,但是对于纯python来说却相当快。

其他答案要慢很多。

答案 5 :(得分:0)

如果您正在寻找速度,这是我发现的更快的方法:

nb_cycles = n//m
leftover = n-m*nb_cycles
indices = list(range(m))*nb_cycles + list(range(leftover))