Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc6e1fd0

Browse files
authored
API: Add .mT attribute for arrays (#23762)
This adds the `.mT` attribute to arrays and specific implementation for masked arrays.
1 parent9cba469 commitc6e1fd0

File tree

10 files changed

+189
-0
lines changed

10 files changed

+189
-0
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Matrix transpose support for ndarrays
2+
-------------------------------------
3+
NumPy now offers support for calculating the matrix transpose of an array. The
4+
matrix transpose is equivalent to swapping the last two axes of an array.
5+
`np.ndarray` and `np.ma.MaskedArray` now exposes a `.mT` attribute.

‎numpy/__init__.pyi‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,8 @@ class _ArrayOrScalarCommon:
992992
@property
993993
defT(self:_ArraySelf)->_ArraySelf: ...
994994
@property
995+
defmT(self:_ArraySelf)->_ArraySelf: ...
996+
@property
995997
defdata(self)->memoryview: ...
996998
@property
997999
defflags(self)->flagsobj: ...

‎numpy/core/_add_newdocs.py‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2877,6 +2877,45 @@
28772877
"""))
28782878

28792879

2880+
add_newdoc('numpy.core.multiarray','ndarray', ('mT',
2881+
"""
2882+
View of the matrix transposed array.
2883+
2884+
The matrix transpose is the transpose of the last two dimensions, even
2885+
if the array is of higher dimension.
2886+
2887+
.. versionadded:: 2.0
2888+
2889+
Raises
2890+
------
2891+
ValueError
2892+
If the array is of dimension less than 2.
2893+
2894+
Examples
2895+
--------
2896+
>>> a = np.array([[1, 2], [3, 4]])
2897+
>>> a
2898+
array([[1, 2],
2899+
[3, 4]])
2900+
>>> a.mT
2901+
array([[1, 3],
2902+
[2, 4]])
2903+
2904+
>>> a = np.arange(8).reshape((2, 2, 2))
2905+
>>> a
2906+
array([[[0, 1],
2907+
[2, 3]],
2908+
2909+
[[4, 5],
2910+
[6, 7]]])
2911+
>>> a.mT
2912+
array([[[0, 2],
2913+
[1, 3]],
2914+
2915+
[[4, 6],
2916+
[5, 7]]])
2917+
2918+
"""))
28802919
##############################################################################
28812920
#
28822921
# ndarray methods

‎numpy/core/src/multiarray/getset.c‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include"mem_overlap.h"
2323
#include"alloc.h"
2424
#include"npy_buffer.h"
25+
#include"shape.h"
2526

2627
/******************* array attribute get and set routines ******************/
2728

@@ -931,6 +932,12 @@ array_transpose_get(PyArrayObject *self, void *NPY_UNUSED(ignored))
931932
returnPyArray_Transpose(self,NULL);
932933
}
933934

935+
staticPyObject*
936+
array_matrix_transpose_get(PyArrayObject*self,void*NPY_UNUSED(ignored))
937+
{
938+
returnPyArray_MatrixTranspose(self);
939+
}
940+
934941
NPY_NO_EXPORTPyGetSetDefarray_getsetlist[]= {
935942
{"ndim",
936943
(getter)array_ndim_get,
@@ -992,6 +999,10 @@ NPY_NO_EXPORT PyGetSetDef array_getsetlist[] = {
992999
(getter)array_transpose_get,
9931000
NULL,
9941001
NULL,NULL},
1002+
{"mT",
1003+
(getter)array_matrix_transpose_get,
1004+
NULL,
1005+
NULL,NULL},
9951006
{"__array_interface__",
9961007
(getter)array_interface_get,
9971008
NULL,

‎numpy/core/src/multiarray/shape.c‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,22 @@ PyArray_Transpose(PyArrayObject *ap, PyArray_Dims *permute)
731731
return (PyObject*)ret;
732732
}
733733

734+
/*
735+
* Return matrix transpose (swap last two dimensions).
736+
*/
737+
NPY_NO_EXPORTPyObject*
738+
PyArray_MatrixTranspose(PyArrayObject*ap)
739+
{
740+
intndim=PyArray_NDIM(ap);
741+
742+
if (ndim<2) {
743+
PyErr_SetString(PyExc_ValueError,
744+
"matrix transpose with ndim < 2 is undefined");
745+
returnNULL;
746+
}
747+
returnPyArray_SwapAxes(ap,ndim-2,ndim-1);
748+
}
749+
734750
/*
735751
* Sorts items so stride is descending, because C-order
736752
* is the default in the face of ambiguity.

‎numpy/core/src/multiarray/shape.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,10 @@ PyArray_CreateMultiSortedStridePerm(int narrays, PyArrayObject **arrays,
2121
NPY_NO_EXPORTPyObject*
2222
PyArray_SqueezeSelected(PyArrayObject*self,npy_bool*axis_flags);
2323

24+
/*
25+
* Return matrix transpose (swap last two dimensions).
26+
*/
27+
NPY_NO_EXPORTPyObject*
28+
PyArray_MatrixTranspose(PyArrayObject*ap);
29+
2430
#endif/* NUMPY_CORE_SRC_MULTIARRAY_SHAPE_H_ */
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
importpytest
2+
3+
importnumpyasnp
4+
fromnumpy.testingimportassert_array_equal
5+
6+
7+
deftest_matrix_transpose_raises_error_for_1d():
8+
msg="matrix transpose with ndim < 2 is undefined"
9+
arr=np.arange(48)
10+
withpytest.raises(ValueError,match=msg):
11+
arr.mT
12+
13+
14+
deftest_matrix_transpose_equals_transpose_2d():
15+
arr=np.arange(48).reshape((6,8))
16+
assert_array_equal(arr.T,arr.mT)
17+
18+
19+
ARRAY_SHAPES_TO_TEST= (
20+
(5,2),
21+
(5,2,3),
22+
(5,2,3,4),
23+
)
24+
25+
26+
@pytest.mark.parametrize("shape",ARRAY_SHAPES_TO_TEST)
27+
deftest_matrix_transpose_equals_swapaxes(shape):
28+
num_of_axes=len(shape)
29+
vec=np.arange(shape[-1])
30+
arr=np.broadcast_to(vec,shape)
31+
tgt=np.swapaxes(arr,num_of_axes-2,num_of_axes-1)
32+
mT=arr.mT
33+
assert_array_equal(tgt,mT)

‎numpy/ma/core.py‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6092,6 +6092,41 @@ def take(self, indices, axis=None, out=None, mode='raise'):
60926092
T=property(fget=lambdaself:self.transpose())
60936093
transpose=_arraymethod('transpose')
60946094

6095+
@property
6096+
defmT(self):
6097+
"""
6098+
Return the matrix-transpose of the masked array.
6099+
6100+
The matrix transpose is the transpose of the last two dimensions, even
6101+
if the array is of higher dimension.
6102+
6103+
.. versionadded:: 2.0
6104+
6105+
Returns
6106+
-------
6107+
result: MaskedArray
6108+
The masked array with the last two dimensions transposed
6109+
6110+
Raises
6111+
------
6112+
ValueError
6113+
If the array is of dimension less than 2.
6114+
6115+
See Also
6116+
--------
6117+
ndarray.mT:
6118+
Equivalent method for arrays
6119+
"""
6120+
6121+
ifself.ndim<2:
6122+
raiseValueError("matrix transpose with ndim < 2 is undefined")
6123+
6124+
ifself._maskisnomask:
6125+
returnmasked_array(data=self._data.mT)
6126+
else:
6127+
returnmasked_array(data=self.data.mT,mask=self.mask.mT)
6128+
6129+
60956130
deftolist(self,fill_value=None):
60966131
"""
60976132
Return the data portion of the masked array as a hierarchical Python list.

‎numpy/ma/core.pyi‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,8 @@ class MaskedArray(ndarray[_ShapeType, _DType_co]):
293293
swapaxes:Any
294294
T:Any
295295
transpose:Any
296+
@property# type: ignore[misc]
297+
defmT(self): ...
296298
deftolist(self,fill_value=...): ...
297299
deftobytes(self,fill_value=...,order=...): ...
298300
deftofile(self,fid,sep=...,format=...): ...

‎numpy/ma/tests/test_arrayobject.py‎

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
importpytest
2+
3+
importnumpyasnp
4+
fromnumpy.maimportmasked_array
5+
fromnumpy.testingimportassert_array_equal
6+
7+
8+
deftest_matrix_transpose_raises_error_for_1d():
9+
msg="matrix transpose with ndim < 2 is undefined"
10+
ma_arr=masked_array(data=[1,2,3,4,5,6],
11+
mask=[1,0,1,1,1,0])
12+
withpytest.raises(ValueError,match=msg):
13+
ma_arr.mT
14+
15+
16+
deftest_matrix_transpose_equals_transpose_2d():
17+
ma_arr=masked_array(data=[[1,2,3], [4,5,6]],
18+
mask=[[1,0,1], [1,1,0]])
19+
assert_array_equal(ma_arr.T,ma_arr.mT)
20+
21+
22+
ARRAY_SHAPES_TO_TEST= (
23+
(5,2),
24+
(5,2,3),
25+
(5,2,3,4),
26+
)
27+
28+
29+
@pytest.mark.parametrize("shape",ARRAY_SHAPES_TO_TEST)
30+
deftest_matrix_transpose_equals_swapaxes(shape):
31+
num_of_axes=len(shape)
32+
vec=np.arange(shape[-1])
33+
arr=np.broadcast_to(vec,shape)
34+
35+
rng=np.random.default_rng(42)
36+
mask=rng.choice([0,1],size=shape)
37+
ma_arr=masked_array(data=arr,mask=mask)
38+
39+
tgt=np.swapaxes(arr,num_of_axes-2,num_of_axes-1)
40+
assert_array_equal(tgt,ma_arr.mT)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp