我有一个从不同长度的列表创建的数组。我事先不知道列表的长度,这就是我使用列表而不是数组的原因。
以下是针对此问题的可重现代码:
a = []
for i in np.arange(5):
a += [np.random.rand(np.random.randint(1,6))]
a = np.array(a)
将这个数组转换为结构良好的数组,其行与NaNs的大小相同,是否有更有效的方法?
max_len_of_array = 0
for aa in a:
len_of_array = aa.shape[0]
if len_of_array > max_len_of_array:
max_len_of_array = len_of_array
max_len_of_array
n = a.shape[0]
A = np.zeros((n, max_len_of_array)) * np.nan
for i, aa in enumerate(zip(a)):
A[i][:aa[0].shape[0]] = aa[0]
A
答案 0 :(得分:3)
以下是代码的稍快版本:
def alt(a):
A = np.full((len(a), max(map(len, a))), np.nan)
for i, aa in enumerate(a):
A[i, :len(aa)] = aa
return A
for循环是不可避免的。鉴于a
是一个Python列表,没有必要迭代列表中的项目。有时可以隐藏循环(例如,在调用max
和map
之后),但速度方面它们基本上等同于Python循环。
以下是使用a
的基准,其结果为(100, 100)
:
In [197]: %timeit orig(a)
10000 loops, best of 3: 125 µs per loop
In [198]: %timeit alt(a)
10000 loops, best of 3: 84.1 µs per loop
In [199]: %timeit using_pandas(a)
100 loops, best of 3: 4.8 ms per loop
这是用于基准测试的设置:
import numpy as np
import pandas as pd
def make_array(h, w):
a = []
for i in np.arange(h):
a += [np.random.rand(np.random.randint(1,w+1))]
a = np.array(a)
return a
def orig(a):
max_len_of_array = 0
for aa in a:
len_of_array = aa.shape[0]
if len_of_array > max_len_of_array:
max_len_of_array = len_of_array
n = a.shape[0]
A = np.zeros((n, max_len_of_array)) * np.nan
for i, aa in enumerate(zip(a)):
A[i][:aa[0].shape[0]] = aa[0]
return A
def alt(a):
A = np.full((len(a), max(map(len, a))), np.nan)
for i, aa in enumerate(a):
A[i, :len(aa)] = aa
return A
def using_pandas(a):
return pd.DataFrame.from_records(a).values
a = make_array(100,100)
答案 1 :(得分:0)
我想你可以使用熊猫作为一次性解决方案,但它会像一切熊猫一样效率很低:
pd.DataFrame(a)[0].apply(pd.Series).values
#array([[ 0.28669545, 0.22080038, 0.32727194],
# [ 0.17892276, nan, nan],
# [ 0.26853548, nan, nan],
# [ 0.86460043, 0.78827094, 0.96660502],
# [ 0.41045599, nan, nan]])