【问题标题】:NumPy slicing over variable size, multidimensional arrayNumPy 对可变大小、多维数组进行切片
【发布时间】:2020-03-23 11:55:05
【问题描述】:

假设有以下几行代码

import numpy as np

# The values equal to 1 inside this nested list indicate where the data need to be loaded. a = [7 x 6]
a = [
    [0, 1, 0, 1, None, None],
    [0, 0, 0, 0, None, 0],
    [0, 0, 1, 0, None, 0],
    [0, 1, 0, 1, None, 1],
    [0, 0, 0, 1, None, 0],
    [0, 0, 0, 0, None, 0],
    [1, 0, 0, 0, None, None]
]
# The list "a" cannot be modified for a number of reasons, so I create a np.array copy, named "b"
b = np.array(a)

N = int(1E7)  # Number of samples

# The loop below retrieves the positions inside "b" in which data need to be loaded
row = []
col = []
for i in range(len(b)):
    col.append([])
    if any(b[i] == 1):
        row.append(i)
    for j in range(len(a[i])):
        if b[i][j] is 1:
            b[i][j] = np.zeros((N, 1))
            col[i].append(j)


# Loading the data inside the selected positions of "b". "mydata" is a numpy array, whose shape is (N, 6)
for i in row:
    mydata = np.random.randn(N, len(a[0])).reshape(N, len(a[0])) # Generation of dummy data
    b[i, col[i]] = mydata[:, col[i]]  # This instruction returns a ValueError

但是,我收到以下错误: ValueError:形状不匹配:形状(10000000,2)的值数组无法广播到形状(2,)的索引结果

为什么这种切片不能正常工作?是不是因为"b"里面的数组元素大小可变?

提前谢谢你。

【问题讨论】:

  • 我在这里试图实现的主要目标是在数据加载过程中避免在for i in row之后出现第二个循环for j in col[i],只是为了提高效率

标签: python arrays list numpy numpy-slicing


【解决方案1】:

对于由于使用b[i, col[i]]而在行中插入多个零数组的情况,切片无法正常工作。

只需考虑您的第一行。这给了你row=[0]col =[[1,3]]。这意味着b[0,0] 引用了第 1 列 3 的 zeros 数组。您应该像以前一样使用嵌套的 for 循环遍历行和列

for i in row:
    for j in col[i]:
        mydata = np.random.randn(N, len(a[0])).reshape(N, len(a[0]))
        b[i, j] = mydata[:, col[i]]

【讨论】:

  • 嵌套循环的引入正是我为了提高效率而想要避免的,因为在实际场景中,“for j in col[i]”循环将运行数万次.有没有其他方法可以解决这个问题?
  • 问一个天真的问题:为什么不在循环通过b 之前初始化mydata 并直接将mydata 中的值分配给带有1 的任何位置,而不用打扰行和列列表和零数组?这会降低效率吗?
  • 我生成了一些虚拟数据只是为了简化讨论,但在实际场景中,我必须从数千个不同的 .h5 文件中提取此类数据。每个 .h5 文件包含大约 6000 个样本,并对应于嵌套列表 a 的给定行:因此我必须在 b 中加载与 a 中等于 1 的位置对应的数据部分>
【解决方案2】:

让我们将N 简化为合理的值,并添加一些打印:

print(row)
print(col)
print(a)
print(b)

跑步:

0942:~/mypy$ python3 stack60813103.py 
[0, 2, 3, 4, 6]
[[1, 3], [], [2], [1, 3, 5], [3], [], [0]]
[[0, 1, 0, 1, None, None], [0, 0, 0, 0, None, 0], [0, 0, 1, 0, None, 0], [0, 1, 0, 1, None, 1], [0, 0, 0, 1, None, 0], [0, 0, 0, 0, None, 0], [1, 0, 0, 0, None, None]]
[[0 array([[0.],
       [0.],
       [0.],
       [0.],
       [0.]]) 0
  array([[0.],
       [0.],
       [0.],
       [0.],
       [0.]]) None
  None]
 [0 0 0 0 None 0]
 [0 0 array([[0.],
       [0.],
       [0.],
       [0.],
       [0.]]) 0
  None 0]
 ....
 [0 0 0 0 None 0]
 [array([[0.],
       [0.],
       [0.],
       [0.],
       [0.]]) 0 0 0
  None None]]
Traceback (most recent call last):
  File "stack60813103.py", line 38, in <module>
    b[i, col[i]] = mydata[:, col[i]]  # This instruction returns a ValueError
ValueError: shape mismatch: value array of shape (5,2) could not be broadcast to indexing result of shape (2,)

rowcola 是列表,b 是对象 dtype 数组(因为所有 None)。您的循环插入了一堆 np.zeros((N,1)) 数组。

mydata 是一个 (N,5) 浮点数组。

col[0][1, 3] 时,mydata[:, col[i]] 将是 (N,2);对于其他i,它可以是 (N,0) 或 (N,1), (N,3)。

b[i, col[i]] 是 (2,)(或 (0,),(1,),(3,))。形状有相当明显的不匹配。不能将位 (N,2) 数组放入 (2,) 槽中。

你为什么要这样构造一个数组? None、数字和具有 (N,1) 和 (N,2) 等形状的数组的混合?


我认为你需要添加一个迭代:

for j in col[i]:
    b[i, j] = mydata[:, j]

这应该将 (N,) 数组分配给 bb[i,j] 元素。

【讨论】:

  • 为了提供额外的上下文,a 列表中的值对应于用户在 GUI 中选择的按钮。当a[i][j] = 0时,用户没有选择给定的“频道”;当a[i][j] = 1时,频道已被选中; a[i][j] = None 相反,对应于无法按下的禁用按钮。由于我正在处理相对较大的数据 (N &gt; 1E7),因此我无法创建一个巨大的零矩阵,因为它会导致内存分配过多。另外,我还需要将a中配置的具体安排保存在b中以备后用
  • 请记住,对象 dtype 数组本质上是列表。元素是对象。将对象 dtype 数组视为 2d(与嵌套列表相反)更容易一些,但列表上的迭代更快。快速numpy 数学不可用。请参阅我的编辑以解决此分配错误。
  • 好的,所以我接受了第二个for 循环:for j in col[i],没有其他办法。无论如何,非常感谢您的建议,然后我将创建 b 作为新列表,而不是 np.array
猜你喜欢
  • 1970-01-01
  • 2018-11-07
  • 2019-03-25
  • 2021-11-23
  • 2013-06-21
  • 2016-02-20
  • 2015-10-15
  • 1970-01-01
相关资源
最近更新 更多