2014-01-26 48 views
6

我希望能够使用列表理解语法轻松处理NumPy数组。例如,我想像下面明显错误的代码来重现相同的数组。NumPy列表理解句法

>>> X = np.random.randn(8,4) 
>>> [[X[i,j] for i in X] for j in X[i]] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
IndexError: arrays used as indices must be of integer (or boolean) type 

什么是简单的方法来做到这一点,以避免使用range(len(X)

+1

X [I,J]是X语法糖[i] [j]在与NumPy –

+9

不要这样做!它击败了使用NumPy的全部目的。 – user2357112

+0

而且(即使你修复它),这将不会重现数组,它会产生一个列表的列表,而不是。 – abarnert

回答

0

你的意思是以下吗?

>>> [[X[i,j] for j in range(X.shape[1])] for i in range(X.shape[0])] 
[[0.62757350000000001, -0.64486080999999995, -0.18372566000000001, 0.78470704000000002], 
[1.78209799, -1.336448459999999 9, -1.3851422200000001, -0.49668994], 
[-0.84148266000000005, 0.18864597999999999, -1.1135151299999999, -0.40225053999999 999], 
[0.93852824999999995, 0.24652238000000001, 1.1481637499999999, -0.70346624999999996], 
[0.83842508000000004, 1.0058 697599999999, -0.91267403000000002, 0.97991269000000003], 
[-1.4265273000000001, -0.73465904999999998, 0.6684284999999999 8, -0.21551155], 
[-1.1115614599999999, -1.0035033200000001, -0.11558254, -0.4339924], 
[1.8771354, -1.0189299199999999, - 0.84754008000000003, -0.35387946999999997]] 

使用numpy.ndarray.copy

>>> X.copy() 
array([[ 0.6275735 , -0.64486081, -0.18372566, 0.78470704], 
     [ 1.78209799, -1.33644846, -1.38514222, -0.49668994], 
     [-0.84148266, 0.18864598, -1.11351513, -0.40225054], 
     [ 0.93852825, 0.24652238, 1.14816375, -0.70346625], 
     [ 0.83842508, 1.00586976, -0.91267403, 0.97991269], 
     [-1.4265273 , -0.73465905, 0.6684285 , -0.21551155], 
     [-1.11156146, -1.00350332, -0.11558254, -0.4339924 ], 
     [ 1.8771354 , -1.01892992, -0.84754008, -0.35387947]]) 
+0

他说他试图创造出与他开始的完全相同的形状,所以它甚至不是“转置”,它只是“复制”。 – abarnert

+0

@abarnert,感谢您的评论。我更新了答案。 – falsetru

17

首先,你不应该使用NumPy的数组作为列表的列表来。

其次,让我们忘记NumPy;你的listcomp首先没有任何意义,即使是列表清单。

在内部理解中,for i in X将遍历X中的行。这些行不是数字,它们是列表(或NumPy中的1D数组),因此X[i]没有任何意义。您可能需要改为i[j]

在外围理解中,for j in X[i]有同样的问题,但是有更大的问题:没有i的值。你有理解循环每个i里面这个理解。

如果你被一个理解困惑,写出来作为一个明确的for声明,作为List Comprehensions教程部分解释:

tmp = [] 
for j in X[i]: 
    tmp.append([X[i,j] for i in X]) 

...这将扩展为:

tmp = [] 
for j in X[i]: 
    tmp2 = [] 
    for i in X: 
     tmp2.append(X[i,j]) 
    tmp.append(tmp2) 

......这应该明显表明这里有什么问题。


我想你想要的是:

[[cell for cell in row] for row in X] 

再次,把它放回明确for声明:

tmp = [] 
for row in X; 
    tmp2 = [] 
    for cell in row: 
     tmp2.append(cell) 
    tmp.append(tmp2) 

这显然正确的。

或者,如果你真的想使用索引(但你不知道):

[[X[i][j] for j in range(len(X[i]))] for i in range(len(X))] 

所以,回到NumPy的。在NumPy的条款,即最后一个版本是:

[[X[i,j] for j in range(X.shape[1])] for i in range(x.shape[0])] 

...如果你想在列优先的顺序,而不是行主要去了,你可以(不像列表的列表):

[[X[i,j] for i in range(X.shape[0])] for j in range(x.shape[1])] 

...但这当然会改变阵列,这不是你想要做的。

你做的一件事不能在同一个表达式中混列专业和行专业的次序,因为你最终是废话。


当然的正确的方式,使一个数组的副本是使用copy方法:

X.copy() 

正如移调数组的正确方法是:

X.T 
6

简单的方法是不要这样做。改用numpy的隐式矢量化。举例来说,如果你有数组a和b如下:

A = numpy.array([[1, 3, 5], 
       [2, 4, 6], 
       [9, 8, 7]]) 
B = numpy.array([[5, 3, 5], 
       [3, 5, 3], 
       [5, 3, 5]]) 

然后使用列表理解下面的代码:

C = numpy.array([[A[i, j] * B[i, j] for j in xrange(A.shape[1])] 
       for i in xrange(A.shape[0])]) 

可以更容易写成

C = A * B 

它也会跑得快得多。通常,如果您不使用numpy进行列表推导,那么您将生成更快,更清晰的代码。

如果你真的想使用列表解析,标准的Python列表理解写入技术适用。遍历元素,而不是指数:

C = numpy.array([[a*b for a, b in zip(a_row, b_row)] 
       for a_row, b_row in zip(A, B)] 

因此,您的示例代码将成为

numpy.array([[elem for elem in x_row] for x_row in X]) 
+0

注意:为了提高效率,如果您不再使用该列表,则可能需要使用'np.asarray()'而不是'np.array()'。这与'copy = False'具有相同的功能。 –

+0

@RicardoCruz:它会以任何一种方式复制。如果输入已经是数组,那么'asarray'只能避免一个副本。 – user2357112

+0

@ user237112,哦,谢谢你指出。我不知道。 –