Seite 1 von 1

Liste mit csw.writer items?

Verfasst: Freitag 23. Juli 2010, 00:54
von p90
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?

Re: Liste mit csw.writer items?

Verfasst: Freitag 23. Juli 2010, 03:04
von cofi
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`.

Re: Liste mit csw.writer items?

Verfasst: Freitag 23. Juli 2010, 07:04
von BlackJack
Die letzten zwei Zeilen von cofi kann man noch zu einer eindampfen -- es gibt eine `writerows()`-Methode auf dem Writer-Objekt.

Re: Liste mit csw.writer items?

Verfasst: Freitag 23. Juli 2010, 11:12
von p90
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!

Re: Liste mit csw.writer items?

Verfasst: Freitag 23. Juli 2010, 11:21
von Hyperion
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?

Re: Liste mit csw.writer items?

Verfasst: Freitag 23. Juli 2010, 11:26
von BlackJack
@p90: Kann es sein, dass Deine Daten bereits ein '\n' am Ende enthalten?

Re: Liste mit csw.writer items?

Verfasst: Freitag 23. Juli 2010, 12:41
von p90
@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.

Re: Liste mit csw.writer items?

Verfasst: Freitag 23. Juli 2010, 12:49
von Hyperion
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/

Re: Liste mit csw.writer items?

Verfasst: Freitag 23. Juli 2010, 14:16
von p90
@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.

Re: Liste mit csw.writer items?

Verfasst: Freitag 23. Juli 2010, 15:35
von Hyperion
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.

Re: Liste mit csw.writer items?

Verfasst: Samstag 24. Juli 2010, 13:41
von p90
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()

Re: Liste mit csw.writer items?

Verfasst: Samstag 24. Juli 2010, 14:11
von snafu
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.

Re: Liste mit csw.writer items?

Verfasst: Samstag 24. Juli 2010, 16:38
von p90
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!

Re: Liste mit csw.writer items?

Verfasst: Samstag 24. Juli 2010, 18:07
von 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.

Re: Liste mit csw.writer items?

Verfasst: Dienstag 27. Juli 2010, 21:41
von Hyperion

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.

Re: Liste mit csw.writer items?

Verfasst: Mittwoch 28. Juli 2010, 01:39
von gkuhl
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