Python:如何将矩阵索引更改为笛卡尔索引?

huangapple go评论62阅读模式
英文:

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] = 7matrix[1,2] = 6matrix[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]]

我们将把这个矩阵的索引表示为 ij。同时,我们将把 xy 表示为我们的笛卡尔索引。您想要的是从 (x, y)(i, j) 的映射。例如,从 (2, 1) 到矩阵索引 (0, 4)

最后引入的变量是 i_originj_origin。这些变量是平面 (0, 0) 的笛卡尔原点的 ij。我们可以使用 i_origin = matrix.shape[0] // 2j_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 the ndarray. 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.

huangapple
  • 本文由 发表于 2023年5月11日 17:57:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76226371.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定