修改numpy切片对象的简单方法?

时间:2017-05-12 06:50:03

标签: python numpy slice

如果我有一个像对象定义的切片对象:s = np.s_[10:20, 30:40],有没有简单的方法对这个对象进行基本的操作/操作,而不必手动访问s[0][0]等...创建新切片?

示例:是否有一个神奇的功能可以将切片移动(x,y)以获得shifted(s, x, y) = np.s_[10+x:20+x, 30+y:40+y],或者我是否必须创建自己的函数来执行所有这些基本操作?

3 个答案:

答案 0 :(得分:3)

In [319]: s=np.s_[10:20, 30:40]
In [320]: s
Out[320]: (slice(10, 20, None), slice(30, 40, None))

因此结果是一个包含2个slice个对象的元组。

In [322]: s[0].start
Out[322]: 10
In [324]: s[0].start=20
...
AttributeError: readonly attribute

因此可以创建slice,但不能更改属性。但这没什么大不了的。创建切片并不昂贵。它不是一个大数组或列表。它只是一个具有几个属性的简单对象。

要将其展开为数组,请使用np.r_

之类的内容
In [325]: np.r_[s]
Out[325]: 
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39])

或者s元组可用于索引数组:

In [328]: arr = np.arange(30*50).reshape(30,50)
In [329]: arr[s]
Out[329]: 
array([[530, 531, 532, 533, 534, 535, 536, 537, 538, 539],
       [580, 581, 582, 583, 584, 585, 586, 587, 588, 589],
       [630, 631, 632, 633, 634, 635, 636, 637, 638, 639],
       [680, 681, 682, 683, 684, 685, 686, 687, 688, 689],
       [730, 731, 732, 733, 734, 735, 736, 737, 738, 739],
       [780, 781, 782, 783, 784, 785, 786, 787, 788, 789],
       [830, 831, 832, 833, 834, 835, 836, 837, 838, 839],
       [880, 881, 882, 883, 884, 885, 886, 887, 888, 889],
       [930, 931, 932, 933, 934, 935, 936, 937, 938, 939],
       [980, 981, 982, 983, 984, 985, 986, 987, 988, 989]])

arr[10:20, 30:40]相同,是arr的视图。您无法修改视图(范围),但您当然可以使用新切片创建新视图。

index_tricks.py

来自np.s_

np.lib.index_tricks.py代码
class IndexExpression(object):
    """
    A nicer way to build up index tuples for arrays.
    ...
    """

    def __init__(self, maketuple):
        self.maketuple = maketuple

    def __getitem__(self, item):
        if self.maketuple and not isinstance(item, tuple):
            return (item,)
        else:
            return item

index_exp = IndexExpression(maketuple=True)
s_ = IndexExpression(maketuple=False)

基本上它只是捕获Python解释器在看到x[0:3, :]之类的代码时生成的元组的一种方式。它会将其转换为x.__getitem__(atuple)

In [334]: np.s_[:,3:3,[1,2,3]]
Out[334]: (slice(None, None, None), slice(3, 3, None), [1, 2, 3])

逗号分隔元组元素,n:m:i字符串转换为slice个对象。这个纯Python; numpy没什么特别的。除了大多数标准的Python类列表都不能使用元组索引。

In [336]: list(range(10))[np.s_[2:5]]
Out[336]: [2, 3, 4]

在同一个index_tricks文件中,查看类AxisConcatenatornd_grid,以便对key的{​​{1}}参数进行更复杂的处理。

答案 1 :(得分:1)

python slice对象没有关联的方法,而numpy似乎只是在不修改的情况下重用该类(尽管有一个新的构造函数s_)。所以,似乎答案是肯定的。

如果你真的想要使用切片,你需要编写自己的函数:

def shifted(s, x, y):
    return np.s_[s[0].start + x: s[0].stop + x, s[1].start + y: s[1].stop + y]

然后你可以重新分配:

 s = shifted(s, x, y)

或者您可以创建slice的子类并将其实现为该类的方法。

答案 2 :(得分:0)

您可以只使用坐标网格来代替使用切片:

s = tuple(np.mgrid[10:20, 30:40])

s可以像slice一样被调用,但像array一样被操纵

arr[s]   # using hpaulj's test data
Out[]: 
array([[530, 531, 532, 533, 534, 535, 536, 537, 538, 539],
       [580, 581, 582, 583, 584, 585, 586, 587, 588, 589],
       [630, 631, 632, 633, 634, 635, 636, 637, 638, 639],
       [680, 681, 682, 683, 684, 685, 686, 687, 688, 689],
       [730, 731, 732, 733, 734, 735, 736, 737, 738, 739],
       [780, 781, 782, 783, 784, 785, 786, 787, 788, 789],
       [830, 831, 832, 833, 834, 835, 836, 837, 838, 839],
       [880, 881, 882, 883, 884, 885, 886, 887, 888, 889],
       [930, 931, 932, 933, 934, 935, 936, 937, 938, 939],
       [980, 981, 982, 983, 984, 985, 986, 987, 988, 989]])

def shifted(s, x, y):
    return (s[0] + x, s[1] + y)

arr[shifted(s,10,10)]
Out[]: 
array([[1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049],
       [1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099],
       [1140, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 1148, 1149],
       [1190, 1191, 1192, 1193, 1194, 1195, 1196, 1197, 1198, 1199],
       [1240, 1241, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249],
       [1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299],
       [1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347, 1348, 1349],
       [1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399],
       [1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449],
       [1490, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 1498, 1499]])

请注意,这会比切片占用更多内存