不同行大小的numpy填充矩阵

ssgvzors  于 2023-04-30  发布在  其他
关注(0)|答案(3)|浏览(106)

我有一个不同行大小的numpy数组

a = np.array([[1,2,3,4,5],[1,2,3],[1]])

我想把它变成一个密集的(固定n × m大小,没有可变行)矩阵。直到现在我尝试过这样的东西

size = (len(a),5)    
result = np.zeros(size)
result[[0],[len(a[0])]]=a[0]

但我收到一个错误告诉我
形状不匹配:无法将形状(5,)的值数组广播到形状(1,)的索引结果
我也试着用NP做填充。pad,但根据numpy的文档。pad似乎我需要在pad_width中指定行的先前大小(这是可变的,并在尝试-1,0和最大行大小时产生错误)。
我知道我可以像here所示的那样,每行填充填充列表,但是我需要用更大的数据数组来做这件事。
如果有人能帮我回答这个问题,我会很高兴知道的。

e4eetjau

e4eetjau1#

真的没有办法填充jagged array,这样它就会失去它的锯齿性,而不必迭代数组的行。你需要遍历数组两次:一次是找出你需要填充的最大长度,另一次是实际做填充。
你已经链接到的代码提案将完成这项工作,但它不是很有效,因为它在迭代行元素的python for循环中添加了零,而这种追加本来可以预先计算,从而将更多的代码推到C中。
下面的代码预先计算一个所需最小维数的数组,用零填充,然后简单地将锯齿数组M中的行添加到位,这要高效得多。

import random
import numpy as np
M = [[random.random() for n in range(random.randint(0,m))] for m in range(10000)] # play-data

def pad_to_dense(M):
    """Appends the minimal required amount of zeroes at the end of each 
     array in the jagged array `M`, such that `M` looses its jagedness."""

    maxlen = max(len(r) for r in M)

    Z = np.zeros((len(M), maxlen))
    for enu, row in enumerate(M):
        Z[enu, :len(row)] += row 
    return Z

给予你一些关于速度的想法:

from timeit import timeit
n = [10, 100, 1000, 10000]
s = [timeit(stmt='Z = pad_to_dense(M)', setup='from __main__ import pad_to_dense; import numpy as np; from random import random, randint; M = [[random() for n in range(randint(0,m))] for m in range({})]'.format(ni), number=1) for ni in n]
print('\n'.join(map(str,s)))
# 7.838103920221329e-05
# 0.0005027339793741703
# 0.01208890089765191
# 0.8269036808051169

如果你想在数组前面加上零,而不是追加,这是对代码的一个足够简单的修改,我将把它留给你。

kpbwa7wx

kpbwa7wx2#

你可以用numpy做类似的事情。垫

import numpy as np
a = np.array([[1,2,3,4,5],[1,2,3],[1]])
l = np.array([len(a[i]) for i in range(len(a))])
width = l.max()
b=[]
for i in range(len(a)):
    if len(a[i]) != width:
        x = np.pad(a[i], (0,width-len(a[i])), 'constant',constant_values = 0)
    else:
        x = a[i]
    b.append(x)
b = np.array(b)
print(b)

上面的一段代码输出了这样的东西。

b = [[1, 2, 3, 4, 5],
     [1, 2, 3, 0, 0],
     [1, 0, 0, 0, 0]]

您可以通过执行以下操作来读回数据的输入版本

a = []
for i in range(len(b)):
    a.append(b[i][0:l[i]])
a = np.array(a)
print(a)

在这里你可以得到下面的输出

a = array([array([1, 2, 3, 4, 5]), array([1, 2, 3]), array([1])], dtype=object)

希望这能帮助像我一样挣扎的人解决这个问题。谢谢大家。

x7rlezfr

x7rlezfr3#

import tensorflow as tf

a = [[1,2,3,4,5],[1,2,3],[1]]
x = tf.keras.utils.pad_sequences(a, padding='post')
print(f"{type(x)}\n{x}")
-----
<class 'numpy.ndarray'>
[[1 2 3 4 5]
 [1 2 3 0 0]
 [1 0 0 0 0]]
import awkward as ak

a = [[1,2,3,4,5],[1,2,3],[1]]
ak.fill_none(ak.pad_none(a, 5, axis=-1), 0).to_numpy()
-----
array([[1, 2, 3, 4, 5],
       [1, 2, 3, 0, 0],
       [1, 0, 0, 0, 0]])

相关问题