Probleme bei Funktionsdefinition

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
itchy_scratchy
User
Beiträge: 5
Registriert: Dienstag 24. April 2012, 13:19

Hallo zusammen,

ich arbeite seit kurzer Zeit mit Python. Momentan führe ich eine Auswertung von Fahrdaten durch.

So will ich untersuchen, welche Strecken ein PKW über den Tag zurücklegt und alle verschiedenen Zielorte mit dem morgendlichen Abfahrtsort vergleichen (über die Harversine-Formel, welche durch die Geokoordinaten die Entfernung zwischen den Orten bestimmt). Nun bin ich dabei eine Funktion zu definieren, welche den Standort wiedergeben soll (bspw. zuhause). Die Funktion greift hierbei auf Parameter aus einer CSV-Tabelle, welche in einer späteren Funktion verwendet wird, zu.

Fahrzeug abdatum abzeit abstrasse ablongitudo ablatitude andatum anzeit anstrasse anland anort anlongitudo anlatitude
211 20100628 1115 Seestraße 10.5643 49.7132 20110628 1125 Bleichereistraße DE Seestraße 9.56012 49.7152
211 20100628 1153 Seestraße 10.5597 49.7150 20110628 1153 Bleichereistraße DE Seestraße 9.55898 49.71513
211 20100628 1309 Seestraße 10.5590 49.7150 20110628 1311 Bleichereistraße DE Seestraße 10.56004 49.71521
211 20100628 1423 Seestraße 10.5597 49.7152 20110628 1427 Bleichereistraße DE Seestraße 10.55906 49.71495
211 20100628 1450 Seestraße 10.5584 49.7154 20110628 1501 Leibnizstraße DE Kreuzstrass 10.57995 49.68392
211 20100628 1524 Kreuzstraße 10.5800 49.6842 20110628 1545 Bleichereistraße DE Seestraße 10.55965 49.71533

Stimmen die Ziel- mit den Abfahrdaten überein, soll ausgegeben werden dass sich das Fahrzeug zuhause befindet. Ebenso soll auch ausgegeben werden, dass sich das Fahrzeug zuhause befindet wenn die Distanz <= 0.5 km ist. Andernfalls soll ausgegeben werden, dass sich das Fahrzeug unterwegs befindet.

Code: Alles auswählen

def standort(abdatum, andatum, ablongitudo, ablatitude, anlongitudo, anlatitude, abzeit, anzeit):
    radius = 6371
    
    # distance
    dlat = math.radians(anlatitude-ablatitude)
    dlon = math.radians(anlongitudo-ablongitudo)
    a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(ablatitude)) \
        * math.cos(math.radians(anlatitude)) * math.sin(dlon/2) * math.sin(dlon/2)
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
    d = (radius * c)
   
    # Funktion Standort
    if abdatum == andatum:
        if (ablongitudo and ablatitude) == (anlongitudo and anlatitude):
            return 'zuhause'
        
        elif (ablongitudo and ablatitude) != (anlongitudo and anlatitude):
            if d <= 0.1:
                return 'zuhause'
            else:
                return 'unterwegs'
    else:
        return 'unterwegs'
Leider gelingt es mir nicht, den ersten Abfahrtsort am Tag im Code zu erfassen, mit welchem ich die restlichen Zielorte über den Tag vergleichen kann. Wie kann ich entsprechend den ersten Abfahrsort am Tag (Längen-/Breitengrad) in der ersten Zeile "merken" und diesen dann mit den anderen Standorten in den nachfolgenden Zeilen vergleichen? Ich stehe hier völlig auf dem Schlauch, habe viel gelesen und gegoogelt und komme dennoch nicht weiter. Hat hier jemand eine zündende Idee?

Viele Grüße
Sebastian
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Auf den ersten Blick fällt auf, dass du das ``and`` wahrscheinlich falsch verstanden hast. Der Ausdruck

Code: Alles auswählen

(ablongitudo and ablatitude) == (anlongitudo and anlatitude)
prüft nicht ob ablongitudo=anlongitudo und ablatitude=anlatitude zutreffen, sondern testet, ob ablongitudo und ablatitude nicht 0 sind, ob anlongitudo und anlatitude nicht 0 sind und anschließend, ob die beiden Zwischenergebnisse übereinstimmen. Du meinst wahrscheinlich

Code: Alles auswählen

ablongitudo == anlongitudo and ablatitude == anlatitude
Am besten probierst du das mal schrittweise auf.

Hier liegt aber auch gleich schon der nächste Fehler. Floats solltest du niemals mit == vergleichen, da diese in der Regel Rundungsfehler enthalten und somit der Vergleich fast immer fehschlägt. Du solltest daher gegen einen kleinen Bereich testen. In deinem Fall möchtest du das so oder so tun, da "zu Hause" bereits unscharf mit 0.5 km definiert ist.

Weiter ist dein elif-Zweig problematisch. Zum einen meinst du wahrscheinlich else, zum anderen ist nicht garantiert, dass deine Funktion überhaupt ein Ergebnis liefert, wenn der elif-Zweig nicht betreten wird. Das ändert sich natürlich bei einem else.

Weiter solltest du keine Strings als Ergebnisse zurückgeben, sondern Konstanten definieren. Diese ermöglichen es dir dann auch, dass Ergebnis außerhalb der Funktion vernünftig zu verwenden. Auch solltest du die Berechnungen in mehrere Schritte teilen, wenn sie zu lang für eine Zeile werden. Oft lassen sich vernünftige Teilausdrücke bilden.

Sebastian
Das Leben ist wie ein Tennisball.
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Ich würde die Distanzberechnung noch in eine eigene Funktion auslagern. Das hat zum einen den Vorteil, dass dein Code thematisch besser aufgeteilt ist, und den anderen, falls die Berechnungsmethode sich mal ändern sollte, du nur die Funktion zur Berechnung ändern musst und nicht die standort-Funktion und evt. weitere Teile deines Codes.

Noch was fachspezifisches: Da du mit Latitude und Longitude Koordinaten rechnest, verwendest du wahrscheinlich das WGS84 Koordinatensystem. Da ist der Erdradius am Äquator mit 6378137m spezifiert, deiner ist 7km und ein bisschen zu klein :)
itchy_scratchy
User
Beiträge: 5
Registriert: Dienstag 24. April 2012, 13:19

Vielen Dank für die raschen Antworten! Ich habe die problematischen Felder mal korrigiert und den Code angepasst..

Leider bin ich bei deim Vergleich des morgendlichen Abfahrtsort und den täglichen Zielort noch nicht weiter gekommen. Ich habe in meiner Tabelle rund 3000 Zeilen mit Fahrten von verschiedenen Fahrzeugen an unterschiedlichen Tagen. Wie gelingt es, die Entfernungen der täglichen "Zielorte" mit dem morgendlichen Abfahrtsort zu vergleichen?

Da mir völlig der Ansatz fehlt, würde ich mich riesig über einen möglichen Lösungsvorschlag freuen!

Viele Grüße
Sebastian
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Ist der Abfahrtsort immer gleich? Denn eigentlich ist das eine klassische Many-to-Many Beziehung (m:n), wie sie in Datenbanken häufig vorkommt. Ein Abfahrtsort kann mehrere Ziele haben und ein Ziel kann von mehreren Abfahrtsorten angefahren werden.

Was ich machen würde, wäre eine Liste aller Abfahrtsorte erstellen und eine Liste aller Zielorte und dann ein kartesisches Produkt aus beiden Listen mit den Strecken berechnen. Itertools.product wäre eine möglicher Ansatz zur Berechnung. Das ganze dann pro PKW durchführen.

IMO würde sich der Einsatz einer Datenbank wie SQLite dafür anbieten. Eine Tabelle für die Fahrzeuge, eine für Orte und eine Relationstabelle, die Fahrzeuge und Orte, und einmal die Orte mit sich selbst verknüpft. Oder man verfolgt einen objektorientierten Ansatz, der ähnlich dem Datenbankschema aufgebaut ist. Eine Klasse für Fahrzeuge, eine für Orte, evt. noch eine für Strecken, die durch zwei Orte gekennzeichnet ist. Grundsätzlich sollte man die Problemdomain ordentlich durchstrukturieren, damit man den Überblick in der Menge der Daten nicht verliert.
itchy_scratchy
User
Beiträge: 5
Registriert: Dienstag 24. April 2012, 13:19

Leider stimmt der tägliche Abfahrtsort meist nie überein. Hier mal ein kleiner Auszug:

Fahrzeug abdatum abzeit abstrasse ablongitudo ablatitude andatum anzeit anstrasse anlongitudo anlatitude
21 20100628 1115 Seestraße 10.5643 49.7132 20110628 1125 Seestraße 9.56012 49.7152
21 20100628 1153 Seestraße 10.5597 49.7150 20110628 1153 Seestraße 9.55898 49.71513
21 20100628 1309 Seestraße 10.5590 49.7150 20110628 1311 Seestraße 10.56004 49.71521
21 20100628 1423 Seestraße 10.5597 49.7152 20110628 1427 Seestraße 10.55906 49.71495
21 20100628 1450 Seestraße 10.5584 49.7154 20110628 1501 Kreuzstrass 10.57995 49.68392
21 20100628 1524 Kreuzstraße 10.5800 49.6842 20110628 1545 Seestraße 10.55965 49.71533
91 20100714 0854 Karlstraße 8.8442 47.0183 20110714 0857 Karlstraße 8.84423 47.01825
91 20100714 0914 Karlstraße 8.8440 47.0181 20110714 0946 Guerickstraße 8.78944 47.0003
91 20100714 1011 Guerickestraße 8.7897 46.9989 20110714 1042 Bergstraße 8.84367 47.01857
91 20100714 1158 Bergstraße 8.8443 47.0182 20110714 1201 Karlstraße 8.84425 47.01821
91 20100714 1221 Karlstraße 8.8438 47.0181 20110714 1449 Karlstraße 8.84403 47.01872

Ich möchte es so definieren, dass automatisch die este Fahrt am Tag mit den darauffolgenden Fahrten verglichen werden kann. Die Frage ist nur, wie man dies in der obigen Funktionsdefinition einbaut?
BlackJack

@itchy_scratchy: Das baut man gar nicht in die obige Funktion ein. Du versuchst viel zu viel auf einmal zu lösen, statt das Problem immer weiter in kleine Teilprobleme aufzubrechen, die man dann einfach(er) lösen und testen kann, und deren Teillösungen eine Gesamtlösung ergeben.

Wenn Du die Daten tageweise betrachten möchtest, würde es sich doch zum Beispiel anbieten die Daten in Tage aufzuteilen. Zum Beispiel in dem man die Datensätze zu jedem einzelnen Tag in einer Liste zusammen fasst. Da kann man dann ganz trivial auf die ersten Abfahrts- und die letzten Ankunftskoordinaten zugreifen und die einer Funktion übergeben, die den Abstand in Kilometern berechnet.

Die verschiedenen Fahrzeuge müsste man da vielleicht auch noch trennen, oder? Also dass man so eine Struktur von Tageszusammenfassungen pro Fahrzeug hat und in einer entsprechenden Datenstruktur speichert. Einem Wörterbuch das Fahrzeugnummer auf die dazugehörigen Daten abbildet zum Beispiel.

Die einzelnen Datensätze könnte man auch jeweils in eine vernünftige Struktur stecken, so dass Koordinaten beispielsweise zu einem Wert zusammen gefasst werden. Und die Datumsangaben durch `datetime.datetime`-Werte repräsentiert werden. Insbesondere wenn die Datensätze nicht verändert werden sollen, würde sich zum Beispiel ein Typ der mit `collections.namedtuple()` erstellt wurde für die einzelnen Datensätze eignen.
frabron
User
Beiträge: 306
Registriert: Dienstag 31. März 2009, 14:36

Dein bisheriger Ansatz erscheint mir nicht geeignet, mit den Daten nach deinen Voraussetzungen arbeiten zu können. Ein erster Schritt, wie ich bereits oben schrieb, wäre es, dein CSV in eine geeignetere Datenstruktur zu überführen. Die Frage ist ja auch, ob in der CSV die Daten immer chronologisch vorliegen, oder ob erst noch nach dem Datum sortiert werden muss.

Ein kleiner Denkanstoss; ob das, gerade wegen dem Datum, in die richtige Richtung geht, musst du halt mal sehen:

Code: Alles auswählen

cars = [
    {
        'id': '21',
        'routes': [
            {
                'departure': {
                    'date': 20100628,
                    'time': 1115,
                    'street': 'Seestraße',
                    'lon': 10.5643,
                    'lat': 49.7132
                },
                'arrival': {
                    'date': 20110628,
                    'time': 1125,
                    'street': 'Seestraße',
                    'lon': 9.56012,
                    'lat': 49.7152
                }
            },
            {
                'departure': {},
                'arrival': {}
            }
        ]
    },
    {
        'id': '91',
        'routes': {}
    }
]

def distance(departure_locatin, arrival_location):
    """Harversine-Formel"""
    return a_distance

for car in cars:
    for route in car['routes']:
        print distance(route['departure'], route['arrival'])
Antworten