【发布时间】:2014-04-18 14:39:53
【问题描述】:
我正在阅读 ascii 和二进制文件,它们都以 fortran 顺序指定 3 维数组。我想对这些数组执行一些任意操作,然后将它们导出为相同的 ascii 或二进制格式。
我对在我的库中处理这些数组的最佳方法感到困惑。我目前的设计似乎很容易出错,因为如果创建了任何新数组,我必须不断地从默认的 C 顺序重新调整。
当前设计:
我有一些函数可以读取这些文件并返回 numpy 数组。读取函数的行为方式都类似,本质上是读取数据并返回如下内容:
return array.reshape((i, j, k), order='F')
按照我的理解,我将 fortran 顺序的视图返回到原始数组中。
我的代码假定所有数组都按 fortran 顺序排列。这意味着任何可能创建新数组的新操作我确保使用 reshape 将其转换回 fortran 顺序。
这似乎很容易出错,因为我必须密切注意任何创建新数组的操作,并确保将其重塑为 fortran 顺序,因为默认值通常是 C 顺序。
我稍后可能不得不再次将这些数组导出为二进制或 ascii,并且需要维护 fortran 排序。所以,我使用numpy.nditer 以fortran 顺序写出每个元素。
担忧:
-
目前的方法似乎很容易出错,因为我通常按 C 顺序思考。恐怕我总是会因为错过对
reshape的调用而被咬伤,这会迫使事情按 C 顺序进行。- 我希望不必担心数组元素的顺序,除非在读取输入文件或将数据写入输出文件时。
-
当前的方法看起来很混乱,因为索引可以以不同的方式解释,事情可能会变得混乱。
- 在处理 fortran 数组时,索引的元组顺序是向后的,对吗?
- 那么,
x[(1, 2, 3)]对于 fortran 数组意味着 k = 1、j = 2 和 i = 3,而对于 C 阶数组,x[(1, 2, 3)]意味着 k = 3、j = 2、i = 1 正确吗?李> - 这意味着我和我的库的用户必须始终以 (k, j, i) 顺序考虑索引,而不是我们 C/Python 程序员通常认为的 (i, j, k)。
问题:
有没有做这种事情的最佳实践?在一个理想的世界中,我想读取 fortran 有序数组,然后在导出到文件之前忘记排序。但是,恐怕我会一直误解索引等。
我已经阅读了我能找到的唯一 numpy 文档,http://docs.scipy.org/doc/numpy/reference/internals.html#multidimensional-array-indexing-order-issues。然而,这个概念对我来说仍然像泥巴一样清晰。也许我只是需要对 numpy 文档的不同解释,http://docs.scipy.org/doc/numpy/reference/internals.html#multidimensional-array-indexing-order-issues。
【问题讨论】:
-
你想多了。我会详细说明,但您基本上只需要在读取或写入磁盘时担心 C 与 F 的顺序。 (提示:写作,使用
x.ravel(order='F').tofile(...))Numpy 将其余部分抽象出来。除非您将事物来回传递给较低级别的函数,否则无需注意 python 端的 C 与 F 排序。在 python 方面,您将数组索引为x[i,j,k]无论如何(除非您错误地读取它)。 -
@JoeKington 我在尝试索引时不必担心数组的顺序吗?例如,如果我想获得 i = 0, j = 2, k = 10 的元素,那么我应该对 C 有序数组使用 (0, 2, 10) 对 Fortran 有序数组使用 (10, 2, 0)大批?因此,我需要向库的用户指定从将数据读入 numpy 数组的函数返回的内容,对吗?我试图让所有数组都以相同的方式排序,这样用户就不会考虑这一点,而是总是使用 (i, j, k) 或 (k, j, i)。这样所有数组都是一致的。
-
不!无论如何,您将在 python 中将其索引为
[0,2,10]。 Numpy 抽象出 C 与 Fortran 在内存中的排序。如果你不能这样做,那是因为你没有正确读入数组(即你读入它就像是 C 排序的一样)。修复它的最简单方法是执行x = x.T。 -
不幸的是,我可能需要一点时间才能发布完整的答案(无论如何,我真的不应该在工作中偷懒。)希望有人在平均时间!
-
在 python 方面,是的。如果您必须使用反向索引,那是因为您在读入数组并最初对其进行整形时将其视为 C 顺序。如果阵列是在磁盘上按 fortran 排序的,那么您将执行
np.fromfile('blah', dtype=whatever).reshape(nx,ny,nz, order='F')将其读入并将其写回磁盘,您将执行data.ravel(order='F').tofile(blah)。 (所有这些都假设您正在将原始二进制数组写入磁盘,但同样的想法适用于 ascii。)如果您正确执行此操作,您将在 python 端以与 C 排序相同的方式对其进行索引。