英文:
Python: How to change matrix indexing to cartesian indexing?
问题
我有一个矩阵
import numpy as np
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
我想在笛卡尔坐标上表示一个离散的二维物理空间。例如,当访问数值时,我想要得到 matrix[0,0] = 7
, matrix[1,2] = 6
, matrix[2,2] = 3
。我该如何实现?我尝试使用 np.meshgrid
,但据我所知,我实现的结果并不是我想要的。通过每次访问数值时转置矩阵可以实现我想要的效果,但我希望直接改变矩阵的索引方式。谢谢!
英文:
I have a matrix
import numpy as np
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
And I want to represent a discrete 2D physical space on cartesian coordinates with it. So for example, when accessing the values I'd get matrix[0,0] = 7
, matrix[1,2] = 6
, matrix[3,3] = 3
.
How can I accomplish that? I have tried using np.meshgrid
, but as far as I have managed to implement it, the results are not what I am looking for. What I'm looking for could be accomplished by transposing the matrix every time I try to access a value, but I would like a way to just change the indexing of the matrix directly.
Thanks!
答案1
得分: 1
你可以使用np.flip
来查看矩阵的反转视图:
vmatrix = np.flip(matrix, axis=0)
print(vmatrix)
# 输出
array([[7, 8, 9],
[4, 5, 6],
[1, 2, 3]])
用法:
>>> vmatrix[0, 0]
7
>>> vmatrix[1, 2]
6
>>> vmatrix[2, 2]
3
你也可以使用np.pad
:
vmatrix = np.pad(np.flip(matrix, axis=0), [[1, 0], [1, 0]])
print(vmatrix)
# 输出
[[0 0 0 0]
[0 7 8 9]
[0 4 5 6]
[0 1 2 3]]
用法:
>>> vmatrix[1, 1]
7
>>> vmatrix[2, 3]
6
>>> vmatrix[3, 3]
3
你还可以子类化 ndarray 并覆盖 __getitem__
和 __setitem__
方法。
英文:
You can use a view of your matrix with np.flip
:
vmatrix = np.flip(matrix, axis=0)
print(vmatrix)
# Output
array([[7, 8, 9],
[4, 5, 6],
[1, 2, 3]])
Usage:
>>> vmatrix[0, 0]
7
>>> vmatrix[1, 2]
6
>>> vmatrix[2, 2]
3
You can also use np.pad
:
vmatrix = np.pad(np.flip(matrix, axis=0), [[1, 0], [1, 0]])
print(vmatrix)
# Output
[[0 0 0 0]
[0 7 8 9]
[0 4 5 6]
[0 1 2 3]]
Usage:
>>> vmatrix[1, 1]
7
>>> vmatrix[2, 3]
6
>>> vmatrix[3, 3]
3
You can also Subclassing ndarray and override __getitem__
and __setitem__
methods.
答案2
得分: 0
关于numpy.ndarray.__getitem__
不可写的事实,建议以其他方式访问值。
numpy.flip
函数可用于沿指定轴翻转或反转数组中的元素顺序。这在各种数据处理和分析任务中都很有用,如图像处理、信号处理和数据操作。
对于我之前不正确的回答,我向您道歉。解决此问题的最佳方法是使用numpy.flip
函数。
英文:
In regards to the fact that numpy.ndarray.__getitem__
is not writable, it is recommended to access the values in another way.
The numpy.flip
function can be used to flip or reverse the order of elements in an array along a specified axis. This can be useful in various data processing and analysis tasks, such as image processing, signal processing, and data manipulation.
I would like to apologize to you for my previous incorrect response. The most optimal solution for this problem is to utilize the numpy.flip function.
答案3
得分: 0
Here is the translated content:
我将为您提供解决方案。尽管我会解释为什么这种方法非常笨拙,并且会在您的实验中引发问题,但我建议查看meshgrid。这里有一个简单的示例,展示了如何在二维笛卡尔平面上使用meshgrid进行计算。我认为这是标准和直接的方法,因此是执行此操作的首选方式。
解决方案
首先,我将介绍一些变量。要表示笛卡尔平面的矩阵,其中 x_values = np.arange(-2, 2+1)
,y_values = np.arrange(-1, 1+1)
:
matrix = np.array[
[1, 1, 0, 2, 2],
[0, 0, 0, 0, 0],
[3, 3, 0, 4, 4]]
我们将把这个矩阵的索引表示为 i
和 j
。同时,我们将把 x
和 y
表示为我们的笛卡尔索引。您想要的是从 (x, y)
到 (i, j)
的映射。例如,从 (2, 1)
到矩阵索引 (0, 4)
。
最后引入的变量是 i_origin
和 j_origin
。这些变量是平面 (0, 0)
的笛卡尔原点的 i
和 j
。我们可以使用 i_origin = matrix.shape[0] // 2
和 j_origin = matrix.shape[1] // 2
来计算它们。我们将使用 i_origin
作为线的索引的偏移量 - 垂直方向 - 也就是 y
,并使用 j_origin
作为 x
的偏移量。
如果您拿出一支铅笔和一张纸,我认为我们可以同意以下关系:
i = i_origin - y
j = j_origin + x
因此,我们可以编写这两个简短的函数:
def map_to_i(i_origin: int, y: int) -> int:
return i_origin - y
def map_to_j(j_origin: int, x: int) -> int:
return j_origin + x
如果您愿意,我们甚至可以编写一个函数来获得 (i, j) 的元组:
def map_to_matrix_indices(i_origin: int, j_origin: int, x: int, y: int) -> tuple[int, int]:
return map_to_i(i_origin, y), map_to_j(j_origin, x)
然后我们可以简单地写成:
>>> matrix[map_to_matrix_indices(i_origin, j_origin, 2, 1)]
2
问题
好吧,我们可以说我们有了解决方案,但这种方法带来了一堆问题:
- 访问/设置值的接口不是标准的。因此,它可能无法与库很好地配合使用。此外,您失去了numpy的一部分广播功能。
- 解决此问题的一种方法是实现一个名为
CartesianMatrix
的类,并将我们的函数放在其方法中。您可以继承或组合它以自ndarray。这可能是可行的,但需要额外的工作。(注意:实际上这是一个有趣的做法) - 如此编写,它无法推广到更多的维度。我认为它可以很容易地形式化。
总之,您必须将新类的接口设置为与ndarray相同,以避免出现问题。否则,您将不得不针对遇到的每个问题找到解决方法,因为您不能按照标准方式访问/设置索引。
注意:对象的接口是对象必须的行为方式。
英文:
I will provide a solution to your problem. Although I will explain why the approach is very clunky and will lead to problem later in your experiments. I would advise to look at meshgrid for this. Here is a simple example how to perform computation on a 2D cartesian plane with meshgrid. I think this the standard and straightforward way, therefore the privilegied way to do that.
The solution
Before, I will introduce some variables. The matrix which is meant to represent the cartesian plane between x_values = np.arange(-2, 2+1)
, y_values = np.arrange(-1, 1+1)
:
matrix = np.array[
[ 1, 1, 0, 2, 2],
[ 0, 0, 0, 0, 0],
[ 3, 3, 0, 4, 4]]
We will denote the indices of this matrix as i
and j
. Also we will note x
and y
as our cartesian indices. What you want is a mapping from (x, y)
to (i, j)
. For example from (2, 1)
you want the top left value with matrix indices (0, 4)
.
The last introduced variable are i_origin
and j_origin
. Those variables are the i
and j
for the cartesian origin of the plane (0, 0)
. We can do i_origin = matrix.shape[0] // 2
and j_origin = matrix.shape[1] // 2
. We wil use i_origin
as an offset for the lines' indices - vertical - so for y
and j_origin
for x
If you take a pencil and a paper I think we can agree that:
i = i_origin - y
j = j_origin + x
So, we can write the two short functions:
def map_to_i(i_origin: int, y: int) -> int:
return i_origin - y
def map_to_j(j_origin: int, x: int) -> int:
return j_origin - x
If you want, we can even make a function to have a tuple of (i, j):
def map_to_matrix_indices(i_origin: int, j_origin: int, x: int, y: int) -> tuple[int, int]:
return map_to_i(i_origin, y), map_to_j(j_origin, x)
The we can simply write:
>>> matrix[map_to_matrix_indices(i_origin, j_origin, 2, 1)]
2
Problems
Well, we can say we have your solution, but this approach brings a bunch of problems:
- The interface of accessing/setting your values is not standard. As such, it might not work well with libraries. Plus, you lose a part of the broadcasting from numpy.
- One way to get around this would be to implement a class
CartesianMatrix
- for example - and put our functions in its method. You can inherit from or composed it from thendarray
. It might be feasible but needs additional work. (Note: it would be interesting to do actually) - Written as such, it cannot be generalized for more dimension. I do think it can be easily formalized.
In general, you must set the interface of your new class the same as ndarray to have no problem. Else, you will have to find a workaround for every problem you encounter because you do not access/set indices by the standard way.
Note: interface of an object is how an object must behave.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论