Spalten statt Zeilen lesen und AUsgabeformat

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
vucub-caquix
User
Beiträge: 9
Registriert: Mittwoch 28. Oktober 2009, 10:33

Hallo,
ich habe nicht viel gemacht mit python bisher und habe 2 Anfängerfragen.
Das Programm das ich schreibe soll Spalten aus einem Textfile auslesen, die Werte der Spalten randomisieren und in einer neuen Spalte in eine Output-Datei schreiben.
Der Vorgang der Randomisierung selbst ist kein Problem, wohl aber die Art und Weise des Datenlesens- und schreibens.
Zunächst bin ich über die funktion f.readlines() gestolpert (um die die Input-Datei Zeilenweise einzulesen); das geht schon ich die richtige Richtung. Was ich nun noch brauche ist eine Funktion, mit der ich die einzelnen Spalten der Input-Datei in jeweils einen Vektor schreiben kann, bzw. eine Funktion mit der ich eine einzelne Spalte aus einer Matrix extrahieren kann. Auf die könnte ich dann readlines anwenden und die Spalte so shuffeln.
Das andere Problem ist das der Ausgabe. Ich schreibe die geshuffelten Daten in ein neues array. Wenn ich dieses nun Ausgeben möchte, sieht das ungefähr so aus:
['4\n', '5\n', '9\n', '0\n', '2\n', '1\n', '3\n', '6\n', '8\n', '7\n']
Tatsächlich möchte ich die Ausgabe aber als string, die oben gezeigt Reihe soll also eine Spalte in der Datei darstellen. Das klappt auch nicht, wenn ich str() auf das array anwende.
Kann mir jemand Tips zu den beiden Problemen geben?
Vielen Dank!
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Python kennt zunächst mal keine "Arrays". Deine Ausgabe scheint eine Liste zu sein. Mein erster Tipp wäre daher: Das Python-Tutorial durchzuarbeiten.
Benutzeravatar
Klip
User
Beiträge: 98
Registriert: Donnerstag 10. August 2006, 20:39

Ausgabe als String:

Code: Alles auswählen

>>> array = ['4\n', '5\n', '9\n']
>>> print ', '.join(array).replace('\n', '')
4, 5, 9
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Sorry, aber Du solltest ggf. auch noch mal das Tutorial durchlesen.

Code: Alles auswählen

', '.join((o.rstrip() for o in data))
Geht auch; Da muß man auch nicht jedes Mal den ganzen String durchforsten und ersetzen. Und zum Anderen wird es das Problem der Sonderzeichen nicht geben, wenn die Dateien anders bearbeitet werden.

Gruß,
Christian
Benutzeravatar
Klip
User
Beiträge: 98
Registriert: Donnerstag 10. August 2006, 20:39

CM hat geschrieben: Geht auch; Da muß man auch nicht jedes Mal den ganzen String durchforsten und ersetzen. Und zum Anderen wird es das Problem der Sonderzeichen nicht geben, wenn die Dateien anders bearbeitet werden
Stimmt, das ist hübscher (:
vucub-caquix
User
Beiträge: 9
Registriert: Mittwoch 28. Oktober 2009, 10:33

So ich bin jetzt etwas weiter, habe ein numpy array genommen. Nun doch die Frage zum Output, der sieht jetzt z.B. so aus (wenn ich print auf das array anwende)
[ 8. 18.]
[ 4. 14.]
[ 9. 19.]
[ 2. 12.]
[ 7. 17.]
[ 5. 15.]
[ 6. 16.]
[ 0. 10.]
[ 1. 11.]
[ 3. 13.]]
Ich möchte aber das weder klammern noch punkte ausgegeben werden, nur die Zahlen mit Leerstellen getrennt.
Dazu bekomme ich eine Wahrung beim Ausführen des Programms:
/usr/lib/python2.6/site-packages/numpy/lib/utils.py:108: DeprecationWarning: read_array is deprecated
warnings.warn(str1, DeprecationWarning)
Vieleicht weiss wer was dazu?
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

Wie schon von zuvor erwähnt, solltest du erstmal das Python-Tutorial durcharbeiten. Da gibt es auch ein Kapitel zur Ein- und Ausgabe.
BlackJack

@vucub-caquix: Wie liest Du die Daten denn ein? Die Warnung deutet darauf hin, dass da eine Funktion benutzt wird, die nicht mehr verwendet werden sollte.
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Und außerdem wurde die Lösung schon gepostet...

Zum Lesen von Dateien in numpy-Arrays sollte man numpy.loadtxt verwenden.
vucub-caquix
User
Beiträge: 9
Registriert: Mittwoch 28. Oktober 2009, 10:33

Danke für die Hilfe, numpy.loadtxt tut sein job und mit der Entsprechung für numpy.savetxt kann man auch bequem die Ausgabe anpassen.

Das mit dem Tutorial ist ein netter Hinweis, tatsächlich ist es fast einer auf den man selbst kommen kann..

Ich will niemanden zwingen mir zu antworten, dass soll bitte nur tun wer Lust darauf hat. Tatsächlich liessen sich sicher sehr viele Fragen "beantworten" indem man sagt, man solle ein Buch lesen, ein Tutorial durcharbeiten oder was auch immer.

Eine Frage habe ich noch an die numpy-Experten,
die Funktion numpy.random.permutation() soll ein array, bzw eine Sequenz randomisieren. Das passiert aber nur für die erste Spalte des arrays, alle anderen Spalten werden entsprechend der ersten Sequenz sortiert. Gibt es eine Möglichkeit die Funktion für jede Spalte aufzurufen, oder muss ich dann für jede Spalte eine einzelne Liste (bzw. ein einzelnes Array) definieren?

Vielen Dank
vucub-caquix
User
Beiträge: 9
Registriert: Mittwoch 28. Oktober 2009, 10:33

Das Problem habe ich schon verstanden:
dtype : dtype, optional
Data type of the resulting array. If this is a record data-type, the resulting array will be 1-dimensional, and each row will be interpreted as an element of the array. In this case, the number of columns used must match the number of fields in the data-type.
numpy.loadtxt(fname, dtype=<type 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False)
Was ich also bräuchte wäre ein dtype, der dafür sorgt, dass das resultierende array die Dimension der Anzahl der Spalten aus dem infile hat. Geht das?
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Verwende doch ``unpack=True``
Dann gehts so:

Code: Alles auswählen

rows = numpy.loadtxt(..., unpack=True)
process(rows[0]) # Zugriff auf 1. Spalte
perm_rows = [numpy.random.permutation(row) for row in rows]
process(perm_rows[1]) # Zugriff auf 2. Spalte permutiert (sagt man das so?)
``process`` ist natürlich nur eine Beispielfunktion.
vucub-caquix
User
Beiträge: 9
Registriert: Mittwoch 28. Oktober 2009, 10:33

Super, vielen Dank!
Jetzt muss ich die Daten nur nochmal transponieren bevor ich sie schreibe, damit ich Zeilen und Spalten wieder in der Ausgangskonfiguration habe, numpy.savetxt kennt die unpack Option leider nicht..
Darüber hinaus fürchte ich, dass das ziemlich langsam werden könnte bei grossen Infiles, dann muss ich vermutlich doch in C schreiben.
Ist das ein allgemeines Problem mit Spalten umzugehen in python?
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Ist eigentlich kein Problem mit Spalten. Du siehst das glaub zu kompliziert.
Vielleicht hilft dir das weiter:

Code: Alles auswählen

In [40]: import numpy

In [41]: data = numpy.loadtxt('data.csv', delimiter=';')

In [42]: datalist = numpy.loadtxt('data.csv', delimiter=';', unpack=True)

In [43]: numpy.all(data[:,0] == datalist[0])
Out[43]: True

In [44]: numpy.all(data == datalist.transpose())
Out[44]: True

In [45]: len(data)
Out[45]: 9060
PS. Weiß ja nicht was du für Größen hast, aber bei der Größe ging das problemlos.
PPS. Numpy müsste das eigentlich schon alles in C haben, da kannst du vermutlich gar nichts optimieren ;)
BlackJack

@vucub-caquix: Ich denke auch Du gehst das wesentlich zu kompliziert an. Wenn ich es richtig verstanden habe, willst Du eine Textdatei mit zwei Spalten mit ganzen Zahlen lesen, bestimmte Spalten "mischen" und das wieder schreiben!? Ganz ohne transponieren und "in place":

Code: Alles auswählen

In [83]: !cat test.txt
1 1
2 2
3 3
4 4
5 5

In [84]: a = np.loadtxt('test.txt', int)

In [85]: a
Out[85]:
array([[1, 1],
       [2, 2],
       [3, 3],
       [4, 4],
       [5, 5]])

In [86]: np.random.shuffle(a[...,1])

In [87]: a
Out[87]:
array([[1, 2],
       [2, 3],
       [3, 5],
       [4, 4],
       [5, 1]])

In [88]: np.random.shuffle(a[...,1])

In [89]: a
Out[89]:
array([[1, 3],
       [2, 4],
       [3, 1],
       [4, 2],
       [5, 5]])

In [90]: np.savetxt(sys.stdout, a, '%d')
1 3
2 4
3 1
4 2
5 5
vucub-caquix
User
Beiträge: 9
Registriert: Mittwoch 28. Oktober 2009, 10:33

Tatsächlich hat meine Testdatei nur 2 Spalten, das Programm soll aber wesentlich grössere Datenmengen "mischen" die nicht nur ints sind, dabei ist die Anzahl der Spalten nicht konstant.
Ich glaube die Methode das orginal Array zu transponieren ist ein gute Idee, ich kann so das Problem umgehen, dass ich nicht weiss wie viele Spalten es geben wird und über

Code: Alles auswählen

data_shuffled = [numpy.random.permutation(row) for row in data]
ein neues Array erzeugen, welches die randomisierten Daten enhält.
Das gleiche geht über

Code: Alles auswählen

for i in range(x):
        numpy.random.shuffle(data[i])
print data
Da müsste man eben "x" kennen, also die Anzahl der Spalten. Wenn ich das Ergebnis in eine file schreibe

Code: Alles auswählen

outfile = numpy.savetxt(infile + '_shuffled.dat', data_shuffled, fmt='%.2f')
kommt in beiden Fällen das Gleiche raus, das sieht dann z.B so aus:
1.50 4.50 2.50 9.50 3.50 6.50 8.50 0.50 7.50 5.50
14.50 12.50 15.50 16.50 10.50 11.50 17.50 13.50 19.50 18.50
Was in meiner Ursprungsdatei also Spalten waren sind nun Zeilen, das ist für die weitere Bearbeitung ungünstig.
Ich finde leider keine Ausgabeoption für numpy.savetxt, die es mir erlaubt transponiert in die Datei zu schreiben (also sowas wie unpack für das lesen). Ich kann auch nicht .transpose() drauf anwenden, python beschwert sich dann, dass mein Objekt eine Liste ist, auf die ich transpose nicht anwenden kann:
data_shuffled.transpose()
AttributeError: 'list' object has no attribute 'transpose'
Das liegt soweit ich das verstehe daran, dass ich im Beispiel mit 2 Spalten, 2 arrays erzeuge, die also eigentlich 2 Listen sind und daher nicht transponierbar.
Das ist wiederum kein Problem, wenn ich nicht unpack nehme und die Schleife oben mir numpy.random.shuffle ausführe.

Es gibt also 2 Möglichkeiten das Problem zu lösen:
1. Die Spalten der Ausgangsdatei zu zählen, damit ich den entsprechenden Wert in die for-Schleife schreiben kann.
2. Die beiden Listen die bei der unpack-Methode rauskommen irgendwie wieder Spalten zu verwandeln

Sorry das ich nerve, vielleicht habt ihr ja noch eine letzte Idee
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Mit data.shape bekommst du Größe der Zeilen und Spalten.

Die Schleife muss aber so aussehen:

Code: Alles auswählen

for i in xrange(data.shape[1]):
    numpy.random.shuffle(data[:,i])
BlackJack

@vucub-caquix: Was gibt es denn da noch in den Spalten? Vielleicht ist `numpy` ja nicht das richtige, denn das kann am besten mit Arrays mit Zahlen umgehen, am besten wenn die auch noch vom gleichen Typ sind. Also was sind dass denn überhaupt für Daten?

Das eine "list comprehension" eine Liste erzeugt, die natürlich keine `transpose()`-Methode kennt, wäre jetzt schon wieder Python-Basiswissen.

Und dass man die Dimensionen eines `numpy`-Arrays über das `shape`-Attribut herausbekommt, hätte man sicher irgendwo in der `numpy`-Dokumentation erfahren:

Code: Alles auswählen

In [109]: a
Out[109]:
array([[1, 3],
       [2, 4],
       [3, 1],
       [4, 2],
       [5, 5]])

In [110]: a.shape
Out[110]: (5, 2)
Wenn diese Spalten "beliebiges" enthalten können, also nicht nur Zahlen eines bestimmten Typs, dann solltest Du vielleicht doch mal Python lernen und das Problem selber lösen. Also überlegen, was "transponieren" eigentlich bedeutet und das programmieren.

Das Format der Daten ist für die gewünschte Operation auch anscheinend auch ziemlich ungünstig.
vucub-caquix
User
Beiträge: 9
Registriert: Mittwoch 28. Oktober 2009, 10:33

Code: Alles auswählen

for i in xrange(data.shape[1]):
    numpy.random.shuffle(data[:,i])
funktioniert! Super vielen Dank, damit ist das Programm fertig
Antworten