Dictionary

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
Julien456935
User
Beiträge: 19
Registriert: Donnerstag 22. November 2018, 15:26

Hallo Leute,
im Grunde habe ich nur eine kurze spezifische Frage bezüglich einer Funktion die mir ein Dictionary erstellt.
Die Funktion:

Code: Alles auswählen

def dicts_2():
    with open("data.csv") as csv_file:
        health_profile = {}
        keys = csv_file.readline().strip().split(",")[1:]
        for line in csv_file:
            name, *patient_data = line.strip().split(",")
            health_profile[name] = {}
            health_profile[name][keys[0]] = patient_data[0]
            health_profile[name][keys[1]] = patient_data[1]
            health_profile[name][keys[2]] = int(patient_data[2].split()[0])
            health_profile[name][keys[3]] = float(patient_data[3].split()[0])
Die Funktion erstellt mir ein Dictionary der Art:
health_profile = {"Max": {"Birth state": "Bayern", "Gender": "Male", "Resting Heart Rate": 74, "Red blood cell count": 4.33}, "Omar": {...}, ...}

aus der Tabelle:
Name Birth state Gender Resting Heart Rate Red blood cell count
Florian Upper Austria Male 60 bpm 5.2 trillion cells/L
Yasmine Bayern Female 50 bpm 4.9 trillion cells/L
Max Bayern Male 74 bpm 4.33 trillion cells/L
Omar Virginia Male 78 bpm 4.67 trillion cells/L

Die Tabelle ist jetzt nicht wichtig.

Was ich nicht verstehe ist diese Zeile:
name, *patient_data = line.strip().split(",")

*patient_data = line.strip().split(",") sagt doch, dass die Variable "patient_data" = die Zeile bei jedem "," gesplittet und von allen Leerzeichen (strip()) entfernt? wie passt "name," da hinein??
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@Julien456935: Du solltest Dir csv.DictReader anschauen:

Code: Alles auswählen

with open("data.csv") as csv_file:
    lines = csv.DictReader(csv_file)
    health_profile = {}
    for entry in lines:
        name = entry.pop('Name')
        entry['Resting Heart Rate'] = int(entry['Resting Heart Rate'].split()[0])
        entry['Red blood cell count'] = float(entry['Red blood cell count'].split()[0])
        health_profile[name] = entry
`dicts_2` ist für einen Funktionsnamen sehr schlecht. Funktionen sollten nach Tätigkeiten benannt sein, und wenn man Funktionen durchnummeriert ist die Funktion nicht spezifisch genug.

`name, *patient_data` heißt unpacking, wo das erste Element eines iterierbaren Objekts an name gebunden und der Rest in patient_data geschrieben wird.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

split() liefert ja die einzelnen Textstücke. Das erste Stück wird hier an name gebunden, alle weiteren Stücke an patient_data. Man könnte auch alles an patient_data binden oder umgekehrt die einzelnen Bestandteile aufzählen:

Code: Alles auswählen

name, birth_state, gender, ... = line.strip().split(',')
Der vorgeschlagene DictReader ist hier aber besser geeignet.
Julien456935
User
Beiträge: 19
Registriert: Donnerstag 22. November 2018, 15:26

@Sirius3 : Danke deine Erklärung hat mir sehr geholfen!
Die Funktion war eine reine Übungsaufgabe und der Name war für einen Autotest so gegeben.
Ich werde mir das csv Module mal näher ansehen im Moment ist es mir verboten dieses zu importieren.

Angenommen ich habe keine csv sondern die Daten wären eine mit numpy erstellte Matrix:
Dann würde ich die werte in der ersten spalte wieder an "name" binden, der Rest allerdings wird übergeben.
name, *patient_data = line
Wäre dann patient_data der Rest der line als Matrix?
Splitten muss ich ja gar nicht, weil in eine Matrix ja nur Elemente vorhanden sind?
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Julien456935: Die Daten eignen sich so nicht für eine Numpy-Matrix weil nicht alle Zellen den gleichen Datentyp haben.

`patient_data` wäre wegen dem * eine Liste. Was auf der rechten Seite des ``=`` für ein Typ steht ist egal solange es iterierbar ist.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@Julien456935: Wenn der Input eine numpy-Matrix wäre (besser numpy structured array, oder irgendwas mit Pandas), dann würde man direkt mit diesen Daten arbeiten und nicht in irgendeine andere Struktur konvertieren. Das kommt aber auch ein bißchen darauf an, wie man die Daten weiter verarbeiten möchte.
Julien456935
User
Beiträge: 19
Registriert: Donnerstag 22. November 2018, 15:26

Okay,
Fazit ich kann eine Matrix oder Dictionary als innere Struktur betrachten und die Daten dann weiterverarbeiten.
Eine Matrix zu erschaffen war relativ einfach und ich denke ich werde diese wählen.
Alternativ (jetzt auch nur zum Verständnis) habe ich probiert anhand eines anderen Bsp ein Dictionary wie oben zu erschaffen, hier der code:

Code: Alles auswählen

Beispielcode

data = [['2782', 'SDS011', '1399', '47.07', '15.45', '2018-08-31 23:59:58', '12.68', '11.38\n'],
        ['2782', 'SDS011', '1399', '47.07', '15.45', '2018-08-31 12:16:23', '10.25', '7.80\n'],
        ['2782', 'SDS011', '1399', '47.07', '15.45', '2018-08-31 11:51:42', '9.13', '7.47\n'],
        ['1747', 'SDS011', '871', '47.03', '15.39', '2018-07-23 19:07:02', '11.97', '10.87\n'],
        ['1747', 'SDS011', '871', '47.03', '15.39', '2018-07-23 18:04:21', '10.53', '9.57\n'],
        ['1747', 'SDS011', '871', '47.03', '15.39', '2018-07-23 17:39:45', '11.90', '10.60\n']]

sensors = {}                                                                     #empty Dictionary named sensors  
keys = ["sensor_id","sensor_type","location","lat","lon","timestamp","P1","P2"]
for line_of_values in data:                                
    sensor_id, *values = line_of_values                    
    sensors[sensor_id] = {}                                
    sensors[sensor_id][keys[3]] = values[2]
    sensors[sensor_id][keys[4]] = values[3]
    sensors[sensor_id][keys[1]] = values[0]
    data = "data"
    sensors[sensor_id][data] = {}
    sensors[sensor_id][data][keys[5]] = values[4]
    sensors[sensor_id][data][keys[6]] = float(values[5])
    sensors[sensor_id][data][keys[7]] = float(values[6])
    print(sensors)
nur dieses mal wollte ich mal eine liste von listen verwenden, ist ja das gleiche wie Zeilen einer csv.
Allerdings stimmt hier irgendetwas mit der For_schleife nicht. Denn der Ausdruck lautet:

{'2782': {'lat': '47.07', 'lon': '15.45', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-08-31 23:59:58', 'P1': 12.68, 'P2': 11.38}}}
{'2782': {'lat': '47.07', 'lon': '15.45', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-08-31 12:16:23', 'P1': 10.25, 'P2': 7.8}}}
{'2782': {'lat': '47.07', 'lon': '15.45', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-08-31 11:51:42', 'P1': 9.13, 'P2': 7.47}}}
{'2782': {'lat': '47.07', 'lon': '15.45', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-08-31 11:51:42', 'P1': 9.13, 'P2': 7.47}}, '1747': {'lat': '47.03', 'lon': '15.39', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-07-23 19:07:02', 'P1': 11.97, 'P2': 10.87}}}
{'2782': {'lat': '47.07', 'lon': '15.45', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-08-31 11:51:42', 'P1': 9.13, 'P2': 7.47}}, '1747': {'lat': '47.03', 'lon': '15.39', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-07-23 18:04:21', 'P1': 10.53, 'P2': 9.57}}}
{'2782': {'lat': '47.07', 'lon': '15.45', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-08-31 11:51:42', 'P1': 9.13, 'P2': 7.47}}, '1747': {'lat': '47.03', 'lon': '15.39', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-07-23 17:39:45', 'P1': 11.9, 'P2': 10.6}}}


Die rot geschriebenen Einträge sind alle zu viel. Diese roten Einträge sind alle gleich, ich verstehe also, dass in der for-Schleife irgendetwas nicht Stimmt, finde den Fehler aber nicht, da der erste Teil ja stimmt! Ändert sich die sensor_id läuft etwas falsch...🧐
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Julien456935: Du erstellst halt *einmal* das Wörterbuch `sensors` und schreibst dann da alle Daten rein. Also in den ersten drei Durchläufen die für den Sensor 2782 und die überschreiben immer die Werte aus dem vorherigen Schleifendurchlauf. Und dann fängst Du an die Daten für den anderen Sensor in das Wörterbuch zu schreiben. Und erwartest anscheinend das die Daten für den 2782-Sensor auf magische Weise aus dem Wörterbuch verschwinden. Warum erwartest Du das? Welcher Codeteil in Deinem Programm sollte das bewirken?
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

Du gibst immer das gesamte Wörterbuch aus, das Du halt immer erweiterst, bzw. Schlüssel überschreibst.

Statt jeden Wert einzeln zuzuweisen, bau Dein Wörterbuch direkt:

Code: Alles auswählen

sensors = {}
for values in data:
    sensors[values[0]] = {
        "lat": values[3],
        "lon": values[4],
        "sensor_type": values[1],
        "data": {
            "timestamp": values[5],
            "P1": float(values[6]),
            "P2":float(values[7]),
        }
    }
print(sensors)
Julien456935
User
Beiträge: 19
Registriert: Donnerstag 22. November 2018, 15:26

@__blackjack__ :" in den ersten drei Durchläufen die für den Sensor 2782 und die überschreiben immer die Werte aus dem vorherigen Schleifendurchlauf"--> wie ist das gemeint die ersten drei Zeilen Unterscheiden sich in den letzten Werten und werden doch nicht überschrieben?? In der Liste der Daten ändert sich lediglich der key und dieser wird doch jede Zeile neu herausgefiltert?

@Sirius3 : Deine Version ist natürlich viel leichter und eh viel verständlicher, das Problem bleibt aber das selbe...

Code: Alles auswählen

data = [['2782', 'SDS011', '1399', '47.07', '15.45', '2018-08-31 23:59:58', '12.68', '11.38\n'],
        ['2782', 'SDS011', '1399', '47.07', '15.45', '2018-08-31 12:16:23', '10.25', '7.80\n'],
        ['2782', 'SDS011', '1399', '47.07', '15.45', '2018-08-31 11:51:42', '9.13', '7.47\n'],
        ['1747', 'SDS011', '871', '47.03', '15.39', '2018-07-23 19:07:02', '11.97', '10.87\n'],
        ['1747', 'SDS011', '871', '47.03', '15.39', '2018-07-23 18:04:21', '10.53', '9.57\n'],
        ['1747', 'SDS011', '871', '47.03', '15.39', '2018-07-23 17:39:45', '11.90', '10.60\n']]

sensors = {}
for values in data:
    sensors[values[0]] = {
        "lat": values[3],
        "lon": values[4],
        "sensor_type": values[1],
        "data": {
            "timestamp": values[5],
            "P1": float(values[6]),
            "P2":float(values[7]),
        }
    }
    print(sensors)
mit dem Unterschied das ich print(sensor) in die Schleife gebe, da ich ja im Grunde von jeder Zeile ein Dictionary möchte und es dann in Sensors packe... ich versuch jetzt mal in der for Schleife nur aus jeder Zeile/Element in der Data ein Dictionary zu erstellen und dann außerhalb in Sensors zu packen... am ende der Schleife müsste doch eigentlich "Sensors.update" auch gehen ist doch das selbe wie ".append" bei listen...
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Julien456935: Im ersten Durchlauf wird der Schlüssel '2782' mit den Werten in das Wörterbuch eingetragen. Und in den nächsten beiden Durchläufen werden diese Werte ersetzt, also überschrieben. Im vierten Durchlauf sind dann noch die Werte für '2782' aus dem dritten Durchlauf im Wörterbuch und Du legst noch den Schlüssel '1747' mit den Werten an. Die dann im 5. und 6. Durchlauf dann wie am Anfang mit dem ersten Schlüssel, ersetzt werden.

Die Frage ist was Du überhaupt haben möchtest. Ein Wörterbuch pro Datensatz? Dann solltest Du halt auch tatsächlich ein Wörterbuch pro Datensatz erstellen und nicht das selbe für alles immer wieder zu verwenden. Oder alle Daten sollen in *einem* Wörterbuch landen, dann musst Du irgendwie damit umgehen, dass mehr als ein Wert pro Schlüssel in den Ausgangsdaten vorhanden ist. Da könnte `collections.defaultdict` und `list` interessant sein.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Julien456935
User
Beiträge: 19
Registriert: Donnerstag 22. November 2018, 15:26

@__blackjack__ : habs in gerade in diesem Augenblick hinbekommen🤘

Code: Alles auswählen

data = [['2782', 'SDS011', '1399', '47.07', '15.45', '2018-08-31 23:59:58', '12.68', '11.38\n'],
        ['2782', 'SDS011', '1399', '47.07', '15.45', '2018-08-31 12:16:23', '10.25', '7.80\n'],
        ['2782', 'SDS011', '1399', '47.07', '15.45', '2018-08-31 11:51:42', '9.13', '7.47\n'],
        ['1747', 'SDS011', '871', '47.03', '15.39', '2018-07-23 19:07:02', '11.97', '10.87\n'],
        ['1747', 'SDS011', '871', '47.03', '15.39', '2018-07-23 18:04:21', '10.53', '9.57\n'],
        ['1747', 'SDS011', '871', '47.03', '15.39', '2018-07-23 17:39:45', '11.90', '10.60\n']]

sensors ={}


for values in data:
    sensors = {values[0] : {
        "lat": values[3],
        "lon": values[4],
        "sensor_type": values[1],
        "data": {
            "timestamp": values[5],
            "P1": float(values[6]),
            "P2":float(values[7]),
        }
    }}
    print(sensors)
mit der Ausgabe:

{'2782': {'lat': '47.07', 'lon': '15.45', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-08-31 23:59:58', 'P1': 12.68, 'P2': 11.38}}}
{'2782': {'lat': '47.07', 'lon': '15.45', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-08-31 12:16:23', 'P1': 10.25, 'P2': 7.8}}}
{'2782': {'lat': '47.07', 'lon': '15.45', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-08-31 11:51:42', 'P1': 9.13, 'P2': 7.47}}}
{'1747': {'lat': '47.03', 'lon': '15.39', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-07-23 19:07:02', 'P1': 11.97, 'P2': 10.87}}}
{'1747': {'lat': '47.03', 'lon': '15.39', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-07-23 18:04:21', 'P1': 10.53, 'P2': 9.57}}}
{'1747': {'lat': '47.03', 'lon': '15.39', 'sensor_type': 'SDS011', 'data': {'timestamp': '2018-07-23 17:39:45', 'P1': 11.9, 'P2': 10.6}}}


Es funktioniert aber alles was ich verändert habe ist der Teil mit der sensor_id als key... werd mir das jetzt nochmal genau durchschauen, aber danke wieder an alle!!
Für meine Aufgabe werd ich eh die Matrix verwenden😂 , wollte nur den Fehler finden😅
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

@Julien456935: Du hast keinen Fehler, sondern nur ein Verständnisproblem. In Deinem neusten Code ist das äußere Wörterbuch sinnlos, da es immer nur einen Schlüssel enthält. Die Belegung von `sensors` vor der Schleife ist auch überflüssig, weil Du es in der Schleife überschreibst.
Jetzt hast Du nur eine Ausgabe, verwirfst die Daten aber gleich wieder.
Julien456935
User
Beiträge: 19
Registriert: Donnerstag 22. November 2018, 15:26

@Sirius3: Stimmtaber dann müsste ich doch statt mit print jede Zeile auszugeben mit ".update()" zusammenfassen können? Wenn ich mit eine For-Schleife Listen bearbeite, dann kann ich mittels dem Befehl ".append()" einer leeren Liste das gewünschte Element hinzufügen. Ich habs mit update bei Dictionarys mal probiert aber würde nicht auf das gewünschte Ergebnis kommen.
Dass Sensors = {} unnötig ist ist mir nun klar und auch der Unterschied zu deinem Code👍. Ich bräuchte aber zum Beispiel alle Zeilen als Dictionary außerhalb der For-Schleife, in deiner Version bekomme ich nur alle wenn das "print(sensors)" in der for-Schleife drinnen steckt. Deshalb wäre meine Idee jede Zeile zu einem Dictionary zu verwandeln und "Sensors" hinzuzufügen. ".update" schein allerdings bisschen anders als "Append" zu funktionieren...
Sirius3
User
Beiträge: 17748
Registriert: Sonntag 21. Oktober 2012, 17:20

Den Unterschied zwischen Listen und Wörterbüchern hat Dir __blackjack__ doch schon erklärt.
Ein Wörterbuch ist falsch, wenn Du zu einem Sensor mehrere Werte haben möchtest. Listen im Wörterbuch wären eine Lösung.
Antworten