1. Die Bedeutung von Formen in NumPy
Sie schreiben: "Ich weiß buchstäblich, dass es eine Liste von Zahlen und eine Liste von Listen ist, in denen alle Listen nur eine Zahl enthalten", aber das ist ein wenig wenig hilfreich, um darüber nachzudenken.
Der beste Weg, um über NumPy-Arrays nachzudenken, besteht darin, dass sie aus zwei Teilen bestehen, einem Datenpuffer, der nur ein Block von Rohelementen ist, und einer Ansicht die beschreibt, wie der Datenpuffer interpretiert wird.
Wenn wir beispielsweise ein Array mit 12 Ganzzahlen erstellen:
>>> a = numpy.arange(12)
>>> a
array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
a
Besteht dann aus einem Datenpuffer, der ungefähr so angeordnet ist:
┌────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┬────┐
│ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 10 │ 11 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
und eine Ansicht, die beschreibt, wie die Daten zu interpretieren sind:
>>> 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,)
Hier bedeutet die Form, (12,)
dass das Array durch einen einzelnen Index indiziert wird, der von 0 bis 11 läuft. Wenn wir diesen einzelnen Index i
kennzeichnen, a
sieht das Array konzeptionell folgendermaßen aus:
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 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
Wenn wir ein Array umformen , ändert dies nichts am Datenpuffer. Stattdessen wird eine neue Ansicht erstellt, die eine andere Art der Interpretation der Daten beschreibt. So danach:
>>> b = a.reshape((3, 4))
Das Array b
hat den gleichen Datenpuffer wie a
, wird jedoch jetzt durch zwei Indizes indiziert , die von 0 bis 2 bzw. 0 bis 3 laufen. Wenn wir die beiden Indizes i
und beschriften j
, b
sieht das Array folgendermaßen aus:
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 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
was bedeutet, dass:
>>> b[2,1]
9
Sie können sehen, dass sich der zweite Index schnell und der erste Index langsam ändert. Wenn Sie dies umgekehrt bevorzugen, können Sie den folgenden order
Parameter angeben :
>>> c = a.reshape((3, 4), order='F')
was zu einem Array führt, das wie folgt indiziert ist:
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 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
was bedeutet, dass:
>>> c[2,1]
5
Es sollte nun klar sein, was es für ein Array bedeutet, eine Form mit einer oder mehreren Dimensionen der Größe 1 zu haben. Nachher:
>>> d = a.reshape((12, 1))
Das Array d
wird durch zwei Indizes indiziert, von denen der erste von 0 bis 11 läuft und der zweite Index immer 0 ist:
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 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
und so:
>>> d[10,0]
10
Eine Dimension der Länge 1 ist (in gewissem Sinne) "frei", daher hindert Sie nichts daran, in die Stadt zu gehen:
>>> e = a.reshape((1, 2, 1, 6, 1))
Geben eines wie folgt indizierten Arrays:
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 │
└────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘
und so:
>>> e[0,1,0,0,0]
6
Weitere Informationen zur Implementierung von Arrays finden Sie in der Dokumentation zu NumPy-Interna .
2. Was ist zu tun?
Schon seit numpy.reshape
nur eine neue Ansicht erstellt wird, sollten Sie keine Angst haben, sie bei Bedarf zu verwenden. Es ist das richtige Werkzeug, wenn Sie ein Array auf andere Weise indizieren möchten.
Bei einer langen Berechnung ist es jedoch normalerweise möglich, Arrays mit der "richtigen" Form zu konstruieren und so die Anzahl der Umformen und Transponierungen zu minimieren. Aber ohne den tatsächlichen Kontext zu sehen, der zur Notwendigkeit einer Umformung geführt hat, ist es schwer zu sagen, was geändert werden sollte.
Das Beispiel in Ihrer Frage lautet:
numpy.dot(M[:,0], numpy.ones((1, R)))
das ist aber nicht realistisch. Erstens dieser Ausdruck:
M[:,0].sum()
berechnet das Ergebnis einfacher. Zweitens, hat Spalte 0 wirklich etwas Besonderes? Vielleicht brauchen Sie tatsächlich:
M.sum(axis=0)