不同行大小的数字填充矩阵

2022-04-08 00:00:00 python numpy arrays padding rows

问题描述

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

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所示,但我需要使用更大的数据数组来做到这一点。

如果有人能帮我回答这个问题,我会很高兴知道的。


解决方案

实际上没有办法填充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('
'.join(map(str,s)))
# 7.838103920221329e-05
# 0.0005027339793741703
# 0.01208890089765191
# 0.8269036808051169

如果您想要在数组前面加上零,而不是追加,这是对代码的简单更改,我将把它留给您。

相关文章