Seite 1 von 1
Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Dienstag 25. März 2014, 10:47
von Nras
Hallo zusammen,
ich komme von einem Matlab-Hintergrund und bin nun dabei, einige geschriebene Programme in Python umzuschreiben. Dazu habe ich schon einige Tutorials durchgearbeitet. Auf der Suche nach einem Pendant zu Matlabs cell-arrays habe ich gefunden, dass man Listen benutzen soll. Für eine Cell mit 3 Zeilen und 2 Spalten kann ich das so initialisieren und dann nach belieben füllen, beispielsweise mit .append():
Code: Alles auswählen
M = [
[[], []],
[[], []],
[[], []]
]
print M[1][0]
M[1][0].append(17)
print M[1][0]
Meine Frage lautet, wie kann ich das für beliebige Größen initialisieren, also für m Zeilen und n Spalten?
Viele Grüße,
Nras.
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Dienstag 25. März 2014, 11:01
von BlackJack
@Nras: Das was Du da zeigst ist in Python ungewöhnlich. Man erstellt normalerweise keine leeren verschachtelten Datenstrukturen um die dann zu füllen, sondern erstellt die Strukturen gleich mit den Daten. Und das dann mit Schleifen und bei Listen in dem man mit einer leeren Liste anfängt und die dann füllt, oder falls es sich anbietet erstellt man die Liste gleich mit Werten mit der „list comprehension”-Syntax.
Ansonsten kann man die Frage so beantworten:
Code: Alles auswählen
In [6]: M = [[list() for _ in xrange(2)] for _ in xrange(3)]
In [7]: M
Out[7]: [[[], []], [[], []], [[], []]]
Aber wie gesagt, es kann passieren das da am Ende kein typischer Python-Code bei heraus kommt.
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Dienstag 25. März 2014, 11:40
von Nras
Hallo,
danke für den Code, das liefert genau das von mir Gewünschte. Dass kein üblicher Python Code enstehen könnte, kann wirklich sein, da ich in Python noch sehr unerfahren bin. Vielleicht gibt es ja auch eine viel elegantere Methode für mein Vorhaben. Ich möchte ein zweidimensionales Histogramm von gebenen Listen x und y machen, ich brauche aber nicht bloß die Häufigkeiten, sondern am Ende für jedes der Bins in der 2d-Ebene die Liste mit den Indizes der Datenpunkte, die in dieses Bin gefallen sind. Pseudomäßig also so (x und y gleich lang gegeben):
Code: Alles auswählen
for index in range(len(x)):
row = find_correct_row(x[index])
col = find_correct_col(y[index])
m[row][col].append(index)
Da fällt es mir schwer bis unmöglich, direkt mit list comprehensions oder ähnlichem zu arbeiten.
Viele Grüße,
Nras.
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Dienstag 25. März 2014, 11:59
von cofi
Was man hier sehr wahrscheinlich machen wuerde, waere ein Dictionary statt einer komplexen Listen Struktur zu nutzen.
Fuer dein kleines Snippet also:
Code: Alles auswählen
from collections import defaultdict
distribution = defaultdict(list)
xs = [...]
ys = [...]
for index, (x, y) in enumerate(zip(xs, ys)):
row = find_correct_row(x)
col = find_correct_col(y)
distribution[(row, col)].append(index)
Damit muss man nicht manuell mit den Indizes hantieren und spart sich das aufbauen und verwalten der Listenstruktur.
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Dienstag 25. März 2014, 12:04
von Nras
Hallo,
dass Tupel als key für ein dictionary funktionieren, habe jetzt erst gelernt. Die Zeile 8 gefällt mir auch sehr gut und ist wohl viel mehr "python-like" als meine Schleife nur über den Index. Dafür auch vielen Dank.
Ich bin auf jeden Fall interessiert, auch die Vorteile von Python zu nutzen und nicht nur Sachen 1zu1 zu übersetzen.
Viele Grüße,
Nras.
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Dienstag 25. März 2014, 14:08
von Darii
Nras hat geschrieben:Hallo zusammen,
ich komme von einem Matlab-Hintergrund und bin nun dabei, einige geschriebene Programme in Python umzuschreiben. Dazu habe ich schon einige Tutorials durchgearbeitet. Auf der Suche nach einem Pendant zu Matlabs cell-arrays habe ich gefunden, dass man Listen benutzen soll.
Nein, nimm numpy.
Code: Alles auswählen
import numpy
print numpy.empty((3, 2))
print numpy.zeros((3, 2))
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Dienstag 25. März 2014, 14:19
von BlackJack
@Darii: Ich hätte ja auch `numpy` vorgeschlagen, wenn es denn zu der Aufgabenstellung gepasst hätte.
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Dienstag 25. März 2014, 18:23
von anogayales
BlackJack hat geschrieben:@Darii: Ich hätte ja auch `numpy` vorgeschlagen, wenn es denn zu der Aufgabenstellung gepasst hätte.
Code: Alles auswählen
In [4]: array = numpy.empty((2,2), dtype=object)
In [9]: array[1,1] = "test"
In [12]: array[0,1] = 2
In [13]: array
Out[13]:
array([[None, 2],
[None, 'test']], dtype=object)
Verhält sich wie IMHO wie ein Matlab cell Objekt.
Grüße,
anogayales
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Dienstag 25. März 2014, 19:40
von BlackJack
@anogayales: Das mag ja sein, aber wie löst man damit jetzt die Aufgabenstellung und welchen Vorteil hätte das gegenüber dem `defaultdict()`? Oder verschachtelten Listen?
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Mittwoch 26. März 2014, 10:17
von anogayales
BlackJack hat geschrieben:@anogayales: Das mag ja sein, aber wie löst man damit jetzt die Aufgabenstellung und welchen Vorteil hätte das gegenüber dem `defaultdict()`? Oder verschachtelten Listen?
Das wollte doch OP wissen:
Nras hat geschrieben: Meine Frage lautet, wie kann ich das für beliebige Größen initialisieren, also für m Zeilen und n Spalten?
und das löst doch meine Codesnippet.
Der Vorteil liegt darin, dass es wesentlich lesbarer als das hier ist
Ich weiß, es ist einfach den von dir vorgestellten Codesnippet in einer Funktion zu packen. Wenn man vom Matlab Hintergrund kommt ist numpy einfacher zu verstehen als Python Listen oder Defaultdicts.
Grüße,
anogayales
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Mittwoch 26. März 2014, 11:32
von Nras
Hallo anogayales,
deine Variante funktionert bei mir nicht einfach so. Ich will Listen unbekannter Länge speichern, nicht nur eine Zahl. Das heißt, wenn array[i,j] noch nicht gefüllt ist, müsste ich array[i,j] = [17] schreiben, und ansonsten array[i,j].append(17):
Ebenso verhält es sich, wenn ich nicht das Defaultdict benutzen würde, was ich bis gestern auch noch nicht kannte, sondern ein leeres dict und dann mit has_key abfrage:
Code: Alles auswählen
import numpy as np
array = np.empty((10,10), dtype=object)
mydict = {}
for i in range(1000):
# zufaellige Position
row = np.random.randint(0,10,1)[0]
col = np.random.randint(0,10,1)[0]
# array-Variante
if array[row,col] == None:
array[row,col] = [i]
else:
array[row,col].append(i)
# dictionary-Variante
if mydict.has_key((row,col)):
mydict[(row,col)].append(i)
else:
mydict[(row,col)] = [i]
print array[3,7]
print array[2,3]
print "-----"
print mydict[(3,7)]
print mydict[(2,3)]
Da es bestimmt noch mehr Varianten gibt (neben meiner Idee der Liste in der Liste in der Liste), frage ich mich, ob eine der Methoden den anderen vorzuziehen ist.
Ein Gedanke, der mir gefällt, ist, dass ich mit dem dictionary freier bin, was meine keys betrifft. Das müssen dann ja nicht Integer (Zeile, Spalte einer Matrix) sein, sondern könnten direkt Werte enthalten für das Zentrum meiner Bins. In dieser Anwendung habe ich beispielsweise 2 mal n Zufallszahlen zwischen 0 und 1. Beispielsweise 10 bins in jede Richtung, dann wären die Zentren bei 0.05, 0.15, ..., 0.95 und das könnte ich direkt als key nehmen. array[1,0] = ... wäre dann direkt mydict[(0.15, 0.05)].
Wie gesagt, ich bin noch recht neu in Python (numpy benutze ich natürlich schon) und weiß eben noch nicht, was "gut" ist oder welche Vorteile zum Beispiel ein numpy.array gegenüber einem dictionary hat. Wenn da noch jemand etwas zu sagen hätte, würde ich das sicher aufmerksam lesen.
Viele Grüße,
Nras.
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Mittwoch 26. März 2014, 12:28
von anogayales
Hallo Nras,
es wäre vielleicht auch gut zu wissen was du *eigentlich* machen willst. Willst du ein Histogramm berechnen? Wozu brauchst du pro Bin eine Liste?
Wenn du eine Liste variabler Länge pro Bin brauchst, dann ist ein Defaultdict der richtige Weg. Eine Abbildung von Bin-Index auf Bin-Zentrum musst du dir dann noch selbst schreiben, das ist aber schnell gemacht.
Grüße,
anogayales
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Mittwoch 26. März 2014, 12:31
von BlackJack
@anogayales: Ja das war die Frage im ersten Beitrag, das ist aber (IMHO) nicht die beste Datenstruktur für das was Nras dann danach damit machen möchte.
@Nras: Die `dict.has_key()`-Methode ist veraltet, da würde man eher den ``in``-Operator verwenden, also statt ``if haystack.has_key(needle):`` ein ``if needle in haystack:``.
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Mittwoch 26. März 2014, 13:05
von Nras
Hallo,
zunächst mal Danke für die Antworten. Das mit den verschachtelten Listen war nur so eine Idee, die ich inzwischen aber schon zugunsten von arrays oder dictionaries verworfen habe. Vermutlich wäre es besser, weitere Fragen in einem anderen Beitrag zu erstellen.
anogayales hat geschrieben:... es wäre vielleicht auch gut zu wissen was du *eigentlich* machen willst. Willst du ein Histogramm berechnen? Wozu brauchst du pro Bin eine Liste?
Zudem möchte ich euch nicht mit dem INhalt des ganzen Projekt belasten, aber vielleicht reicht es, kurz folgendes zu schreiben:
ich will später für jedes Bin (i,j) in einer bestimmten Weise "benachbarte Bins" einsammeln, bis ich eine bestimmte Anzahl an Elementen, beispielsweise 100, beisammen habe. Für dieses Zählen habe ich das Histogramm, das einfach aus obigen dict (oder array) erstellt wird, in dem ich ein mal die Länge der Einträge auslese und abspeichere.
Code: Alles auswählen
freq_dict = {}
for key in mydict:
hist_dict[key] = len(mydict[key])
Mit den Daten, die in dem Bin (i,j) und den Nachbar-Bins liegen, werden dann weitere Berechnungen durchgeführt (beispielsweise Quantile bestimmt). Genau dazu brauche ich die Information, welche Datenpunkte (also den Index) in welches Bin gefallen sind. Das Ergebnis davon wird dann wiederum in einem dict (oder array) abgelegt und auch damit wird noch weitergerechnet, usw. Das Endergebnis ist dann ein numpy array, das in eine Datenbank exportiert wird.
Den Code für das gesamte Projekt habe ich in Matlab schon fertig und dieser soll auch prinzipiell nicht mehr geändert, eben nur in Python (auch numpy) übersetzt werden.
Wenns denn hilft (-:
anogayales hat geschrieben:Eine Abbildung von Bin-Index auf Bin-Zentrum musst du dir dann noch selbst schreiben, das ist aber schnell gemacht
Klar, so ist es ja bisher auch realisiert, aber man könnte sich ja den Umweg über den Bin-Index direkt sparen und das jeweilige Bin-Zentrum direkt als key für das dictionary nehmen.
BlackJack hat geschrieben:@Nras: Die `dict.has_key()`-Methode ist veraltet, da würde man eher den ``in``-Operator verwenden, also statt ``if haystack.has_key(needle):`` ein ``if needle in haystack:``.
Danke, soetwas sind für mich sehr wertvolle Kommentare, die mir beim Einstieg in Python helfen, damit ich mir direkt die Konventionen aneigne (-:
Viele Grüße,
Nras.
Re: Wie 3D Liste initialiseren (Pendant zu Matlab 2D Cells)
Verfasst: Mittwoch 26. März 2014, 14:03
von BlackJack
@Nras: Etwas kompaktere Art die Erstellung des `freq_dict` zu schreiben (ungetestet):
Code: Alles auswählen
freq_dict = dict((key, len(value)) for key, value in mydict.viewitems())