在循环中创建NumPy数组的最有效和最pythonic的方法

时间:2017-07-10 14:11:19

标签: python numpy

我目前正在尝试找出在循环中创建numpy数组的最有效方法,以下是示例:

import numpy as np
from time import time
tic = time()
my_list = range(1000000)
a = np.zeros((len(my_list),))
for i in my_list:
   a[i] = i
toc = time()
print(toc-tic)

VS

tic = time()
a = []
my_list = range(1000000)
for i in my_list:
    a.append(i)
a = np.array(a)
toc = time()

print(toc-tic)

我期待第二个比第一个慢得多,因为在for循环的每个步骤都需要新的内存,但是这些大致相同而且我想知道为什么,但仅仅是为了好奇因为我可以用它们做到这一点。

我实际上想要编写一个简单的numpy数组,其中包含从数据框中提取的数据,它看起来非常混乱。我想知道是否会有更多的pythonic方式来做到这一点。我有这个数据框和我需要的标签列表,最简单的想法是执行以下操作(我需要的值是每列的最后一个):

vars_outputs = ["x1", "x2", "ratio_x1_x2"]
my_df = pd.read_excel(path)
outpts = np.array(my_df[vars_outputs][-1])

然而,这是不可能的,因为我想要的一些标签在数据帧中不能直接使用:例如,需要从两个第一列计算ratio_x1_x2。所以我添加了一个带有缺失标签的dict以及计算它们的方式(它唯一的比例):

missing_labels = {"ratio_x1_x2" : ["x1", "x2"]}

并检查条件并创建numpy数组(因此之前关于效率的问题)

outpts = []
for var in vars_outputs:
    if var in missing_labels.keys():
        outpts.append(my_df[missing_labels[var][0]][-1]/my_df[missing_labels[var][1]][-1])
    else:
        outpts.append(my_df[var][-1])
outpts = np.array(outpts)

在我看来这太复杂了,但我想不出更简单的方法(特别是因为我需要在我的numpy输出数组中有这个特定的顺序)

我的另一个想法是在数据框中添加我想要的操作的列,但因为有大约8000个标签我不知道它是否是最好的,因为我必须要看在此预处理步骤之后进入所有这些标签

非常感谢

2 个答案:

答案 0 :(得分:1)

这是最终的代码,np.fromiter()完成了这个技巧并允许通过使用列表理解来减少行数

df = pd.read_excel(path)
print(df.columns)

输出[' x1',' x2']

vars_outputs = ["x1", "x2", "ratio_x1_x2"]
missing_labels = {"ratio_x1_x2" : ["x1", "x2"]}

it = [df[missing_labels[var][0]].iloc[-1]/df[missing_labels[var][1]].iloc[-1] if var in missing_labels
        else df[var].iloc[-1] for var in vars_outputs]

t = np.fromiter(it, dtype = float)

答案 1 :(得分:0)

谢谢@hpaulj,这对我将来可能非常有用。我不知道使用fromiter()

加快速度
import timeit
setup = '''
import numpy as np
H, W = 400, 400
it = [(1 + 1 / (i + 0.5)) ** 2 for i in range(W) for j in range(H)]'''

fns = ['''
x = np.array([[(1 + 1 / (i + 0.5)) ** 2 for i in range(W)] for j in range(H)])
''', '''
x = np.fromiter(it, np.float)
x.reshape(H, W)
''']
for f in fns:
  print(timeit.timeit(f,setup=setup, number=100))
# gives me
# 6.905218548999983
# 0.5763416080008028

编辑PS你的for循环可能是某种迭代器,如

it = [my_df[missing_labels[var][0]][-1]
        / my_df[missing_labels[var][1]][-1] if var in missing_labels
        else my_df[var][-1] for var in var_outputs]
相关问题