有一个元组列表l = [(x,y,z), (x,y,z), (x,y,z)]
这个想法是找到为每个x-s,y-s,z-s创建不同的np.array的最快方法。在寻求最快的解决方案方面需要帮助。为了进行速度比较,我使用下面随附的代码
import time
def myfast():
code
n = 1000000
t0 = time.time()
for i in range(n): myfast()
t1 = time.time()
total_n = t1-t0
1. np.array([i[0] for i in l])
np.array([i[1] for i in l])
np.array([i[2] for i in l])
输出:0.9980638027191162
2. array_x = np.zeros((len(l), 1), dtype="float")
array_y = np.zeros((len(l), 1), dtype="float")
array_z = np.zeros((len(l), 1), dtype="float")
for i, zxc in enumerate(l):
array_x[i] = zxc[0]
array_y[i] = zxc[1]
array_z[i] = zxc[2]
输出5.5509934425354
3. [np.array(x) for x in zip(*l)]
输出2.5070037841796875
5. array_x, array_y, array_z = np.array(list(zip(*l)))
输出2.725318431854248
答案 0 :(得分:2)
您可以尝试:
import numpy
array_x, array_y, array_z = numpy.array(list(zip(*l)))
或者只是:
numpy.array(list(zip(*l)))
更优雅的方式:
numpy.array(l).transpose()
答案 1 :(得分:2)
这里有一些非常好的选择,所以我总结了一下并比较了速度:
import numpy as np
def f1(input_data):
array_x = np.array([elem[0] for elem in input_data])
array_y = np.array([elem[1] for elem in input_data])
array_z = np.array([elem[2] for elem in input_data])
return array_x, array_y, array_z
def f2(input_data):
array_x = np.zeros((len(input_data), ), dtype="float")
array_y = np.zeros((len(input_data), ), dtype="float")
array_z = np.zeros((len(input_data), ), dtype="float")
for i, elem in enumerate(input_data):
array_x[i] = elem[0]
array_y[i] = elem[1]
array_z[i] = elem[2]
return array_x, array_y, array_z
def f3(input_data):
return [np.array(elem) for elem in zip(*input_data)]
def f4(input_data):
return np.array(list(zip(*input_data)))
def f5(input_data):
return np.array(input_data).transpose()
def f6(input_data):
array_all = np.array(input_data)
array_x = array_all[:, 0]
array_y = array_all[:, 1]
array_z = array_all[:, 2]
return array_x, array_y, array_z
首先,我断言它们都返回相同的数据(使用np.array_equal()
):
data = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]
for array_list in zip(f1(data), f2(data), f3(data), f4(data), f5(data), f6(data)):
# print()
# for i, arr in enumerate(array_list):
# print('array from function', i+1)
# print(arr)
for i, arr in enumerate(array_list[:-1]):
assert np.array_equal(arr, array_list[i+1])
时间比较:
import timeit
for f in [f1, f2, f3, f4, f5, f6]:
t = timeit.timeit('f(data)', 'from __main__ import data, f', number=100000)
print('{:5s} {:10.4f} seconds'.format(f.__name__, t))
给出以下结果:
data = [(1, 2, 3), (4, 5, 6), (7, 8, 9)] # 3 tuples
timeit number=100000
f1 0.3184 seconds
f2 0.4013 seconds
f3 0.2826 seconds
f4 0.2091 seconds
f5 0.1732 seconds
f6 0.2159 seconds
data = [(1, 2, 3) for _ in range(10**6)] # 1 millon tuples
timeit number=10
f1 2.2168 seconds
f2 2.8657 seconds
f3 2.0150 seconds
f4 1.9790 seconds
f5 2.6380 seconds
f6 2.6586 seconds
使f5()
是短输入的最快选择,而f4()
是大输入的最快选择。
如果每个元组中的元素数大于3,则只有3个函数适用于这种情况(其他函数针对每个元组中的3个元素进行了硬编码):
data = [tuple(range(10**4)) for _ in range(10**3)]
timeit number=10
f3 11.8396 seconds
f4 13.4672 seconds
f5 4.6251 seconds
再次使f5()
成为满足这些条件的最快选择。
答案 2 :(得分:1)
也许我遗漏了一些东西,但是为什么不将元组列表直接传递给np.array
?说:
n = 100
l = [(0, 1, 2) for _ in range(n)]
arr = np.array(l)
x = arr[:, 0]
y = arr[:, 1]
z = arr[:, 2]
顺便说一句,我更喜欢使用以下代码计时:
from timeit import default_timer as timer
t0 = timer()
do_heavy_calculation()
print("Time taken [sec]:", timer() - t0)
答案 3 :(得分:0)
我相信这个答案的大部分(并非全部)成分实际上都存在于其他答案中,但是就某些方法而言,到目前为止,我还没有看到苹果与苹果的比较。不是返回np.ndarray
对象的列表,而是返回一个(在我看来很方便)单个np.ndarray()
。
目前尚不清楚这是否可以接受,因此我为此添加了适当的代码。 除此之外,性能可能会有所不同,因为在某些情况下,您要添加一个额外的步骤,而对于另一些情况,则可能不需要创建大对象(可以驻留在不同的内存页面中)。
最后,对于较小的输入(3 x 10),np.ndarray()
列表只是一些额外的负担,这些负担会大大增加时间。
对于较大的输入(3 x 1000)以及更高的输入,不再需要额外的计算,但是一种涉及理解并避免创建大型numpy
数组的方法可以变得和(甚至 faster < / em>)。
此外,我介绍的所有代码都适用于任意大小的元组/列表(当然,只要内部元组都具有相同的大小)即可。
(编辑:对最终结果添加了评论)
测试的方法是:
import numpy as np
def to_arrays_zip(items):
return np.array(list(zip(*items)))
def to_arrays_transpose(items):
return np.array(items).transpose()
def to_arrays_zip_split(items):
return [arr for arr in np.array(list(zip(*items)))]
def to_arrays_transpose_split(items):
return [arr for arr in np.array(items).transpose()]
def to_arrays_comprehension(items):
return [np.array([items[i][j] for i in range(len(items))]) for j in range(len(items[0]))]
def to_arrays_comprehension2(items):
return [np.array([item[j] for item in items]) for j in range(len(items[0]))]
(这是检查结果是否相同的便捷功能。)
def test_equal(items1, items2):
return all(np.all(x == y) for x, y in zip(items1, items2))
对于少量输入:
N = 3
M = 10
ll = [tuple(range(N)) for _ in range(M)]
print(to_arrays_comprehension2(ll))
print('Returning `np.ndarray()`')
%timeit to_arrays_zip(ll)
# 2.82 µs ± 28 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit to_arrays_transpose(ll)
# 3.18 µs ± 30 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
print('Returning a list')
%timeit to_arrays_zip_split(ll)
# 3.71 µs ± 47 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit to_arrays_transpose_split(ll)
# 3.97 µs ± 42.8 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit to_arrays_comprehension(ll)
# 5.91 µs ± 96.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%timeit to_arrays_comprehension2(ll)
# 5.14 µs ± 109 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
讲台在哪里
to_arrays_zip_split()
(如果可以使用单个数组,则为非_split
)to_arrays_zip_transpose_split()
(如果可以使用单个数组,则为非_split
)to_arrays_comprehension2()
对于较大的输入:
N = 3
M = 1000
ll = [tuple(range(N)) for _ in range(M)]
print('Returning `np.ndarray()`')
%timeit to_arrays_zip(ll)
# 146 µs ± 2.3 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit to_arrays_transpose(ll)
# 222 µs ± 2.01 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
print('Returning a list')
%timeit to_arrays_zip_split(ll)
# 147 µs ± 1.68 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%timeit to_arrays_transpose_split(ll)
# 221 µs ± 2.58 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit to_arrays_comprehension(ll)
# 261 µs ± 2.6 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit to_arrays_comprehension2(ll)
# 212 µs ± 1.68 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
登上领奖台:
to_arrays_zip_split()
(无论您使用的是_split
还是非_split
的变体,都没有太大区别)to_arrays_comprehension2()
to_arrays_zip_transpose_split()
(无论您使用的是_split
还是非_split
的变体,都没有太大区别)对于更大的输入:
N = 3
M = 1000000
ll = [tuple(range(N)) for _ in range(M)]
print('Returning `np.ndarray()`')
%timeit to_arrays_zip(ll)
# 215 ms ± 4.27 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit to_arrays_transpose(ll)
# 220 ms ± 4.62 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
print('Returning a list')
%timeit to_arrays_zip_split(ll)
# 218 ms ± 6.21 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit to_arrays_transpose_split(ll)
# 222 ms ± 3.48 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit to_arrays_comprehension(ll)
# 248 ms ± 3.55 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%timeit to_arrays_comprehension2(ll)
# 186 ms ± 481 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
登上领奖台:
to_arrays_comprehension2()
to_arrays_zip_split()
(无论您使用的是_split
还是非_split
的变体,都没有太大区别)to_arrays_zip_transpose_split()
(无论您使用的是_split
还是非_split
的变体,都没有太大区别)与_zip
和_transpose
的变体非常接近。
(我还尝试通过Numba加快运行速度,效果不佳)