Numpy. Dizi şekli (R, 1) ve (R,) arasındaki fark


320

İçinde numpybazı işlemler şekillenir, (R, 1)bazıları geri döner (R,). Bu, açık reshapegerektiği için matris çarpımını daha sıkıcı hale getirecektir . Örneğin, bir matris verildiğinde , satır sayısını nerede Myapmak istiyorsak (elbette aynı sorun sütun bazında da gerçekleşir). Biz alacak beri hatayı şeklinde olduğunu ancak şeklindedir .numpy.dot(M[:,0], numpy.ones((1, R)))Rmatrices are not alignedM[:,0](R,)numpy.ones((1, R))(1, R)

Yani sorularım:

  1. Şekil (R, 1)ve arasındaki fark nedir (R,). Kelimenin tam anlamıyla, tüm listenin yalnızca bir sayı içerdiği sayıların listesi ve liste listesi olduğunu biliyorum. Neden daha kolay matris çarpımı yerine numpyşekli tercih edecek şekilde tasarlamadığını merak ediyorum .(R, 1)(R,)

  2. Yukarıdaki örnek için daha iyi yollar var mı? Açıkça böyle yeniden şekillendirmeden:numpy.dot(M[:,0].reshape(R, 1), numpy.ones((1, R)))


3
Bu yardımcı olabilir. Yine de pratik bir çözüm bulmakla değil.
keyser

1
Uygun çözüm: numpy.ravel (M [:, 0]) - şekli (R, 1) 'den (R,)' ye dönüştürür
Andi R

Yanıtlar:


545

1. NumPy'deki şekillerin anlamı

"Kelimenin tam anlamıyla bir liste ve tüm listenin sadece bir sayı içerdiği liste listesi olduğunu biliyorum" yazıyorsunuz, ama bu biraz düşünmek için yararsız bir yol.

NumPy diziler düşünmek için en iyi yolu, iki parça, bir oluşur ki veri tampon sadece ham elemanlarının bir blok, ve a görünüşüdür veri tamponu yorumlama açıklamaktadır.

Örneğin, 12 tamsayıdan oluşan bir dizi oluşturursak:

>>> a = numpy.arange(12)
>>> a
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])

Sonra aböyle bir şey düzenlenmiş bir veri arabelleğinden oluşur:

┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
  0   1   2   3   4   5   6   7   8   9  10  11 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

ve verilerin nasıl yorumlanacağını açıklayan bir görünüm:

>>> 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,)

Burada şekil (12,) , dizinin 0'dan 11'e kadar çalışan tek bir dizinle dizine eklendiği anlamına gelir. Kavramsal olarak, bu tek dizini etiketlersek idizi aşöyle görünür:

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 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

Bir diziyi yeniden şekillendirirsek , veri arabelleği değişmez. Bunun yerine, verileri yorumlamanın farklı bir yolunu tanımlayan yeni bir görünüm oluşturur. Sonra:

>>> b = a.reshape((3, 4))

dizi b, aynı veri arabelleğine sahiptir a, ancak şimdi sırasıyla 0'dan 2'ye ve 0'dan 3'e kadar çalışan iki endeksle dizine eklenir . İki dizini etiketlersek ive jdizi şu şekilde bgörünür:

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 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

bunun anlamı:

>>> b[2,1]
9

İkinci dizinin hızla değiştiğini ve ilk dizinin yavaş değiştiğini görebilirsiniz. Bunun tam tersi olmasını tercih ediyorsanız, orderparametreyi belirtebilirsiniz :

>>> c = a.reshape((3, 4), order='F')

dizine şu şekilde dizin verilir:

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 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

bunun anlamı:

>>> c[2,1]
5

Şimdi, bir dizinin 1 veya daha fazla boyutu olan bir şekle sahip olmasının ne anlama geldiği açık olmalıdır.

>>> d = a.reshape((12, 1))

dizi d, birincisi 0'dan 11'e kadar çalışan iki dizin tarafından dizine eklenir ve ikinci dizin her zaman 0'dır:

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 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

ve bu yüzden:

>>> d[10,0]
10

Uzunluk 1'in boyutu "özgür" (bir anlamda), yani sizi şehre gitmekten alıkoyan bir şey yok:

>>> e = a.reshape((1, 2, 1, 6, 1))

şöyle dizine eklenmiş bir dizi vererek:

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 
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘

ve bu yüzden:

>>> e[0,1,0,0,0]
6

Dizilerin nasıl uygulandığı hakkında daha fazla bilgi için NumPy dahili belgelerine bakın .

2. Ne yapmalı?

Yana numpy.reshapesadece yeni bir görünüm oluşturur, sen gerektiğinde bunu kullanma konusunda korkmak gerekir. Bir diziyi farklı bir şekilde dizine eklemek istediğinizde kullanmak için doğru araçtır.

Bununla birlikte, uzun bir hesaplamada, ilk etapta "doğru" şekle sahip diziler oluşturmak ve böylece yeniden şekillendirme ve aktarım sayısını en aza indirmek genellikle mümkündür. Ancak yeniden şekillendirme ihtiyacına yol açan gerçek bağlamı görmeden neyin değiştirilmesi gerektiğini söylemek zor.

Sorunuzdaki örnek şudur:

numpy.dot(M[:,0], numpy.ones((1, R)))

ama bu gerçekçi değil. İlk olarak, bu ifade:

M[:,0].sum()

sonucu daha basit hesaplar. İkincisi, sütun 0 hakkında gerçekten özel bir şey var mı? Belki de aslında ihtiyacınız olan şey:

M.sum(axis=0)

34
Bu, dizilerin nasıl saklandığını düşünmede son derece yardımcı oldu. Teşekkür ederim! Daha fazla matris hesaplaması için bir (2-d) matrisin bir sütununa (veya sırasına) erişmek elverişsizdir, çünkü her zaman sütunu uygun şekilde yeniden şekillendirmem gerekir. Her seferinde şekli (n,) 'den (n, 1)' e değiştirmek zorundayım.
OfLettersAndNumbers

3
@SammyLee: Kullanım newaxisörneği için Başka bir eksen gerekiyorsa a[:, j, np.newaxis]olduğunu jinci sütunu ave a[np.newaxis, i]bir iinci sıra.
Gareth Rees

Ben bu model tarafından kağıt üzerinde daha iyi bir anlayış elde etmek için endeksler çizmek çalışıyorum ve ben bunu elde gibi görünmüyor, eğer 2 x 2 x 4 bir şekil olsaydı ben ilk 2 0000000011111111 olarak anlaşılabilir ve son 4 olabilir anlamak 0123012301230123 olarak anlaşılan ortadaki ne olur?
PirateApp

3
Bunu düşünmenin kolay bir yolu, numpy'nin tam olarak burada beklendiği gibi çalışmasıdır, ancak Python'un tuples baskısı yanıltıcı olabilir. Bu (R, )durumda, şekli ndarraytek bir öğeye sahip bir demettir, bu nedenle sondaki virgülle Python tarafından yazdırılır. Ek virgül olmasaydı, parantez içindeki bir ifade ile belirsiz olurdu . ndarrayTek bir boyuta sahip bir A , uzunluktaki bir sütun vektörü olabilir R. Gelen (R, 1)durumda, demet, böylece bir sıra vektörü (ya da uzunluğu 1 sırası ile, bir matris olarak düşünülebilir iki öğe R.
Michael Yang

1
@ Alex-droidAD: Bu soruya ve cevaplarına bakın.
Gareth Rees

16

Arasındaki fark (R,)ve (1,R)tam anlamıyla size kullanım gereken endeksleri sayısıdır. ones((1,R))yalnızca bir satırı olan 2 boyutlu bir dizidir. ones(R)bir vektördür. Genellikle, değişkenin birden fazla satır / sütuna sahip olması mantıklı değilse, tek bir boyutlu bir matris değil, bir vektör kullanmalısınız.

Özel durumunuz için birkaç seçenek vardır:

1) İkinci argümanı bir vektör yapın. Aşağıdaki iyi çalışır:

    np.dot(M[:,0], np.ones(R))

2) Matlab benzeri matris işlemleri istiyorsanız, sınıfı matrixkullanın ndarray. Tüm matrisler 2-D diziler olmaya zorlanır ve operatör *element-wise yerine matris çarpımı yapar (böylece noktaya ihtiyacınız yoktur). Benim tecrübeme göre, bu daha değerli, ama buna değer, eğer matlab için kullanılırsanız güzel olabilir.


Evet. Daha matlab benzeri bir davranış bekliyordum. matrixDerse bir göz atacağım . matrixBTW sınıfı için sorun nedir ?
clwen

2
Sorun matrix, sadece 2D olması ve ayrıca operatörün '*' 'ı aşırı yüklemesi nedeniyle, a için ndarraykullanıldığında yazılan işlevlerin başarısız olabileceğidir matrix.
Evan

11

Şekil bir demettir. Yalnızca 1 boyut varsa, şekil bir sayı olacak ve virgülden sonra boş olacaktır. 2+ boyut için, tüm virgüllerden sonra bir sayı olacaktır.

# 1 dimension with 2 elements, shape = (2,). 
# Note there's nothing after the comma.
z=np.array([  # start dimension
    10,       # not a dimension
    20        # not a dimension
])            # end dimension
print(z.shape)

(2)

# 2 dimensions, each with 1 element, shape = (2,1)
w=np.array([  # start outer dimension 
    [10],     # element is in an inner dimension
    [20]      # element is in an inner dimension
])            # end outer dimension
print(w.shape)

(2,1)


5

Temel dizi sınıfı için, 2d dizileri 1d veya 3d olanlardan daha özel değildir. Boyutları koruyan bazı işlemler vardır, bazıları onları küçültür, diğerleri birleştirir, hatta genişletir.

M=np.arange(9).reshape(3,3)
M[:,0].shape # (3,) selects one column, returns a 1d array
M[0,:].shape # same, one row, 1d array
M[:,[0]].shape # (3,1), index with a list (or array), returns 2d
M[:,[0,1]].shape # (3,2)

In [20]: np.dot(M[:,0].reshape(3,1),np.ones((1,3)))

Out[20]: 
array([[ 0.,  0.,  0.],
       [ 3.,  3.,  3.],
       [ 6.,  6.,  6.]])

In [21]: np.dot(M[:,[0]],np.ones((1,3)))
Out[21]: 
array([[ 0.,  0.,  0.],
       [ 3.,  3.,  3.],
       [ 6.,  6.,  6.]])

Aynı diziyi veren diğer ifadeler

np.dot(M[:,0][:,np.newaxis],np.ones((1,3)))
np.dot(np.atleast_2d(M[:,0]).T,np.ones((1,3)))
np.einsum('i,j',M[:,0],np.ones((3)))
M1=M[:,0]; R=np.ones((3)); np.dot(M1[:,None], R[None,:])

MATLAB sadece 2D dizilerle başladı. Daha yeni sürümler daha fazla boyuta izin verir, ancak 2'nin alt sınırını korur. Ancak yine de bir satır matrisi ile birinci sütun, biri (1,3)v şeklinde olan sütun arasındaki farka dikkat etmeniz gerekir (3,1). Ne sıklıkla yazdın [1,2,3].'? Ben yazacaktım row vectorve column vectorancak bu 2d kısıtlama ile, MATLAB'da herhangi vektörler bulunmamaktadır - en azından değil 1d olarak vektörün matematiksel anlamda.

np.atleast_2dBaktınız mı (_1d ve _3d versiyonları da)?


1

1) bir şekle tercih değil nedeni (R, 1)üzerinde (R,)gereksiz yere işleri karmaşık olmasıdır. Ayrıca, neden (R, 1)bir uzunluk-R vektörü için varsayılan olarak şekle sahip olmak tercih edilmeli (1, R)? Ek boyutlara ihtiyaç duyduğunuzda basit tutmak ve açık olmak daha iyidir.

2) Örneğin, bir dış ürünü hesaplarsınız, böylece bunu reshapekullanarak arama yapmadan yapabilirsiniz np.outer:

np.outer(M[:,0], numpy.ones((1, R)))

Cevap için teşekkürler. 1) M[:,0]temelde tüm satırları ilk elemanla elde eder, bu yüzden sahip (R, 1)olmaktan daha mantıklıdır (1, R). 2) Her zaman np.outer, örneğin (1, R) şeklindeki matris için nokta (R, 1) ile değiştirilemez.
clwen

1) Evet, bu sözleşme olabilir , ancak bu diğer durumlarda daha az elverişlidir. Kural, M [1, 1] 'in bir şekil (1, 1) dizisini döndürmesi de olabilir, ancak bu genellikle bir skalerden daha az uygundur. Gerçekten matris benzeri davranışlar istiyorsanız, bir matrixnesne kullanmanız daha iyi olur . 2) Aslında, np.outerbağımsız olarak şekilleri bağımsız olarak çalışır (1, R), (R, 1)ya da ikisinin bir kombinasyonu olabilir.
bogatron

0

Burada zaten çok iyi cevaplar var. Ama benim için, şekil veya dizinin tüm programı kırabileceği bir örnek bulmak zor oldu.

İşte burada:

import numpy as np
a = np.array([1,2,3,4])
b = np.array([10,20,30,40])


from sklearn.linear_model import LinearRegression
regr = LinearRegression()
regr.fit(a,b)

Bu hata ile başarısız olur:

ValueError: Beklenen 2D dizi, bunun yerine 1D dizi aldı

ama biz eklerseniz reshapeiçin a:

a = np.array([1,2,3,4]).reshape(-1,1)

bu doğru çalışıyor!

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.