翻譯自:stackoverflow 回答 By Gareth Reeshtml
在 numpy 中,有些運算返回 shape 爲 (R, 1)
而有些返回 (R,)
。因爲須要顯式調用 reshape
,這會讓矩陣乘法變得更加繁瑣。舉例來講,假設有一個矩陣 M
,若是咱們想執行 numpy.dot(M[:,0], numpy.ones((1, R)))
,其中 R
是行數(固然,換成列會有一樣的問題)。咱們會獲得 matrices are not aligned
異常,由於 M[:,0]
的 shape 是 (R,)
可是 numpy.ones((1, R))
的 shape 是 (1, R)
。python
因此個人問題是:數組
shape (R, 1)
and (R,)
有什麼區別。我知道從字面意思上一個是數的 list,另外一個是隻包含一個數的 list 組成的 list。只是好奇爲何不把 numpy
設計成更傾向於 shape (R, 1)
而不是 (R,)
以讓矩陣乘法更簡單。bash
上面的例子有更好的方法嗎?而不用顯式地像這樣調用 reshape
:numpy.dot(M[:,0].reshape(R, 1), numpy.ones((1, R)))
。ide
你寫到,「我知道從字面意思上一個是數的 list,另外一個是隻包含一個數的 list 組成的 list」,可是用這種方式去想有點沒啥用。工具
考慮 NumPy 數組的最好方式是它們包含兩個部分,一個 數據緩衝區(data buffer),它只是一個原始數據塊(a block of raw elements), 以及一個描述如何解釋數據緩衝區的 視圖(view)。spa
好比,若是咱們建立一個包含 12 個整數的數組:翻譯
>>> a = numpy.arange(12)
>>> a
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
複製代碼
這時 a
包含一個數據緩衝區,排列以下:設計
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
複製代碼
以及描述如何解釋數據的視圖:code
>>> a.flags
C_CONTIGUOUS : True
F_CONTIGUOUS : True
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
>>> a.dtype
dtype('int64')
>>> a.itemsize
8
>>> a.strides
(8,)
>>> a.shape
(12,)
複製代碼
這裏的 shape (12,)
表示這個數組由單個索引索引,該索引從 0 到 11。從概念上講,若是咱們標記這個索引 i
,數組 a
看起來像這樣:
i= 0 1 2 3 4 5 6 7 8 9 10 11
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
複製代碼
若是咱們 reshape 一個數組,它不會改變數據緩衝區。相反,它建立了一個新視圖,描述瞭解釋數據的不一樣方式。因此當運行下面以後:
>>> b = a.reshape((3, 4))
複製代碼
數組 b
和 a
有相同的數據緩衝區,可是如今被 兩個 索引索引,其中分別從 0 到 2 和 0 到 3。若是咱們標記兩個索引爲 i
和 j
,數組 b
像這樣:
i= 0 0 0 0 1 1 1 1 2 2 2 2
j= 0 1 2 3 0 1 2 3 0 1 2 3
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
複製代碼
這意味着:
>>> b[2,1]
9
複製代碼
你能夠看到第二個索引改變得快一點,第一個索引改變得慢。若是你但願反過來,能夠指定 order
參數:
>>> c = a.reshape((3, 4), order='F')
複製代碼
這會使得數組索引像這樣:
i= 0 1 2 0 1 2 0 1 2 0 1 2
j= 0 0 0 1 1 1 2 2 2 3 3 3
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
複製代碼
這意味着:
>>> c[2,1]
5
複製代碼
如今應該清楚了數組具備一個或多個維度(dimensions)爲 1 的 shape 意味着什麼。通過執行:
>>> d = a.reshape((12, 1))
複製代碼
數組 d
被兩個索引索引,第一個從 0 到 11,第二個索引全是 0:
i= 0 1 2 3 4 5 6 7 8 9 10 11
j= 0 0 0 0 0 0 0 0 0 0 0 0
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
複製代碼
因此:
>>> d[10,0]
10
複製代碼
維度爲 1 是 「自由的」(某種意義上來講),因此沒人你能阻止你這麼幹:
>>> e = a.reshape((1, 2, 1, 6, 1))
複製代碼
使得一個數組的全部變成這樣:
i= 0 0 0 0 0 0 0 0 0 0 0 0
j= 0 0 0 0 0 0 1 1 1 1 1 1
k= 0 0 0 0 0 0 0 0 0 0 0 0
l= 0 1 2 3 4 5 0 1 2 3 4 5
m= 0 0 0 0 0 0 0 0 0 0 0 0
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
複製代碼
所以:
>>> e[0,1,0,0,0]
6
複製代碼
有關如何實現數組的更多詳細信息,請參見 NumPy 內部文檔。
既然 numpy.reshape 只是建立了一個新視圖,那麼在有必要去使用它的時候不要感到懼怕。當你想要以不一樣的方式索引數組時,這是正確的工具。
然而,在長時間的計算中,一般能夠首先安排去構造具備「正確」形狀的數組,從而最大限度地減小 reshape 和 transpose 的次數。但在沒有看到致使有 reshape 需求的實際背景以前,很難說應該改變什麼。
你的問題中的例子是:
numpy.dot(M[:,0], numpy.ones((1, R)))
複製代碼
但這是不現實的。首先,這個表達式:
M[:,0].sum()
複製代碼
能夠更簡單地計算結果。其次,第 0 列真的有什麼特別的嗎?也許你真正須要的是:
M.sum(axis=0)
複製代碼