Python:组合函数多次运行的输出变量的优雅方法

2024-09-28 03:16:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个函数,它返回许多大小不同的输出数组。你知道吗

arr1,arr2,arr3,arr4,arr5, ... = func(data)

我想在数据的时间序列上多次运行这个函数,并将每个输出变量组合成一个覆盖整个时间序列的数组。你知道吗

详细说明:如果在调用函数时,输出arr1有维数(x,y),我想运行函数't'次,最后得到一个有维数(x,y,t)的数组。大小为(x,y)的“t”数组列表也是可以接受的,但不是首选。你知道吗

同样,输出数组并非都具有相同的维数,甚至维数也不相同。Arr2可能有大小(x2,y2),arr3可能只是长度的向量(x3)。我不知道所有这些数组的大小。你知道吗

我目前的解决方案是这样的:

arr1 = []
arr2 = []
arr3 = []
...

for t in range(t_max):
   arr1_t, arr2_t, arr3_t, ... = func(data[t])

   arr1.append(arr1_t)
   arr2.append(arr2_t)
   arr3.append(arr3_t)
...

等等。然而,当对每个输出阵列重复27次时,这看起来并不美观。你知道吗

有没有更好的办法?你知道吗


Tags: 数据函数data时间序列数组func调用函数
3条回答

你可以把arr1arr2等列成一个列表(向量或矩阵或任何东西)。然后使用循环迭代从func获得的结果,并将它们添加到各个列表中。你知道吗

arrN = [[] for _ in range(N)]  # N being number of results from func
for t in range(t_max):
    results = func(data[t])
    for i, res in enumerate(results):
        arrN[i].append(res)

不同子列表中的元素不必具有相同的维度。你知道吗

这个答案给出了一个使用structured arrays的解决方案。它有以下要求:即使一个函数f返回N数组,并且每个返回数组的大小可以不同,那么对于f的所有结果,len(array_i)必须始终相同。例如

arrs_a = f("a")
arrs_b = f("b")
for sub_arr_a, sub_arr_b in zip(arrs_a, arrs_b):
   assert len(sub_arr_a) == len(sub_arr_b)

如果上述情况属实,则可以使用结构化数组。结构化数组类似于普通数组,只是具有复杂的数据类型。例如,我可以指定一个数据类型,它由一个shape5的int数组和另一个shape(2, 2)的float数组组成。例如

# define what a record looks like
dtype = [
    # tuples of (field_name, data_type)
    ("a", "5i4"), # array of five 4-byte ints
    ("b", "(2,2)f8"), # 2x2 array of 8-byte floats
]

使用dtype可以创建一个结构化数组,并一次性设置结构化数组上的所有结果。你知道吗

import numpy as np

def func(n):
    "mock implementation of func"
    return (
        np.ones(5) * n,
        np.ones((2,2))* n
    )

# define what a record looks like
dtype = [
    # tuples of (field_name, data_type)
    ("a", "5i4"), # array of five 4-byte ints
    ("b", "(2,2)f8"), # 2x2 array of 8-byte floats
]

size = 5
# create array
arr = np.empty(size, dtype=dtype)
# fill in values
for i in range(size):
    # func must return a tuple
    # or you must convert the returned value to a tuple
    arr[i] = func(i)

# alternate way of instantiating arr
arr = np.fromiter((func(i) for i in range(size)), dtype=dtype, count=size)

# How to use structured arrays
# access individual record
print(arr[1]) # prints ([1, 1, 1, 1, 1], [[1, 1], [1, 1]])
# access specific value   get second record -> get b field -> get value at 0,0
assert arr[2]['b'][0,0] == 2
# access all values of a specific field
print(arr['a']) # prints all the a arrays

不确定它是否算作“优雅”,但您可以构建结果tuplelist,然后使用zip按返回位置而不是按调用号将它们分组到tuple,然后可选地map将这些tuple转换为最终的数据类型。例如,对于numpyarray

from future_builtins import map, zip  # Only on Python 2, to minimize temporaries
import numpy as np

def func(x):
     'Dumb function to return tuple of powers of x from 1 to 27'
     return tuple(x ** i for i in range(1, 28))

# Example inputs for func
data = [np.array([[x]*10]*10, dtype=np.uint8) for  in range(10)]

# Output is generator of results for each call to func
outputs = map(func, data)

# Pass each complete result of func as a positional argument to zip via star
# unpacking to regroup, so the first return from each func call is the first
# group, then the second return the second group, etc.
positional_groups = zip(*outputs)

# Convert regrouped data (`tuple`s of 2D results) to numpy 3D result type, unpack to names
arr1,arr2,arr3,arr4,arr5, ...,arr27 = map(np.array, positional_groups)

如果在给定位置从func返回的元素可能有不一致的维度(例如,一个调用可能返回10x10作为第一个返回,另一个返回5x5),那么您应该避免最后的map步骤(因为array没有一致的维度,只需将第二个到最后一个步骤替换为:

arr1,arr2,arr3,arr4,arr5, ...,arr27 = zip(*outputs)

使arr#成为tuple的2D array,或者如果需要可变:

arr1,arr2,arr3,arr4,arr5, ...,arr27 = map(list, zip(*outputs))

使它们成为2D arraylist

相关问题 更多 >

    热门问题