<p>为了回答这个问题,我们必须看看如何在Numpy中索引多维数组。首先假设你的问题中有数组<code>x</code>。分配给<code>x</code>的缓冲区将包含16个从0到15的升序整数。如果您访问一个元素,比如<code>x[i,j]</code>,NumPy必须找出这个元素相对于缓冲区开头的内存位置。这是通过计算实际的<code>i*x.shape[1]+j</code>(并与int的大小相乘以获得实际的内存偏移量)来完成的。</p>
<p>如果通过基本切片(如<code>y = x[0:2,0:2]</code>)提取子数组,则结果对象将与<code>x</code>共享底层缓冲区。但是,如果您访问<code>y[i,j]</code>,会发生什么?NumPy不能使用<code>i*y.shape[1]+j</code>来计算数组的偏移量,因为属于<code>y</code>的数据在内存中不是连续的。</p>
<p>NumPy通过引入<em>跨步</em>来解决这个问题。在计算访问<code>x[i,j]</code>的内存偏移量时,实际计算的是<code>i*x.strides[0]+j*x.strides[1]</code>(这已经包括int大小的因子):</p>
<pre><code>x.strides
(16, 4)
</code></pre>
<p>当如上所述提取<code>y</code>时,NumPy不会创建一个新的缓冲区,但它会创建一个引用同一缓冲区的新数组对象(否则<code>y</code>将只等于<code>x</code>)。新数组对象将具有不同的形状,然后<code>x</code>,可能会有不同的缓冲区起始偏移量,但将与<code>x</code>共享这些进展(在本例中至少是这样):</p>
<pre><code>y.shape
(2,2)
y.strides
(16, 4)
</code></pre>
<p>这样,计算<code>y[i,j]</code>的内存偏移量将得到正确的结果。</p>
<p>但是对于像<code>z=x[[1,3]]</code>这样的事情,NumPy应该怎么做呢?如果原始缓冲区用于<code>z</code>,那么spinds机制将不允许正确的索引。从理论上讲,NumPy可以添加一些比streams更复杂的机制,但这会使元素访问相对昂贵,在某种程度上违背了数组的整体思想。此外,视图不再是真正的轻量级对象。</p>
<p>这在<a href="http://docs.scipy.org/doc/numpy-1.5.x/reference/arrays.indexing.html" rel="noreferrer">the NumPy documentation on indexing</a>中有详细介绍。</p>
<p>哦,差点忘了你的实际问题:下面是如何使多个列表的索引按预期工作:</p>
<pre><code>x[[[1],[3]],[1,3]]
</code></pre>
<p>这是因为索引数组是一个公共形状的<a href="http://docs.scipy.org/doc/numpy-1.5.x/reference/ufuncs.html#broadcasting" rel="noreferrer">broadcasted</a>。
当然,对于这个特定的示例,您还可以使用基本切片:</p>
<pre><code>x[1::2, 1::2]
</code></pre>