"VLookUp" von Dataframes, falsches Datenformat beim Schreiben eines CSV

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
Antworten
andreas96
User
Beiträge: 11
Registriert: Montag 7. September 2020, 08:27

Ich ordne über einen Index Daten, mit der merge Funktion zu, sozusagen einem "VLookUp" in pandas, danach füge ich in einem weiteren Schritt einen siebenzeiligen Kopf ein. Beim Anzeigen des Dataframe "result" im IDE-Window sind noch alle Zahlen richtig dargestellt. Nach dem Schreiben als csv werden einge Zeilen als Datum angezeigt, andere enthalten eine weitere Stelle angehängt, so bspw. beim Programmnamen oder beim Hauptstrom.
Versucht habe ich ich die Zuweisung über astype, dtype, as_numeric usw. dies sowohl zeilenweise oder auf den gesamten Dataframe. Dies auch schon beim Lesen und beim Schreiben der Dateien. Was mache ich falsch? Wie wandle ich richtigerweise den Datentyp "object" um.
Hilfe wäre toll! Gruß Andreas

Code: Alles auswählen

import pandas as pd
import os

os.chdir("C:/DATA/daten/")  # setting working directory.
quelle_path = r'C:\DATA\quelle.xlsx'
quelle_prgheader = r'C:\DATA\header.xlsx'
prg_path = r'C:\DATA\programm.xlsx'

def dataframes_merge():
    global df3
    global result
    df1 = pd.read_excel(prg_path)
    df2 = pd.read_excel(quelle_path) # dtype={'Programmname':int}
    df1.head()
    df2.head()

    df3 = df1.merge(df2, on='index', how='left')
    df4 = pd.read_excel(quelle_prgheader)

    result = pd.concat([df4, df3])

dataframes_merge()
print(result
print(result.dtypes)

# result.to_csv(str(file) + '.csv', sep=";" ,decimal=",", index=False, header=False, date_format=None)
# result.to_excel((str(file) + '.xlsx'), header=False, index=False)
result.to_excel(('Testfile'.xlsx'), header=False, index=False)
Link zu den drei xlsx-Dateien Quelle, Programm und Header:
https://1drv.ms/u/s!AiFbEUFIX3kVjM8etFc ... g?e=i9N49y
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

Der Code ist so gar nicht lauffährig, in der letzten Zeile ist ein Systaxfehler. Zwischendurch fehlen Klammern.

Globale Varaiablen sollte man nicht benutzen, alle Variablen die eine Funktion benötigt bekommt diese über Parameter und geben ein Ergebnis mittels return zurück.

os.chdir() sollte nicht benutzt werden. Benutze absolute Pfade, am besten mit dem pathlib Modul.

Auf Modulebene sollten nur Konstanten stehen und der if __name__ == '__main__': Aufruf, der die main() aufruft und dort drin sollte dann dein Programm laufen.

Variablen sollte man ausschreiben und nicht abkürzen.
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

Benutze kein os.chdir, weil es globalen Zustand ändert. Brauchst Du auch gar nicht, weil alle Deine Pfade absolut sind.
Benutze auch kein `global`. Werte werden per `return` zurückgegeben. Benutze keine Abkürzungen. Die head-Aufrufe sind ohne Effekt.
Excel ist nicht wirklich gut darin, csv-Dateien zu lesen.
Wie sehen Deine Daten aus?

Code: Alles auswählen

import pandas as pd
quelle_path = r'C:\DATA\quelle.xlsx'
quelle_programm_header_path = r'C:\DATA\header.xlsx'
programm_path = r'C:\DATA\programm.xlsx'

def dataframes_merge():
    programm = pd.read_excel(programm_path )
    quelle = pd.read_excel(quelle_path)
    merged = programm.merge(quelle, on='index', how='left')
    quelle_programm_header= pd.read_excel(quelle_programm_header_path )
    return pd.concat([quelle_programm_header, merged])

result = dataframes_merge()
andreas96
User
Beiträge: 11
Registriert: Montag 7. September 2020, 08:27

Ich habe den Code aus einem grösseren Programm als Abschnitt raus kopiert und leicht geändert. Anscheinend eine Klammer vergessen. :roll:
Der bereinigte Code, gerade getestet:

Code: Alles auswählen

import pandas as pd

quelle_path = r'C:\DATA\daten\quelle.xlsx'
quelle_prgheader = r'C:\DATA\daten\header.xlsx'
prg_path = r'C:\DATA\daten\programm.xlsx'

def dataframes_merge():
    global df3
    global result
    df1 = pd.read_excel(prg_path)
    df2 = pd.read_excel(quelle_path)  # dtype={'Programmname':int}
    df1.head()
    df2.head()

    df3 = df1.merge(df2, on='index', how='left')
    df4 = pd.read_excel(quelle_prgheader)

    result = pd.concat([df4, df3])

dataframes_merge()
print(result)

# result.to_csv('Testfile'  + '.csv', sep=";" ,decimal=",", index=False, header=False, date_format=None)
result.to_excel(('Testfile' + '.xlsx'), header=False, index=False)
Das Programm habe ich so im Einsatz. Nur wenn ich es als csv aus dem Programm mit to_csv speichere gibt es falsche Datenformate.

Link zu den drei xlsx-Dateien Quelle, Programm und Header:
https://1drv.ms/u/s!AiFbEUFIX3kVjM8etFc ... g?e=i9N49y
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

@andreas96: Du hast jetzt nur nochmal den Code kopiert und keine meiner Anmerkungen berücksichtigt? Warum?
Der Link ist kaputt.
Jankie
User
Beiträge: 592
Registriert: Mittwoch 26. September 2018, 14:06

#edit: Verlesen.
andreas96
User
Beiträge: 11
Registriert: Montag 7. September 2020, 08:27

@Sirius3 sorry, ich habe deine Änderung vorher nicht gesehen. (Danke für die Geduld)

Link für Daten neu generiert: https://1drv.ms/u/s!AiFbEUFIX3kVjM8etFc ... g?e=ZpVCzG

Code update und getestet (läuft super), es bleibt nur der Fehler mit dem Datenformat:

Code: Alles auswählen

import pandas as pd
quelle_path = r'C:\DATA\daten\quelle.xlsx'
quelle_programm_header_path = r'C:\DATA\daten\header.xlsx'
programm_path = r'C:\DATA\daten\programm.xlsx'

def dataframes_merge():
    programm = pd.read_excel(programm_path )
    quelle = pd.read_excel(quelle_path)
    merged = programm.merge(quelle, on='index', how='left')
    quelle_programm_header= pd.read_excel(quelle_programm_header_path )
    return pd.concat([quelle_programm_header, merged])

result = dataframes_merge()

dataframes_merge()
print(result)

result.to_csv('Testfilexx' + '.csv', sep=";" ,decimal=",", index=False, header=False, date_format=None)
#result.to_excel(('Testfilexx' + '.xlsx'), header=False, index=False)
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@andreas96: Was für falsche Datenformate?

Spalte BZ enthält einige komische Werte, aber die sind ja schon in den Eingabedaten so komisch. Und Du kannst halt nicht wirklich verhindern das Zahlen als Zahlen erkannt werden. Die Information ob 20,00 in einer Zelle eine Zahl oder ein Text sein soll, gibt das CSV-Format nicht her. Da werden Tabellenkalkulationen beim einlesen eine Zahl draus machen. Was ja auch nicht wirklich anders geht, denn wenn sich die Programme an der Stelle für Text entscheiden würden, wäre das in 99,99% der Fälle die falsche Entscheidung, und man müsste nach dem laden manuell *alle* Zahlen als solche Kennzeichnen/umwandeln.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
andreas96
User
Beiträge: 11
Registriert: Montag 7. September 2020, 08:27

Der Groschen ist pfennigweise gefallen.
@blackjack Jetzt verstehe ich: ich habe die Datei mit einem einfachen Editor als reinen Text betrachtet, dabei ist bzw. bleibt das unerwünschte Datumsformat aus. Der Hauptstrom bleibt eine normale 8.1 Zahl. Ich habe es zuvor immer mit Excel geöffnet. Daher habe ich immer die Datei betrachtet, wie sie Excel interpretiert. :roll:

Dann bleibt nur eine Frage offen. Spalte "Programmname" [Spalte B] sowie andere Spalten erscheinen auch im CSV als "1010.0." Richtig ist aber "1010"
Nur einige Spalten, so etwa (BZ) ist und bleibt 20.0.

Löse ich dies über eine "split-Funktion" ? Eine Zuweisung eines Dateiformates ohne 'Kommastelle' in diesem Falle '.' funktioniert nicht, bzw. hat bei mir nicht funktioniert.
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@andreas96: Das ist IMHO alles kosmetischer Kram mit dem ich mich nicht weiter beschäftigen würde. Beziehungsweise ist Pandas nicht für ”Optik” sondern für Daten.

1010.0 ist die gleiche Zahl wie 1010 weil beide den gleichen Wert haben. Tabellenkalkulation kennen letztendlich eigentlich nur Gleitkommazahlen und Text. 1010 ist im Hintergrund eine Gleitkommazahl bei der keine Nachkommastellen angezeigt werden. Wenn die Exceltabelle eingelesen wird, dann wird in den DataFrame eine 1010.0 eingelesen, denn das steht als Wert in der Zelle: eine Gleitkommazahl mit 0 nach dem Komma beziehungsweise Dezimalpunkt. Das die in der Exceltabelle nicht angezeigt wird, ist eine Formatinformation der Zelle, die nicht im DataFrame landet, denn das ist ”Optik” und nicht das wofür Pandas da ist — Rechnen mit Daten.

Die Werte in der Spalte BZ bleiben so wie sie sind weil das keine Zahlen sondern Texte sind. In Pandas müssen alle Werte in einer Spalte den gleichen Typ haben, und wenn da etwas drin ist was sich nur als Text darstellen lässt, dann werden alle Werte in der Spalte als Texte eingelesen. Auch die, die Zahlen sind. In der Spalte sind Werte wie "20.00,,", also wo noch ein oder zwei Kommas hinter der Zahl stehen, womit das keine Zahl sein kann und damit auch kein anderer Wert in der Spalte eine Zahl sein kann im DataFrame.

Es gehen sowohl beim Laden einer Exceltabelle in einen DataFrame, also auch beim speichern eines DataFrame in eine CSV-Datei, Informationen verloren. Und beim laden einer CSV-Datei in eine Tabellenkalkulation hängt das Ergebnis von verschiedenen Faktoren ab. Zum Beispiel Spracheinstellungen des Systems, welche Tabellenkalkulationssoftware in welcher Version verwendet wird, und so weiter. Wenn diese Informationsverluste ein Problem darstellen, kann man diesen Weg so einfach nicht gehen.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
andreas96
User
Beiträge: 11
Registriert: Montag 7. September 2020, 08:27

@blackjack Danke für deine Antwort. Es ist leider nur teilweise "kosmetischer Kram" Die CSV wird in einen Schweißdatenrechner eingegeben. Das Dataframe dort ist 100 Spalten breit, daher die zusätzlichen Kommata. Dies sind Fragmente aus vorherigen Daten, die in der Matrix stehen geblieben sind. Diese stören auch nicht. Ich habe es gerade probiert. Beim einladen von "1010.0" wird diese auch als diese Zahl als Programmname hinterlegt. Im Schweißdatenrechner ist "1010.0" nicht gleich "1010". Somit muss ich in der CSV eine "1010" übergeben. Wie sage ich es also meinem Programm: In Spalte "XY" schneide die Ausgabe der Zahl ab, oder in dieser Zelle nur Integer.

PS das Forum ist toll. Ich hätte nicht erwartet, dass sich jemand so viel Zeit für eine Antwort gibt. Toll!

PPS was ich nicht verstehe, ist, dass auf dem Bildschirm der Dataframe immer ohne ".0" ausgegeben wird. Nach dem to_csv stehen alle Zahlen mit Punkt. Ist dies auf den Dataframetyp object zurückzuführen? Dies auch in einem reinen Texteditor.
Benutzeravatar
__blackjack__
User
Beiträge: 13123
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich habe gerade gesehen Pandas beim einlesen wohl doch ganze Zahlen verwendet wenn alle Werte in einer Spalte keine Nachkommastellen haben. Aber der Ergebnis-DataFrame hat alle Spalten als Typ `object`. Ich würde sagen Pandas ist hier das falsche Werkzeug. Es wird ja nicht wirklich mit den Daten gerechnet und Pandas ist für Daten mit einer oder mehrerer optionalen Kopfzeilen und nicht für Daten wo am Ende jede Spalte `object` sein muss, weil verschiedene Datentypen darin vorkommen und der ”kleinste gemeinsame Nenner” dann immer `object` ist.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
andreas96
User
Beiträge: 11
Registriert: Montag 7. September 2020, 08:27

@blackjack Ich habe den Dataframe als xlsx gespeichert anstatt CSV. Dann in einem anderen kleinen Programm mit pd.read_excel geöffnet und mit df.to_csv gespeichert.
Dann sind die Datenformate alle richtig. keine ".0"er mehr an den "falschen" Stellen.

Besteht die Möglichkeit so etwas zu machen: Datei nach dem Zusammenführen speichern (wie bisher) Wartezeit ..... dann im Programm read_excel und dann als to csv speichern.
Sirius3
User
Beiträge: 17761
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie __blackjack__ schon geschrieben hat: wenn Du spezielle Anforderungen an das Format hast, dann darfst Du halt nicht pandas benutzen, sondern die Daten direkt mit dem csv-Modul schreiben.
Das ist deutlich transparenter, als jetzt irgendwie die Daten so lange zu konvertieren, bis es zufällig passt.
andreas96
User
Beiträge: 11
Registriert: Montag 7. September 2020, 08:27

Danke euch! Werde es direkt mit dem csv-Modul schreiben, bzw. versuche es :-)
andreas96
User
Beiträge: 11
Registriert: Montag 7. September 2020, 08:27

Jankie hat geschrieben: Mittwoch 9. September 2020, 07:59 Der Code ist so gar nicht lauffährig, in der letzten Zeile ist ein Systaxfehler. Zwischendurch fehlen Klammern.

Globale Varaiablen sollte man nicht benutzen, alle Variablen die eine Funktion benötigt bekommt diese über Parameter und geben ein Ergebnis mittels return zurück.

os.chdir() sollte nicht benutzt werden. Benutze absolute Pfade, am besten mit dem pathlib Modul.

Auf Modulebene sollten nur Konstanten stehen und der if __name__ == '__main__': Aufruf, der die main() aufruft und dort drin sollte dann dein Programm laufen.

Variablen sollte man ausschreiben und nicht abkürzen.
Danke Janki, setze ich um.
Antworten