Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 为元组列表中的每个项创建np.Array的最快方法_Python_Python 3.x_List_Performance_Numpy - Fatal编程技术网

Python 为元组列表中的每个项创建np.Array的最快方法

Python 为元组列表中的每个项创建np.Array的最快方法,python,python-3.x,list,performance,numpy,Python,Python 3.x,List,Performance,Numpy,有一个元组列表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

有一个元组列表
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

产出5.5509934425354

产出2.5070037841796875

产出2.725318431854248

你可以试试:

import numpy
array_x, array_y, array_z = numpy.array(list(zip(*l)))
或者只是:

numpy.array(list(zip(*l)))
更优雅的方式:

numpy.array(l).transpose()
你可以试试:

import numpy
array_x, array_y, array_z = numpy.array(list(zip(*l)))
或者只是:

numpy.array(list(zip(*l)))
更优雅的方式:

numpy.array(l).transpose()

也许我遗漏了什么,但为什么不直接将元组列表传递给
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)

也许我遗漏了什么,但为什么不直接将元组列表传递给
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)

这里有一些非常好的选择,所以我总结了它们并比较了速度:

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()
):

时间比较:

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个元素硬编码):


使
f5()
再次成为这些标准的最快选项。

这里有一些非常好的选项,所以我总结了它们并比较了速度:

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()
):

时间比较:

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个元素硬编码):

f5()
再次成为这些标准的最快选择。

我相信这个答案的大部分(但不是全部)成分实际上都存在于其他答案中,但到目前为止,在所有答案中,我还没有看到苹果对苹果的比较,从某种意义上说,有些方法不是返回
np.ndarray
对象列表,而是返回一个(在我看来很方便的)单个
np.ndarray()

现在还不清楚您是否可以接受这一点,因此我正在为此添加适当的代码。 此外,性能可能会有所不同,因为在某些情况下,您添加了一个额外的步骤,而在另一些情况下,您可能不需要创建大型对象(可能位于不同的内存页中)

最后,对于较小的输入(3 x 10),np.ndarray()s列表只是一些额外的负担,大大增加了计时。 对于较大的输入(3 x 1000)和更大的输入,额外的计算不再重要,但是一种涉及理解和避免创建大型
numpy
数组的方法可以与用于较小输入的最快方法一样快(甚至更快)

此外,我展示的所有代码都适用于任意大小的元组/列表(当然,只要内部元组的大小都相同)

(编辑:添加对最终结果的评论)


测试方法包括:

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]))]
(这是一个检查结果是否相同的方便功能。)


对于小输入:

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\u zip\u split()
    (如果您可以使用单个数组,则使用非
    \u split
  • 到数组\u-zip\u转置\u-split()
    (如果您可以使用单个数组,则使用非
    \u-split
  • 到\u数组\u理解2()

  • 对于较大的输入:

    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)
    
    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_array\u zip_split()
    (无论是使用
    \u split
    还是非
    \u split
    变体,都没有多大区别)
  • 到\u数组\u理解2()
  • 到数组\u-zip\u转置\u-split()
    (无论您使用
    \u-split
    还是非
    \u-split
    变体,都没有多大区别)

  • 对于更大的输入:

    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)
    
    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)
    
    讲台变成:

  • 到\u数组\u理解2()
  • to_array\u zip_split()
    (无论是使用
    \u split
    还是非
    \u split
    变体,都没有多大区别)
  • 到数组\u-zip\u转置\u-split()
    (无论您使用
    \u-split
    还是非
    \u-split
    变体,都没有多大区别)
  • \u-zip
    \u-transpose
    变体彼此非常接近

    (我还试图加快与Numba的合作,但进展并不顺利)

    我相信这个答案的大部分(但不是全部)成分实际上都存在于其他答案中,但到目前为止,在所有答案中,我还没有看到苹果对苹果的比较,因为有些方法没有返回
    np.ndarray
    对象的列表,而是一个(在我看来很方便的)单一的
    np.ndarray()

    现在还不清楚您是否可以接受这一点,因此我正在为此添加适当的代码。 此外,性能可能会有所不同,因为在某些情况下,您添加了一个额外的步骤,而在另一些情况下,您可能不需要创建大型对象(可能位于不同的内存页中)

    最后,对于较小的输入(3 x 10),np.ndarray()s列表只是一些额外的负担,大大增加了计时。 对于较大的输入(3 x 1000)和更大的输入,额外的计算不再重要,而是一种涉及理解和避免创建大型
    numpy