Wetterdaten: Datei schreiben nicht möglich

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.
Julu
User
Beiträge: 11
Registriert: Sonntag 18. Februar 2024, 15:01

Guten Tag,
ich möchte gern die Daten aus meiner Wetterstation speichern und auswerten. Diese als *.csv exportierten Daten haben ein etwas merkwürdiges Format, das ich hier leider nicht eingefügt bekomme. ich habe sie in meinem Online-Speicher hinterlegt, Zugriff mit https://c.1und1.de/@657946008252062578/ ... on6oO4CiDg
Die erste Zeile enthält die Spaltenüberschriften, in den folgenden Zeilen stehen die Daten, in die sehr viele NUL-Zeichen eingefügt sind. Ich öffne die Datei mit Kate und entferne die erste Zeile manuell, da ich bisher noch keine andere Möglichkeit gefunden habe. Die überflüssigen Zeichen bekomme ich mit diesem Programm heraus:

Code: Alles auswählen

wc_in_file = 'Weathercloud V832 2024-01.csv'
wc_out_file = 'WC_Out'
f1 = open(wc_data_file, 'rt')
f2 = open(wc_out_file, 'a')
line = f1.readline()
char_delete = line[0]
for line in f1:
    line = line.replace(char_delete, '')
    f2.write(line)
    print(line)
f1.close
f2.close
Die Zeile "print(line)" ist für mich die Kontrolle, ob das Entfernen geklappt hat. Die Datei "WC_Out" wird angelegt, es wird aber nichts hineingeschrieben, eine Fehlermeldung gibt es auch nicht. Schreiben und Lesen in dem Arbeitsverzeichnis funktioniert grundsätzlich, das habe ich mit einer einfachen Lese- und Schreiboperation geprüft. Als Newbie bin ich jetzt leider mit meinem Latein am Ende und hoffe auf einen Tipp, woran es liegen könnte, dass die verarbeiteten Daten nicht geschrieben werden.

Beste Grüße
Jürgen

Ich habe das Programm in einem Japyter-Notebook unter Visual Studio Code V1.86.2 mit Python 3.10.12 auf einem Linux-Rechner mit Tuxedo-OS (basiert auf ubuntu 22.04) erstellt
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

f1 und f2 sind schlechte Namen. Bitte gewöhn dir gleich an, vernünftige Namen zu vergeben.

Das Schließen der Dateien hat keine Wirkung, weil du die close-Methode nicht aufrufst. Denn dafür müssten () folgen.
Die ist aber auch überflüssig, weil man Dateien in Python mit with das Öffenen in einen Kontext schiebt und sich deshalb darüber keine Gedanken machen musst.

Warum entfernst du da irgendwelche Zeichen? Welches Encoding haben denn die Daten und warum gibst du das nicht an?

Das ist dem Namen nach ja CSV. Dafür gibt es das csv Modul.
Und da möchtest du dir den DictReader anschauen.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Beim Öffnen von Text-Dateien muß man immer das richtige Encoding angeben, bei Dir ist das "utf-16le".
Zum Lesen nimmt man dann csv.DictReader, dann hat man für die einzelnen Spalten auch gleich schöne Namen:

Code: Alles auswählen

import csv

def read_weather(filename):
    with open(filename, encoding='utf-16le') as file:
        return list(csv.DictReader(file, delimiter=";"))

def main():
    items = read_weather("Weathercloud V832 2024-01.csv")
    for item in items:
        print(item["Temperatur Innen (°C)"])

if __name__ == "__main__":
    main()
Benutzeravatar
snafu
User
Beiträge: 6743
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wobei ich ja nicht vorher alle Daten in eine Liste stecken, sondern den Iterator weiterverwenden würde:

Code: Alles auswählen

#!/usr/bin/env python3
import csv

FILENAME = "Weathercloud V832 2024-01.csv"


def read_weather(filename):
    with open(filename, encoding="UTF-16LE") as stream:
        yield from csv.DictReader(stream, delimiter=";")


def main():
    for item in read_weather(FILENAME):
        print(item["Temperatur Innen (°C)"])


if __name__ == "__main__":
    main()
Julu
User
Beiträge: 11
Registriert: Sonntag 18. Februar 2024, 15:01

Danke für eure Antworten, aber der Reihe nach:
Die Originaldatei braucht eine UTF16-Codierung, weil in der Titelzeile "oCelsius" verwendet wird. Bei den Datenzeilen ist mir aufgefallen, dass diese doppelt so viele wie angezeigte Zeichen enthalten. Diese zusätzlichen Zeichen werden nicht angezeigt, Python hat da nur rechteckige Kästchen angezeigt. Ich habe diesen Zeichen dann eingelesen und mit replace gegen nichts ('') ersetzt. Bei den Testdaten hat das auch funktioniert. Also war meine Überlegung, ich lese die Datei zeilenweise ein, entferne die überflüssigen Zeichen und kümmere mich dann um die weitere Verarbeitung. Das hat aber wie beschrieben nicht geklappt. Die Verarbeitung mit meinen code-Schnipseln klappt nur, wenn ich die Datei zuvor in LibreCalc als csv öffne und wieder speichere; dabei werden dann offenbar alle überflüssigen Zeichen entfernt. Das wäre dann der, leider etwas aufwendigere, Plan B, wenn eine direkte Verarbeitung nun gar nicht klappen sollte.
Mit dem Einlesen per csv-Funktion hatte ich mich nicht beschäftigt, weil ich - vermutlich falsch - davon ausgegangen bin, dass diese merkwürdigen Zeichen dabei auch nur Probleme verursachen würden.

Ich habe mir ein kleineres Testfile (Weasthercloud V832 2024-01_Teil.csv) manuell erzeugt, das nur die Titelzeile und vier weitere Datenzeilen enthält. Mit dem Code von snafu bekomme ich jetzt die Ausgabe in der Form "Spaltenname: Werte" hin, wobei allerdings nur drei der vier Zeilen angezeigt werden und am Ende eine Unicode-Fehlermeldung "UnicodeDecodeError: 'utf-16-le' codec can't decode byte 0x0a in position 0: truncated data" kommt. Hex 0a ist decimal 10 und damit ein line feed; der ist aber am Ende jeder Zeile vorhanden.
Da ich die erste Zeile ohnehin ersetzen möchte mit kürzeren Spaltennamen, z. B. ['Date/Time', 'TempIn', 'TempOut', 'Chill', 'DewIn', 'DewOut', 'HeatIn', 'HeatOut', 'HumIn', 'HumOut', 'WspHi', 'WspAvg', 'WDirAvg', 'Bar', 'Rain', 'RainRate', 'SolRad', 'UV'], stellt sich mir bei der csv.DictReader-Funktion die Frage, wie ich die erste Zeile überspringen kann. Und damit bin ich wieder bei meinem eingangs geschilderten Problem mit dem nicht erfolgreichen Schreiben der Datei. Ich habe es mit diesem Ansatz versucht,

Code: Alles auswählen

#!/usr/bin/env python3

FILENAME = "Weathercloud V832 2024-01_Teil.csv"
with open(FILENAME, encoding = 'UTF-16') as file_raw:
    for line in file_raw:
        print(line)
bekomme am Ende aber nur wieder einen Unicodeerror, diesmal "UTF-16 stream does not start with BOM". BOM, sagt mir die Recherche, ist Byte Order Mark und sollte bei UTF-16 entweder "FE FF" sein oder "FF FE", aber welche ist richtig und wie bekomme ich das in die Datei?

Ein zweiter Versuch mit

Code: Alles auswählen

#!/usr/bin/env python3
import csv

FILENAME = "Weathercloud V832 2024-01_Teil.csv"

with open(FILENAME, newline = '') as file_raw:
    data_read = csv.reader(file_raw, delimiter = ';')
    for row in data_read:
        print(row)
produziert auch wieder einen Unicode-Fehler "UnicodeDecodeError: 'utf-8' codec can't decode byte 0xb0 in position 80: invalid start byte". Die Option "encoding" ist für csv.reader nicht vorgesehen. Habt ihr noch eine Idee, wie ich das angehen könnte?

Beste Grüße
Jürgen
Benutzeravatar
__blackjack__
User
Beiträge: 13116
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Julu: Man *braucht* für das Grad-Celsius-Zeichen kein UTF-16. Da gehen auch andere Kodierungen, beispielsweise UTF-8.

Du Unterscheidest nicht sauber zwischen Bytes und Zeichen in Deiner Beschreibung. Die Datei enthält nicht doppelt so viele Zeichen „wie angezeigt werden“, sondern sie enthält doppelt so viele Bytes wie Zeichen, weil immer zwei Bytes ein Zeichen beschreiben. (Ist etwas vereinfacht, weil es auch Zeichen gibt die in UTF-16 mit mehr als zwei Bytes kodiert werden, aber hier sehr wahrscheinlich nicht vorkommen in der Datei.)

Python hat nirgends Rechtecke angezeigt. Du hast die Datei mit der falschen Kodierungsangabe geöffnet und dann irgendwo ausgegeben, beispielsweise einem Terminal, und *dieses* Programm hat dann Kästchen angezeigt.

Beim Code von Snafu fehlt ein ``newline=""``-Argument beim öffnen der Datei.

UTF-16 erwartet die BOM-Sequenz. Wenn die nicht vorhanden ist, muss man die Endianess explizit angeben, eben UTF-16LE.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Julu
User
Beiträge: 11
Registriert: Sonntag 18. Februar 2024, 15:01

@__blackjack__
Danke für die Klarstellung hinsichtlich UTF-16, diese 2-Byte-Darstellung hat mich doch etwas verwirrt.
Mit diesem Programm bekomme ich jetzt die Daten korrekt angezeigt

Code: Alles auswählen

#!/usr/bin/env python3
import csv

FILENAME = "Weathercloud V832 2024-01_Teil.csv"

with open(FILENAME, newline = '', encoding = 'UTF-16LE') as file_raw:
    data_read = csv.reader(file_raw, delimiter = ';')
    for row in data_read:
        print(row)
Wenn ich die Datei neu schreibe, kann ich jetzt die erste Zeile einfach weglassen. Noch eine generelle Frage: Weiter oben war gesagt worden, dass dem Öffnen von Dateien mit "with" der Vorzug zu geben sei. Wenn ich jetzt also in einer inneren Schleife eine neue Datei zum Schreiben öffne und die aktuelle Zeile dorthin schreibe, dann schließt sich diese neue Datei vor dem Aufruf der äußeren Schleife ja wieder. Wäre es in einem solchen Fall nicht besser, beide Dateien offen zu halten und erst am Ende des Vorgangs zu schließen?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du kannst auch problemlos zwei Dinge gleichzeitig mit with oeffnen:

Code: Alles auswählen

with open(..) as input_file, open(..) as output_file:
     output_file.write(input_file.read())
Ist natuerlich nur exemplarisch. Aber selbst verschachtelt geht es:

Code: Alles auswählen

with open(..) as input_file:
    with open(..) as output_file:
         for line in input_file:
               output_file.write(line)
Julu
User
Beiträge: 11
Registriert: Sonntag 18. Februar 2024, 15:01

Lesen der Daten klappt jetzt, aber leider nicht das Schreiben. Ich bekomme hiermit

Code: Alles auswählen

#!/usr/bin/env python3
import csv

WC_OUT = 'WC_Out.csv'
WC_IN = "Weathercloud V832 2024-01_Teil.csv"

fieldname = ['Date/Time', 'TempIn', 'TempOut', 'Chill', 'DewIn', 'DewOut', 'HeatIn', \
                'HeatOut', 'HumIn', 'HumOut', 'WspHi', 'WspAvg', 'WDirAvg', \
                'Bar', 'Rain', 'RainRate', 'SolRad', 'UV']

with open(WC_IN, newline = '', encoding = 'UTF-16LE') as file_raw, \
        open(WC_OUT, newline = '', encoding = 'UTF-8') as file_out:
    data_read = csv.reader(file_raw, delimiter = ';')
    data_write = csv.writer(file_out, delimiter = ';', quotechar='|', quoting = csv.QUOTE_NONNUMERIC )
    data_write.writerow(fieldname)
    for row in data_read:
        if row[0] != 'Datum (Europe/Berlin)':
            print(row)
            data_write.writerow(row)
die Fehlermeldung, dass die Zeilen "data_write.writerow(fieldname)" oder auch "data_write.writerow(row)" nicht geschrieben werden können ("not writable"). Aber ich finden den Fehler einfach nicht...
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Bitte den vollständigen Stscktrace. Keine Prosa aus der Erinnerung.
Julu
User
Beiträge: 11
Registriert: Sonntag 18. Februar 2024, 15:01

Bitte den vollständigen Stscktrace
Damit

Code: Alles auswählen

#!/usr/bin/env python3[quote=sparrow post_id=427304 time=1708713645 user_id=8490]
Bitte den vollständigen Stscktrace.
[/quote]
import csv

WC_OUT = 'WC_Out.csv'
WC_IN = "Weathercloud V832 2024-01_Teil.csv"

fieldname = ['Date/Time', 'TempIn', 'TempOut', 'Chill', 'DewIn', 'DewOut', 'HeatIn', \
                'HeatOut', 'HumIn', 'HumOut', 'WspHi', 'WspAvg', 'WDirAvg', \
                'Bar', 'Rain', 'RainRate', 'SolRad', 'UV']

with open(WC_IN, newline = '', encoding = 'UTF-16LE') as file_raw, \
        open(WC_OUT, newline = '', encoding = 'UTF-8') as file_out:
    data_read = csv.reader(file_raw, delimiter = ';')
    data_write = csv.writer(file_out, delimiter = ';', quotechar='|', quoting = csv.QUOTE_NONNUMERIC )
    data_write.writerow(fieldname)
    for row in data_read:
        if row[0] != 'Datum (Europe/Berlin)':
            print(row)
            data_write.writerow(row)
gibt es diese Fehlermeldung

Code: Alles auswählen

{
	"name": "UnsupportedOperation",
	"message": "not writable",
	"stack": "---------------------------------------------------------------------------
UnsupportedOperation                      Traceback (most recent call last)
/tmp/ipykernel_22780/1824221238.py in <module>
     13     data_read = csv.reader(file_raw, delimiter = ';')
     14     data_write = csv.writer(file_out, delimiter = ';', quotechar='|', quoting = csv.QUOTE_NONNUMERIC )
---> 15     data_write.writerow(fieldname)
     16     for row in data_read:
     17         if row[0] != 'Datum (Europe/Berlin)':

UnsupportedOperation: not writable"
}
Der andere, zitierte Fehler folgt auf diese Programmversion

Code: Alles auswählen

#!/usr/bin/env python3
import csv

WC_OUT = 'WC_Out.csv'
WC_IN = "Weathercloud V832 2024-01_Teil.csv"

fieldname = ['Date/Time', 'TempIn', 'TempOut', 'Chill', 'DewIn', 'DewOut', 'HeatIn', \
                'HeatOut', 'HumIn', 'HumOut', 'WspHi', 'WspAvg', 'WDirAvg', \
                'Bar', 'Rain', 'RainRate', 'SolRad', 'UV']

with open(WC_IN, newline = '', encoding = 'UTF-16LE') as file_raw, \
        open(WC_OUT, newline = '', encoding = 'UTF-8') as file_out:
    data_read = csv.reader(file_raw, delimiter = ';')
    data_write = csv.writer(file_out, delimiter = ';', quotechar='|', quoting = csv.QUOTE_NONNUMERIC )
    #data_write.writerow(fieldname)
    for row in data_read:
        if row[0] != 'Datum (Europe/Berlin)':
            print(row)
            data_write.writerow(row)

Code: Alles auswählen

['2024-01-01 00:00:00', '20,2', '7', '6,1', '', '4,6', '', '', '50', '85', '5,4', '5', '112', '1.015,5', '0', '0', '', '', '']
{
	"name": "UnsupportedOperation",
	"message": "not writable",
	"stack": "---------------------------------------------------------------------------
UnsupportedOperation                      Traceback (most recent call last)
/tmp/ipykernel_22780/3710469160.py in <module>
     17         if row[0] != 'Datum (Europe/Berlin)':
     18             print(row)
---> 19             data_write.writerow(row)
     20 

UnsupportedOperation: not writable"
}
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Dateien muss man zum Schreiben auch mit dem richtigen Modus öffnen: "w".
Julu
User
Beiträge: 11
Registriert: Sonntag 18. Februar 2024, 15:01

Sirius3 hat geschrieben: Freitag 23. Februar 2024, 22:12 Dateien muss man zum Schreiben auch mit dem richtigen Modus öffnen: "w".
Klarer Fall von Anfängerfehler :oops: , hatte ich mir schon gedacht, dass es in die Richtung geht. Aber manchmal sehe ich denn Wald vor lauter Bäumen nicht.
Jetzt läuft es jedenfalls, nochmals Danke für eure Hilfestellung
Julu
User
Beiträge: 11
Registriert: Sonntag 18. Februar 2024, 15:01

Nachdem jetzt die Daten in eine besser lesbare Form gebracht sind, tut sich beim Import nach Pandas das nächste Problem auf: Die Spaltenüberschriften und die Daten passen nicht zusammen.
Die Daten liegen in diesem Format in WC_Out.csv vor:

Code: Alles auswählen

DateTime;TempInW;TempOut;Chill;DewIn;DewOut;HeatInW;HeatOut;HumInW;HumOut;WspHi;WspAvg;WDirAvg;Bar;Rain;RainRate;SolRad;UV
2021-12-12 21:20:00;22,5;7,8;7,8;;7,2;;;45;96;0,9;0,9;158;1.039,2;4,8;0,8;;;
2021-12-12 21:30:00;20,4;7,9;7,9;;7,3;;;45;96;0;0;158;1.039,3;4,8;0,8;;;
2021-12-12 21:40:00;19,8;8;8;;7,4;;;49;96;0,8;0,8;225;1.039,3;4,8;0,8;;;
Import nach Pandas habe ich so formuliert

Code: Alles auswählen

#!/usr/bin/env python3
import pandas as pd
file_import = 'WC_Out.csv'
temp_data = pd.read_csv(file_import, sep = ';', dayfirst = False)
temp_data.head()
Und das wird mir angezeigt

Code: Alles auswählen

                    DateTime TempInW TempOut  Chill DewIn  DewOut  HeatInW  \
2021-12-12 21:20:00     22,5     7,8     7,8    NaN   7,2     NaN      NaN   
2021-12-12 21:30:00     20,4     7,9     7,9    NaN   7,3     NaN      NaN   
2021-12-12 21:40:00     19,8       8       8    NaN   7,4     NaN      NaN   
2021-12-12 21:50:00     19,7     8,1     8,1    NaN   7,5     NaN      NaN   
2021-12-12 22:00:00     19,7     8,1     8,1    NaN   7,5     NaN      NaN   

                     HeatOut  HumInW HumOut WspHi  WspAvg  WDirAvg  Bar Rain  \
2021-12-12 21:20:00     45.0    96.0    0,9   0,9   158.0  1.039,2  4,8  0,8   
2021-12-12 21:30:00     45.0    96.0      0     0   158.0  1.039,3  4,8  0,8   
2021-12-12 21:40:00     49.0    96.0    0,8   0,8   225.0  1.039,3  4,8  0,8   
2021-12-12 21:50:00     49.0    96.0      0     0   202.0  1.039,4  4,8  0,8   
2021-12-12 22:00:00     50.0    96.0    0,5   0,5   225.0  1.039,3  4,8    0   

                     RainRate  SolRad  UV  
2021-12-12 21:20:00       NaN     NaN NaN  
2021-12-12 21:30:00       NaN     NaN NaN  
2021-12-12 21:40:00       NaN     NaN NaN  
2021-12-12 21:50:00       NaN     NaN NaN  
2021-12-12 22:00:00       NaN     NaN NaN  
Die Spaltennamen sind eine Position nach rechts versetzt. Ich habe bisher keinen Weg gefunden, das zu korrigieren und hoffe auf Hinweise.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei Deinen Daten haben die Zeilen unterschiedlich viele Spalten; normalerweise meckert da pandas, weil es nicht weiß, wie es damit umgehen soll, warum sich hier pandas aber so komisch verhält kann ich aber nicht sagen.
Der Grund ist aber eindeutig, Deine Daten sind kaputt.
Warum ersetzt Du überhaupt die schönen Spaltenüberschriften, die in den Originaldaten vorhanden sind, durch diesen kryptischen Schrott?
Julu
User
Beiträge: 11
Registriert: Sonntag 18. Februar 2024, 15:01

Sirius3 hat geschrieben: Sonntag 25. Februar 2024, 18:35 Bei Deinen Daten haben die Zeilen unterschiedlich viele Spalten...
Ich habe die Überschriften und Spalten jetzt mehrfach nachgezählt und komme immer auf 18 per Semikolon getrennte Spalten. Was übersehe ich denn?
Sirius3 hat geschrieben: Sonntag 25. Februar 2024, 18:35 Warum ersetzt Du überhaupt die schönen Spaltenüberschriften, die in den Originaldaten vorhanden sind, durch diesen kryptischen Schrott?
Nun ja, in einer Grafik ist der für die Überschriften nötige Platz begrenzt und die angedachte Auswertung wird sich auch einfacher gestalten lassen, wenn die Feldnamen nicht endlos lang sind.
juwido
User
Beiträge: 20
Registriert: Donnerstag 15. Dezember 2022, 13:41

Die Zeile mit den18 Spaltenüberschriften hat 17 Semikolon, die Datenzeilen haben 18...
Benutzeravatar
sparrow
User
Beiträge: 4195
Registriert: Freitag 17. April 2009, 10:28

Also werden die Daten gelesen, die Überschriften werden kryptischer Mumpitz und das Format geht dadurch kaputt.
Also insgesamt ein Vorgang, den man sich komplett sparen kann. Denn man kann ja die Urprungsdaten ebenso Pandas einlesen - und spart sich den Zwischenschritt, der in diesem Fall auch noch kaputt ist.
Benutzeravatar
DeaD_EyE
User
Beiträge: 1021
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Bleib bei der Standardbibliothek und lerne, wie man das mit dem CSV-Modul macht.
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Julu hat geschrieben: Sonntag 25. Februar 2024, 19:11 Nun ja, in einer Grafik ist der für die Überschriften nötige Platz begrenzt und die angedachte Auswertung wird sich auch einfacher gestalten lassen, wenn die Feldnamen nicht endlos lang sind.
Das ist dann bestenfalls ein Grund, die in der Anzeige anders zu benennen. Keiner, die Daten wieder (kaputt gespielt) abzuspeichern.
Antworten