Seite 1 von 1

Matrix-list erstellen mit range?

Verfasst: Montag 30. Mai 2016, 18:15
von GPD
Hallo,

ich will eine Matrix-list erstellen, die 61 Zeilen und 3 Spalten hat.

Folgenden Code benutze ich:

Code: Alles auswählen



bar = [0 for i in range(61)]   
Matrix = [bar for i in range(3)]

b = 0
for i in range(len(Matrix)):
    for n in range(len(Matrix[0])):
        Matrix[i][n] = b
        app.PrintPlain(Matrix[i][n])
        b = b + 1

Print('Matrix:')
Print(Matrix)
Ausgabe:
Matrix:
[[180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [
180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [180, 181, 182], [18
0, 181, 182]]

Wenn ich stattdessen folgenden Code ausführe:

Code: Alles auswählen


bar = [0 for i in range(3)]   
Matrix = [[0 for i in range(3)] for i in range(61)]

b = 0
for i in range(len(Matrix)):
    for n in range(len(Matrix[0])):
        Matrix[i][n] = b
        app.PrintPlain(Matrix[i][n])
        b = b + 1

Print('Matrix:')
Print(Matrix)
erhalte ich:
Matrix:
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14], [15, 16, 17], [18, 19, 20], [21, 22, 23], [24, 25, 26], [27, 28, 29], [30, 31, 32], [33, 34, 35], [36, 37, 38], [39, 40, 41], [42, 43, 44], [45, 46, 47], [48, 49, 50], [51, 52, 53], [54, 55, 56], [57, 58, 59], [60, 61, 62], [63, 64, 65], [66, 67, 68], [69, 70, 71], [72, 73, 74], [75, 76, 77], [78, 79, 80], [81, 82, 83], [84, 85, 86], [87, 88, 89], [90, 91, 92], [93, 94, 95], [96, 97, 98], [99, 100, 101], [102, 103, 104], [105, 106, 107], [108, 109
, 110], [111, 112, 113], [114, 115, 116], [117, 118, 119], [120, 121, 122], [123, 124, 125], [126, 127, 128], [129, 130, 131], [132, 133, 134], [135, 136, 137], [138, 139, 140], [141, 142, 143], [144, 145, 146], [147, 148, 149], [150, 151, 152], [153, 154, 155], [156, 157, 158], [159, 160, 161], [162, 163, 164], [165, 166, 167], [168, 169, 170], [171, 172, 173], [174, 175, 176], [177, 178, 179], [180, 181, 182]]
Die letzte Ausgabe ist das, was ich haben wollte!

Warum gibt es einen Unterschied zwischen (funktioniert):

Code: Alles auswählen

bar = [0 for i in range(NrRow)]   
Matrix = [[0 for i in range(NrRow)] for i in range(NrCol)]
und (funktioniert nicht):

Code: Alles auswählen

bar = [0 for i in range(NrRow)]   
Matrix = [[0 for i in range(NrRow)] for i in range(NrCol)]
?

Re: Matrix-list erstellen mit range?

Verfasst: Montag 30. Mai 2016, 18:50
von snafu
GPD hat geschrieben:und (funktioniert nicht):

Code: Alles auswählen

bar = [0 for i in range(NrRow)]   
Matrix = [[0 for i in range(NrRow)] for i in range(NrCol)]
Das würde funktionieren. Folgendes entspricht deinem eingangs gezeigten Code und funktioniert nicht wie du es erwartest:

Code: Alles auswählen

bar = [0 for i in range(NrRow)]   
Matrix = [bar for i in range(NrCol)]
Das Problem entsteht dadurch, dass du anstatt einer neuen Liste lediglich die Referenz auf die Liste ("bar") in die Matrix reinsteckst. Daher beziehen sich all deine Zuweisungen letztlich auf die selbe 3-elementrige Liste und dadurch kommt das für dich komische Ergebnis zustande.

Übrigens: Listen belegt man in Python üblicherweise nicht erst mit Nullwerten, sondern man befüllt sie mit den tatsächlichen Werten. Da es Listen sind, wachsen die dynamisch bei jeder Befüllung. Dein Konstrukt erinnert mich eher an Arrays wie man sie z.B. aus C oder Java kennt. Wobei man das selbst in diesen Sprachen etwas anders machen würde.

Re: Matrix-list erstellen mit range?

Verfasst: Montag 30. Mai 2016, 18:52
von __deets__
Beim zweiten Code-Schnipsel kannst du dir das bar komplett sparen - das benutzt du ja nicht.

Und damit ist auch schon erklaert, was da anders ist: du erstellst eine Liste mit drei Elementen, und jedes Element ist eine Liste mit 61 Elementen.

Nur das im ersten Fall es drei mal dieselbe Liste ist. Nur beim zweiten mal erzeugst du eine *neue* Liste pro Zeile.

Das ist auch schon die ganze Erklaerung. Aehnliches beobachtest du hier:

Code: Alles auswählen

l = range(10)

def foo(arg):
      arg.append(20)
      
print l
foo(l)
print l
Auch da wird keine implizite Kopie der Liste angefertigt, nur weil sie irgendwie verwendet wird.

Re: Matrix-list erstellen mit range?

Verfasst: Montag 30. Mai 2016, 19:06
von snafu
Die gewünschte Ausgabe lässt sich kompakt so realisieren:

Code: Alles auswählen

matrix = [[i + 3 * j for i in range(3)] for j in range(61)]
print(matrix)
Ansonsten könnte man natürlich auch Numpy nutzen:

Code: Alles auswählen

import numpy as np
np.arange(61 * 3).reshape((61, 3))

Re: Matrix-list erstellen mit range?

Verfasst: Dienstag 31. Mai 2016, 07:29
von GPD
Vielen Dank euch allen!

Jaa, das mit der Referenzierung hätt ich mir auch denken können! In Java gibt es ja die Clone-Metode. Hab grade das hier gefunden für python:

>>> from copy import deepcopy
>>>
>>> lst1 = ['a','b',['ab','ba']]
>>>
>>> lst2 = deepcopy(lst1)

mal sehen ob das funktioniert!

Vielen Dank!

Re: Matrix-list erstellen mit range?

Verfasst: Dienstag 31. Mai 2016, 07:46
von Sirius3
@GPD: wie snafu schon geschrieben hat, ist es in Python üblich, jedesmal eine neue Liste zu erzeugen, statt Listen mit Dummywerte nachträglich zu füllen, oder gar Listen zu kopieren und zu ändern.

Re: Matrix-list erstellen mit range?

Verfasst: Dienstag 31. Mai 2016, 08:08
von snafu
GPD hat geschrieben:>>> from copy import deepcopy
>>>
>>> lst1 = ['a','b',['ab','ba']]
>>>
>>> lst2 = deepcopy(lst1)
Du verwirrst mich. Was soll denn jetzt tatsächlich in die Liste rein? Zahlen? Strings? Etwas völlig anderes...?

Re: Matrix-list erstellen mit range?

Verfasst: Dienstag 31. Mai 2016, 08:16
von GPD
snafu hat geschrieben:
GPD hat geschrieben:>>> from copy import deepcopy
>>>
>>> lst1 = ['a','b',['ab','ba']]
>>>
>>> lst2 = deepcopy(lst1)
Du verwirrst mich. Was soll denn jetzt tatsächlich in die Liste rein? Zahlen? Strings? Etwas völlig anderes...?
Der Code-Snippet ist nur ein Bispiel für die Funktion deepcopy, die ich spontan gegoogled hat. Speziell für meinen Fall kommen nur Zahlen in die Liste. Aber gut zu wissen, dass man auch Listen mit Strings tief kopieren kann.

Bei Matlab ist es so, dass ein nachträgliches vergrößern eines Arrays den Code verlangsamt. Komisch, dass es bei Python üblich ist, Listen nicht vorzudeklarieren.

Re: Matrix-list erstellen mit range?

Verfasst: Dienstag 31. Mai 2016, 08:55
von Sirius3
@GPD: Matlab und Python haben völlig unterschiedliche Konzepte. Vor allem wenn man aus der Matlab-Welt kommt muß man stark umdenken. Es ist quasi unmöglich etwas komplexeren Matlab-Code auf Anhieb fehlerfrei nach Python zu konvertieren. Matlab verwendet ein Copy-on-Write-Konzept. Das heißt, sobald mehrere Variablen auf die selbe Matrix zeigen und man ändert einen Wert der Matrix, wird sie komplett kopiert und die Kopie der Variable zugewiesen:
[codebox=matlab file=Unbenannt.m]
a = magic(5);
b = a; % b und a zeigen auf die gleiche Matrix im Speicher
a(4) = 3; % a zeigt nun auf eine Kopie, die danach geändert wird.
[/code]

Das macht es unmöglich, Funktionen zu schreiben, die Datenstrukturen verändern. Vorteil, man kann nicht aus Versehen b ändern obwohl man nur in a etwas schreibt. Nachteil: man kann nicht willentlich mit Shared-Data arbeiten. Fazit: Matlab verhindert schwer zu findende Fehler auf Kosten von Flexibilität, Speicher und Geschwindigkeit.

Python geht das andere Extrem: alles wird geteilt. Nur wenn man explizit sagt, dass man eine Kopie will, wird auch eine erstellt. Um also Fehler zu verhindern, dass man aus Versehen eine Datenstruktur ändert, die irgendwo anders noch benutzt wird, ist es üblich, einfach nichts zu ändern sondern gleich neue Datenstrukturen zu erstellen. Das geht auch wieder ein bißchen auf Kosten des Speichers; Geschwindigkeit ist in den meisten Fällen kein Problem, weil beim Verarbeiten einer Liste sowieso jedes Element verändert wird.

Nun zu Deinem Problem: Du willst wahrscheinlich gar keine Listen, sondern tatsächlich eine Matrix, wo man in Python üblicherweise numpy benutzt. numpy-Arrays sind ähnlich wie Matlab-Matrizen, mit dem entscheidenden Unterschied, dass es kein Copy-on-Write gibt. Es muß also explizit kopiert werden:

Code: Alles auswählen

import numpy

a = numpy.random.random((4,4))
b = a  # a und b zeigen auf das selbe Array
a = a.copy()  # explizite Kopie
a[0, 3] = 0.5
Ebenso gibt es kein implizites Vergrößern einer Matrix, indem man über das Ende hinaus Zahlen schreibt (was in Matlab bedeutet, dass eine neue Matrix erstellt und der alte Inhalt kopiert wird, daher langsam). Es ist also bei numpy zwingend, sich über die Größe schon vorher Gedanken zu machen (Matlab warnt nur), oder explizit numpy.append, numpy.resize, numpy.hstack etc. zu benutzen (eher unüblich; üblich wäre, alles in eine Python-Liste zu stecken und nachträglich z.B. per numpy.hstack in ein numpy-Array zu konvertieren).

Weitere Unterschiede, die einem den Umstieg schwer machen, sind, dass Indizes bei Matlab ab 1 gezählt werden und der erste Index Zeilen zählt, während Python ab 0 zählt und der erste Index Spalten zählt.

Re: Matrix-list erstellen mit range?

Verfasst: Dienstag 31. Mai 2016, 12:00
von GPD
Sirius3 hat geschrieben:@GPD: Matlab und Python haben völlig unterschiedliche Konzepte. Vor allem wenn man aus der Matlab-Welt kommt muß man stark umdenken. Es ist quasi unmöglich etwas komplexeren Matlab-Code auf Anhieb fehlerfrei nach Python zu konvertieren. Matlab verwendet ein Copy-on-Write-Konzept. Das heißt, sobald mehrere Variablen auf die selbe Matrix zeigen und man ändert einen Wert der Matrix, wird sie komplett kopiert und die Kopie der Variable zugewiesen:
[codebox=matlab file=Unbenannt.m]
a = magic(5);
b = a; % b und a zeigen auf die gleiche Matrix im Speicher
a(4) = 3; % a zeigt nun auf eine Kopie, die danach geändert wird.
[/code]

Das macht es unmöglich, Funktionen zu schreiben, die Datenstrukturen verändern. Vorteil, man kann nicht aus Versehen b ändern obwohl man nur in a etwas schreibt. Nachteil: man kann nicht willentlich mit Shared-Data arbeiten. Fazit: Matlab verhindert schwer zu findende Fehler auf Kosten von Flexibilität, Speicher und Geschwindigkeit.

Python geht das andere Extrem: alles wird geteilt. Nur wenn man explizit sagt, dass man eine Kopie will, wird auch eine erstellt. Um also Fehler zu verhindern, dass man aus Versehen eine Datenstruktur ändert, die irgendwo anders noch benutzt wird, ist es üblich, einfach nichts zu ändern sondern gleich neue Datenstrukturen zu erstellen. Das geht auch wieder ein bißchen auf Kosten des Speichers; Geschwindigkeit ist in den meisten Fällen kein Problem, weil beim Verarbeiten einer Liste sowieso jedes Element verändert wird.

Nun zu Deinem Problem: Du willst wahrscheinlich gar keine Listen, sondern tatsächlich eine Matrix, wo man in Python üblicherweise numpy benutzt. numpy-Arrays sind ähnlich wie Matlab-Matrizen, mit dem entscheidenden Unterschied, dass es kein Copy-on-Write gibt. Es muß also explizit kopiert werden:

Code: Alles auswählen

import numpy

a = numpy.random.random((4,4))
b = a  # a und b zeigen auf das selbe Array
a = a.copy()  # explizite Kopie
a[0, 3] = 0.5
Ebenso gibt es kein implizites Vergrößern einer Matrix, indem man über das Ende hinaus Zahlen schreibt (was in Matlab bedeutet, dass eine neue Matrix erstellt und der alte Inhalt kopiert wird, daher langsam). Es ist also bei numpy zwingend, sich über die Größe schon vorher Gedanken zu machen (Matlab warnt nur), oder explizit numpy.append, numpy.resize, numpy.hstack etc. zu benutzen (eher unüblich; üblich wäre, alles in eine Python-Liste zu stecken und nachträglich z.B. per numpy.hstack in ein numpy-Array zu konvertieren).

Weitere Unterschiede, die einem den Umstieg schwer machen, sind, dass Indizes bei Matlab ab 1 gezählt werden und der erste Index Zeilen zählt, während Python ab 0 zählt und der erste Index Spalten zählt.

Hallo Sirius3,

danke für deinen Top-Beitrag! Ja, als Matlab-Programmierer muss ich mich wohl etwas umstellen. Danke für die Hinweise! :)