Liste mit csw.writer items?

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
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

Hi,

okay, muss bei meinem Projekt noch irgendwie die Daten zum plotten ausgeben.
Würde dazu gerne eine CSV-Datei verwenden.
Dazu würde ich gerne sowas machen:

Code: Alles auswählen

      
for z in koerper:
    csvwriter[koerper.index(z)] = csv.writer(open( str(koerper[koerper.index(z)][0]) + ".txt", "wb"))
for z in log:
     writer[koerper.index(z)].writerow(z[1])
Leider kann ich anscheinend nicht auf diese weise die csvwriter Elemente erzeugen.
Auch wenn ich per Hand:

Code: Alles auswählen

        
csvwriter[0] = csv.writer(open( "Erde.txt", "wb"))
csvwriter[1] = csv.writer(open( "Mond.txt", "wb"))
(Mond und Erde sind die ersten Elemente in meiner Liste)
mache geht es nicht.

Immo behelfe ich mir mit:

Code: Alles auswählen

csvwriter0 = csv.writer(open( "Erde.txt", "wb"))
csvwriter1 = csv.writer(open( "Mond.txt", "wb"))
for z in log:
     if z[0]=='Erde':
          csvwriter0.writerow(z[1])
     if z[0]=='Mond':
          csvwriter1.writerow(z[1])
Das tut zwar genau das was es soll aber ich möchte halt später beliebig viele Körper verwenden die ich dann nur noch in der Eingangsdatei spezifiziere und so wird das nicht gehen.
hat jemand einen Tip für mich?
Zuletzt geändert von p90 am Freitag 23. Juli 2010, 12:25, insgesamt 1-mal geändert.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ungetestet:

Code: Alles auswählen

import collections

collector = collections.defaultdict(list)
for entry in log:
    collector[entry[0]].append(entry)

for name, entries in collector.iteritems():
    with open("%s.txt" % name, "w") as fobj:
        writer = csv.writer(fobj)
        for entry in entries:
            writer.writerow(entry)
Der Gedanke ist folgender: Man braucht die Daten getrennt, also trennt man sie auf.
Um sich man von den Namen unabhaengig zu machen, nimmt man ein Dictionary und damit man nicht ueberpruefen muss, ob man schon den Namen kennt, nimmt man ein `defaultdict`.
BlackJack

Die letzten zwei Zeilen von cofi kann man noch zu einer eindampfen -- es gibt eine `writerows()`-Methode auf dem Writer-Objekt.
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

Hi,
habs jetzt so gemacht:

Code: Alles auswählen

        collector = collections.defaultdict(list)
        for entry in log:
            collector[entry[0]].append(entry[1])

        for name, entries in collector.iteritems():
            print len(entries)
            with open("%s.txt" % name, "w") as fobj:
                writer = csv.writer(fobj)
                writer.writerows(entries)
Geht ganz gut, leider hab ich immer eine Leerzeile zwischen den Einträgen.
Also am Ende in den Dateien 2000 Einträge obwohl entries je nur 1000 Einträge haben.
Muss mir auch das mit den Dicts mal genauer ansehen...

Mal noch zwei andere Fragen:
1. Wie bekomme ich Farbe in meine CODE-Tags?
2. Kann man irgendwie das "," als Seperator aus der Liste austauschen?
Möchte das ganze später durch gnuplot jagen um die Planetenbahnen zu sehen.
Kann ich die Row einfach wie einen String behandeln und dann immer noch per writerows rausschreiben?

MfG und schon mal Danke für die Hilfe!
Zuletzt geändert von Anonymous am Freitag 23. Juli 2010, 11:23, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

p90 hat geschrieben: Mal noch zwei andere Fragen:
1. Wie bekomme ich Farbe in meine CODE-Tags?
Es gibt doch extra den Python-Button, der zu folgendem BB-Code führt: [ python]...[ /python], ohne die Leerzeichen. Oder auch [ code=python]... [ /code] manuell.
2. Kann man irgendwie das "," als Seperator aus der Liste austauschen?
Guck doch einfach in die Doku zu CSV. Dort wird auf die "Dialects and Formatting Parameters. " verwiesen; wenn man die sich anguckt, findet man das ganz schnell. Zudem wird oben beim Writer auch ein Beispiel gezeigt. Also: Erst Doku gucken und dann fragen :-) (Ja, man übersieht auch mal was; hier ist es aber denke ich offensichtlich)
Kann ich die Row einfach wie einen String behandeln und dann immer noch per writerows rausschreiben?
Was meinst Du mit Row?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@p90: Kann es sein, dass Deine Daten bereits ein '\n' am Ende enthalten?
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

@Hyperion
Hatte schon nachgesehen, aber auf der Doku Seite waren nur Delimiter Bsp. fürs lesen aber es geht genauso fürs schreiben wie ich gerade gemerkt habe.
Dachte eigentlich das das "," nicht als Delimiter da steht sondern ein Teil meiner Liste ist und ich eigentlich nur eine Spalte habe. Aber gut, das hatte ich einfach falsch verstanden.

@BlackJack
Sollten sie nicht.
Eigentlich sollte das nur zwei Floats in einer Liste sein.
Hier einfach mal das ganze Programm:

Code: Alles auswählen

import csv
import operator
import math
import collections

class Vector:
    'Represents a 2D vector.'
    def __init__(self, x = 0, y = 0):
        self.x = float(x)
        self.y = float(y)

    def size(self):
            return sqrt(self.x**2+self.y**2) 
    
    def normalize(self):
        n=sqrt(self.x**2+self.y**2)
        self.x = self.x / n
        self.y = self.y /n
        return self

    def __add__(self, val):
        return Point( self[0] + val[0], self[1] + val[1] )
    
    def __sub__(self,val):
        return Point( self[0] - val[0], self[1] - val[1] )
    
    def __iadd__(self, val):
        self.x = val[0] + self.x
        self.y = val[1] + self.y
        return self
        
    def __isub__(self, val):
        self.x = self.x - val[0]
        self.y = self.y - val[1]
        return self
    
    def __div__(self, val):
        return Point( self[0] / val, self[1] / val )
    
    def __mul__(self, val):
        return Point( self[0] * val, self[1] * val )
    
    def __idiv__(self, val):
        self[0] = self[0] / val
        self[1] = self[1] / val
        return self
        
    def __imul__(self, val):
        self[0] = self[0] * val
        self[1] = self[1] * val
        return self
                
    def __getitem__(self, key):
        if( key == 0):
            return self.x
        elif( key == 1):
            return self.y
        else:
            raise Exception("Invalid key to Point")
        
    def __setitem__(self, key, value):
        if( key == 0):
            self.x = value
        elif( key == 1):
            self.y = value
        else:
            raise Exception("Invalid key to Point")
        
    def __str__(self):
        return "(" + str(self.x) + "," + str(self.y) + ")"
Point = Vector

def DistanceSqrd( point1, point2 ):
    'Returns the distance between two points squared. Marginally faster than Distance()'
    return ( (point1[0]-point2[0])**2 + (point1[1]-point2[1])**2)
def Distance( point1, point2 ):
    'Returns the distance between two points'
    return math.sqrt( DistanceSqrd(point1,point2) )
def LengthSqrd( vec ):
    'Returns the length of a vector sqaured. Faster than Length(), but only marginally'
    return vec[0]**2 + vec[1]**2
def Length( vec ):
    'Returns the length of a vector'
    return math.sqrt( LengthSqrd(vec) )
def Normalize( vec ):
    'Returns a new vector that has the same direction as vec, but has a length of one.'
    if( vec[0] == 0. and vec[1] == 0. ):
        return Vector(0.,0.)
    return vec / Length(vec)
def Dot( a,b ):
    'Computes the dot product of a and b'
    return a[0]*b[0] + a[1]*b[1]
def ProjectOnto( w,v ):
    'Projects w onto v.'
    return v * Dot(w,v) / LengthSqrd(v)

 


G=1
def csvreader(filename,delim):
    print "analyzing ",filename
    csv_in = csv.reader(open(filename, "rb"), delimiter=';')
    #csv_in = pylab.csv2rec(file, checkrows=0, skiprows=1, delimiter=delim, names='name,position,speed,mass')
    koerper=[]
    #Name, Positionx, Positiony, Speedx, Speedy, Masse
        for row in csv_in:
                name, x_pos, y_pos, x_speed, y_speed, mass = row
                koerper.append([name, [float(x_pos),float(y_pos)], [float(x_speed),float(y_speed)], float(mass)])
        return koerper

def diff(x,y):
        out = [x[0]-y[0],x[1]-y[1]]
        return out
def skalar(x,y):
        out = x[0]*y[0]+x[1]*y[1]
        return out
def skavec(x,y):
        out=[x*y[0],x*y[1]]
        return out
def addlist(x):
        out = [0,0]
        for y in x:
                out = [out[0]+y[0],out[1]+y[1]]
        return out

def main():
        print "gestartet"
    zeitaufloesung = 0.1
    hops = 1000
    print "einlesen"
    koerper = csvreader("koerper.txt", ";")
    log=[]
    for i in range(0, hops):
                koerpernew=[]
        for x in koerper:
            force = [0,0]
            for y in koerper:
                if not y == x:
                     force = addlist([force, skavec(G * x[3] * y[3] / (skalar(x[1],y[1])**3), diff(x[1],y[1]))]) 
            speednew=addlist([skavec(zeitaufloesung, force),x[2]])
            positionnew = addlist([skavec(0.5 * (zeitaufloesung**2), force), skavec(zeitaufloesung,x[2]),x[1]])
             koerpernew.append([x[0], positionnew, speednew, x[3]])
             koerper=koerpernew[:]
             for z in koerper:
                  log.append([koerper[koerper.index(z)][0], koerper[koerper.index(z)][1], i])

        #csvwriter0 = csv.writer(open( "Erde.txt", "wb"))
        #csvwriter1 = csv.writer(open( "Mond.txt", "wb"))
        #for z in koerper:
        #        csvwriter[koerper.index(z)].append(csv.writer(open( str(koerper[koerper.index(z)][0]) + ".txt", "wb")))
        #for z in log:
        #        csvwriter[koerper.index(z)].writerow(z[1])
        #for z in log:
        #        if z[0]=='Erde':
        #                csvwriter0.writerow(z[1])
        #        if z[0]=='Mond':
        #                csvwriter1.writerow(z[1])



        collector = collections.defaultdict(list)
        for entry in log:
            collector[entry[0]].append(entry[1])

        for name, entries in collector.iteritems():
            print len(entries)
            with open("%s.txt" % name, "w") as fobj:
                writer = csv.writer(fobj, delimiter='\t')
                print entries
                writer.writerows(entries)
    print "finished"
    
            
        
main()
Der class Vektor Kram steht nur drin weil ich unten diese hässlichen Berechnungen ersetzen möchte. Hab mir da zwar (obwohl ich gelesen habe das Python das automatisch richtig machen würde) einen Lösung gebaut, aber zum lesen ist die nicht geeignet.
Ist halt alles sehr hässlich aber zumindest geht es soweit schon mal.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Es gibt mit numpy ein hervorragendes Modul für Deine Berechnungen!
http://www.scipy.org/more_about_SciPy

Hier mal ein Link auf die Doku wegen des Vektor-Ersatzes: http://docs.scipy.org/doc/numpy/reference/arrays.html

Damit könntest Du Dir das Neu Erfinden des Rades sparen und Deinen Quellcode ziemlich radikal reduzieren.

Zeige uns doch mal einen Ausschnitt aus den Eingabedaten; ohne die wird es schwer etwas dazu zu sagen; zumal Dein Quellcode arg unübersichtlich ist. (Wir haben hier ein Paste-Bin im Board für längere Code-Schnipsel)
Guck Dir mal PEP8 an: http://www.python.org/dev/peps/pep-0008/
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

@Hyperion
NumPy und SciPy hatte ich schon gesehen. Leider kann ich sie nicht installieren weil sie Python 2.6 nicht finden. Denke mal das liegt daran das ich 2.7 verwende. Selbes gilt übrigens auch für pylab das ich zuerst für das einlesen verwende wollte.

Meine Eingabe Datei sieht einfach so aus:
koerper.txt

Code: Alles auswählen

Erde; 2;2;3;3;500
Mond; 1;3;1;3;500
Die Werte sind immo zwar alle Integers, ich wandle sie aber beim einlesen direkt in floats um.
Und wenn hinter der 500 noch in \n stehen würde würde er mir doch sicher beim multiplizieren eine Exception werfen oder?

[EDIT]
Wenn ich

Code: Alles auswählen

Erde; 2;2;3;3;500;
Mond; 1;3;1;3;500;
schreibe und dafür oben beim einlesen die letzte Spalte gar nicht verwende ist das Problem immer noch da. Denke als nicht das ein \n aus den Eingabedaten kommt.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

p90 hat geschrieben:@Hyperion
NumPy und SciPy hatte ich schon gesehen. Leider kann ich sie nicht installieren weil sie Python 2.6 nicht finden. Denke mal das liegt daran das ich 2.7 verwende. Selbes gilt übrigens auch für pylab das ich zuerst für das einlesen verwende wollte.
Na dann würde ich dafür eben noch Python 2.6 nutzen; oder bist Du so stark an die 2.7 gebunden? Bevor ich versuche, eine durchdachte Lib durch meinen eigenen Code zu ersetzen, würde ich dann lieber auf eine ältere Python Version setzen und später ggf. migrieren. Da Python 2.7 relativ neu ist, wird es sicher noch ein wenig dauern, bis die entsprechenden Versionen von SciPy / NumPy verfügbar sind, aber bestimmt nicht wirklich lange. Mein Rat wäre also, das dringend zu überdenken!


Denke als nicht das ein \n aus den Eingabedaten kommt.
Ich mag das jetzt nicht komplett nachvollziehen geschweige denn ausprobieren, aber evtl. liegt es ja doch an Deinem eigenen Code. Kann mir nicht vorstellen, dass CSV da künstlich Leerzeilen einbaut...

Noch ein paar generelle Anmerkungen:
- ich würde das alles modularer aufbauen; versuche die Arbeitsschritte in Funktion zu zerteilen. Versuche vor allem das Parsen, Berechnen und anschließende Wegschreiben zu trennen. Das ist eigentlich immer ein guter Tipp.
- Nutze den "if __name__ == "__main__"-Hook
- Benutze optparse (oder bei 2.7 argparse; aber zu 2.7 s.o. ;-) ) für Parameter, die Du per Komandozeile übergeben möchtest; mindestens aber sys.argv[...], sollte es da nur ein oder zwei Stück geben.
- beachte PEP8
- versuche die Mischung aus Englisch und Deutschen Namen zu vermeiden; "zeitauflösung" und "force" passen einfach nicht zusammen ;-) (wird doch wohl so ein Wort wie timescale geben?; dict.leo.org ist sonst Dein Freund)

Wenn Du das alles umsetzt, wird es auch einfacher, Dir zu helfen, weil der Code dann auch separat testbar wird und das ganze lesbarer.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

Hi,
ne bin nicht an python 2.7 gebunden.
Hab jetzt erst mal 2.6 installiert.
Nach ner menge umschreiben (hoffe es stimmt jetzt mit PEP8 überein...) hab ich jetzt überall arrays. Geht damit wunderbar und durch das ausbauen der Logik ist es wesentlich schöner zu lesen.
Was du mit "if __name__ == "__main__" meinst weiß ich gerade noch nicht ganz (hab gesehen das man damit bei bestimmten Argumenten verschiedenen Code ausführen kann, aber immo übergebe ich gar nichts, werde es mir aber für die Zukunft ansehen.
Sieht jetzt so aus, aber hab immer noch die Leerzeilen.

Code: Alles auswählen

import csv
import collections
import pylab
import numpy as n

# Defination Simulations Konstanten und Kraftkopplungen
G=1 #Gravitationskopplung
time = 0.1 # Zeit pro Hop
hops = 1000 # Hops

# Definiere Hilfsfunktionen
def norm(x):
    out=n.sqrt(n.dot(x,x))
    return out

def csvreader(filename,delim):
    print "analyzing ",filename
    csv_in = csv.reader(open(filename, "rb"), delimiter=';')
    #csv_in = pylab.csv2rec(filename, checkrows=0, skiprows=1, delimiter=delim, names='name,pos_x,pos_y,speed_x,speed_y,mass,bla')
    bodies=[]
    #Name, Positionx, Positiony, Speedx, Speedy, Masse
    for row in list(csv_in)[1:]:
        name, pos_x, pos_y, speed_x, speed_y, mass, bla = row
        print row
        bodies.append([name, n.array([float(pos_x),float(pos_y)]), n.array([float(speed_x),float(speed_y)]), float(mass)])
    print "finished reading"
    return bodies

def csvwriter(log):
    collector = collections.defaultdict(list)
    for entry in log:
        collector[entry[0]].append(entry[1])

    for name, entries in collector.iteritems():
        with open("%s.txt" % name, "w") as fobj:
            writer = csv.writer(fobj, delimiter='\t')
            writer.writerows(entries)
    return "finished writing"

def calcgravforce(x,y):
    #G * m1 * m2 * er /r^2
    out = (x[1]-y[1]) * G * x[3] * y[3] / norm(x[1]-y[1])**3
    return out

def calcgravforcecomplete(x, bodies):
    force = n.array([0,0])
    for y in bodies:
        if not y == x:
            force = force - calcgravforce(x, y)
    return force

def calcnewposition(x, force):
    # 1/2 * a * t^2 + v * t +x
    out = 0.5 * (time**2) * force + time * x[2] + x[1]
    return out
    
def calcnewspeed(x, force):
    #a * t + v
    out = time * force + x[2]
    return out

def calcnewmass(x):
    #konstante masse, Raketen noch nicht drin
    out = x[3]
    return out

def calcbody(x, force):
    out = [x[0], calcnewposition(x, force), calcnewspeed(x, force), calcnewmass(x)]
    return out


def main():
    bodies = csvreader("koerper.txt", ";")
    log=[]
    for i in range(0, hops):
        bodiesnew=[]
        for x in bodies:
            force = calcgravforcecomplete(x, bodies)
            bodiesnew.append(calcbody(x, force))
            #log.append([bodies[bodies.index(z)][0], bodies[bodies.index(z)][1], i])
            log.append([x[0], x[1], i])
        bodies=bodiesnew[:]
    print csvwriter(log)
    return 1
                    
main()
Benutzeravatar
snafu
User
Beiträge: 6862
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hyperion hat geschrieben:dict.leo.org ist sonst Dein Freund
Und dict.cc, was ich inzwischen sogar besser als LEO finde.

@p90: Nur das Code-Auslagern fehlt noch. ;)

Zudem macht mir der Aufbau - ohne jetzt die Berechnungen im Detail nachvollzogen zu haben - den Eindruck als könnte man es hier mal mit einem objektorientierten Ansatz (sprich: einer Klasse) probieren.
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

ka ob und wie ich das in eine Klasse ummodeln soll.
Ist aber gerade auch nicht ganz soo wichtig.
Hab aber den Grund für die Leerzeile gefunden.
Der Default "lineterminator" von csv.writer ist "\r\n"
Ersetze ich ihn gegen "\n" habe ich genau das was ich haben wollte.
Danke erst mal für die ganzen Tipps, wenn ihr noch was habt, immer her damit!
BlackJack

@p90: Das kopieren der Liste am Ende der äusseren ``for``-Schleife in `main()` ist übrigens nicht nötig. Eine einfache Zuweisung würde ausreichen.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Code: Alles auswählen

import numpy as n
Würde ich mir noch mal überlegen! n ist zwar kurz und daher schön zu tippen, aber numpy doch auch nicht so lang, dafür aber sofort eingänglich. n ist mir hier zu magisch als Name für ein Modul.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

Die offizielle SciPy Dokumentation verwendet:

Code: Alles auswählen

>>> import numpy as np
>>> import scipy as sp
>>> import matplotlib as mpl
>>> import matplotlib.pyplot as plt
Anstatt überall alles per float umzuwandeln, lässt sich auch folgendes schreiben:

Code: Alles auswählen

np.array([pos_x, pos_y], dtype='float')
Weitere Anmerkungen:
- nutze nump.linalg.norm statt deiner Hilfsfunktion
- a -= b ist schneller als a = a - b (weniger Typüberprüfungen notwendig)
- np.zeros((2), dtype='float') anstelle von np.array([0,0]) (ebenfalls schneller)
- geb dein Ergebnis direkt zurück ohne es an den Namen``out`` zu binden, z.B. ``return 0.5 * (time**2) * force + time * x[2] + x[1]``
- lese nicht alle Daten auf einmal ein, sondern verwende einen Generator, der dir immer die aktuelle Zeile zurückgibt. Das spart vor allem Memory, wenn du größere Datensätze hast.

So, muss jetzt zur Arbeit :)

Grüße
Gerrit
Antworten