Excel-File mit Datum kopieren

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
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

Hallo zusammen :)

Ich habe mir eine Excel-Tapete erstellt, die ich gern mit pandas kopieren und als neue Datei (mit eigenem Namen) abspeichern möchte.
https://www.directupload.net/file/d/569 ... 3u_jpg.htm
Ich versuche es so hinzubekommen, daß ein Datum (egal in welche Zelle) automatisch erkannt wird und in der Form strftime('%d.%m.%Y') übernommen wird.
Das was ich versuche, ist, ein Dictionary zu erstellen, welches ich wieder als Excel-File abspeichern kann.
Dabei funktioniert das Datum erkennen und umwandeln schon mal.
Mein bisheriger Code:

Code: Alles auswählen

import os
import pandas as pd

input_file = "C:\\Users\\xxx\\Desktop\\DM-Dateiimport\\Testdatei.xlsx"
process_file = "C:\\Users\\xxx\\Desktop\\DM-Dateiimport\\Testdatei - Kopie.xlsx"

if os.path.isfile(process_file):
    os.remove(process_file)

def undate(x):
    if pd.isnull(x):
        return x
    try:
        return x.strftime('%d.%m.%Y')
    except AttributeError:
        return x
    except Exception:
        raise

excel_file = pd.ExcelFile(input_file)
process_dict = {}
for sheet_name in excel_file.sheet_names:
    df_frame = pd.DataFrame(pd.read_excel(input_file, sheet_name=sheet_name))
    if not df_frame.empty:
        # print(sheet_name)
        if sheet_name not in process_dict:
            process_dict[sheet_name] = {}
        for key, value in df_frame.items():
            # print(key)
            if key not in process_dict[sheet_name]:
                process_dict[sheet_name][key] = []
            process_dict[sheet_name][key].append(df_frame[key].apply(undate))
            
print(process_dict)

excel_file.close()
Ausgabe:

Code: Alles auswählen

{'Tabelle1': {'Name': [0         Ankit
1         Rahul
2       Shaurya
3    03.05.1999
4      Priyanka
Name: Name, dtype: object], 'Age': [0          18
1          19
2          20
3          18
4    7.7.1852
Name: Age, dtype: object], 'Stream': [0          Math
1       Science
2    01.02.1987
3          Math
4       Science
Name: Stream, dtype: object], 'Percentage': [0    07.06.2013
1            90
2            85
3            80
4            75
Name: Percentage, dtype: object]}, 'Tabelle2': {'Date_Names': [0        Ankit
1        Rahul
2      Shaurya
3    Aishwarya
4     Priyanka
Name: Date_Names, dtype: object], 'Dates': [0    01.02.1987
1    02.05.1999
2    02.05.1999
3    01.02.1987
4    02.05.1999
Name: Dates, dtype: object]}}

Process finished with exit code 0
Probleme tauchen jetzt schon bei der Erstellung des Dictionaries auf,
da ich diese ganzen Zusätze nicht in das Dict übernehmen will, sondern nur das was direkt in den Tabellen (im Bild) vorhanden ist.
Kennt sich da jmd mit aus?
LG Christian
einfachTobi
User
Beiträge: 512
Registriert: Mittwoch 13. November 2019, 08:38

Puh, da fällt es mir schwer den Grund dafür nachzuvollziehen.
Zunächst: Warum kann z. B. die Spalte `Name` ein Datum enthalten? Ist es nicht angebracht dafür zu sorgen, dass die Eingangsdaten konsistent sind? Was ist der Sinn hinter dem ganzen vorhaben?
Meistens gilt: Wenn man über ein DataFrame iteriert, macht man etwas falsch.
So kannst du zum Beispiel mit einer Zeile gleich beim Einlesen ein Dictionary je Blatt erzeugen und die Kalenderdaten automatisch als DateTime parsen:

Code: Alles auswählen

mein_frame = pd.read_excel(<pfad_zur_mappe>, parse_dates=True, sheet_name=['Tabelle1', 'Tabelle2'])
print(mein_frame)
Die Formatierung für die DateTimes solltest du eher bei er Ausgabe anpassen. Ansonsten schau dir die Doku von `read_excel()` an. Da steht beschreiben, wie man einen eigenen Parser verwendet.
Um aus einem DataFrame ein Dictionary zu machen sollte man ebenfalls nicht selbst mit for-Schleifen basteln, sondern to_dict() verwenden.
Du kannst aber auch gleich mit to_excel() wieder als Excelmappe abspeichern.
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

Ich möchte es gern so haben, daß man überall auch ein Datum einfügen kann.
In meinem neuen Code passt das auch alles.
Es fehlt nur noch, daß die einzelnen df_frame's nicht immer nur in der ersten Spalte eingesetzt (d.h. dauernd überschrieben) werden.
Es taucht in der Excel-Datei immer nur die letzte Spalte auf, alle anderen werden anscheinend immer überschrieben :)

Code: Alles auswählen

import os
import pandas as pd

input_file = "C:\\Users\\xxx\\Desktop\\DM-Dateiimport\\Testdatei.xlsx"
process_file = "C:\\Users\\xxx\\Desktop\\DM-Dateiimport\\Testdatei - Kopie.xlsx"
if os.path.isfile(process_file):
    os.remove(process_file)


def undate(x):
    if pd.isnull(x):
        return x
    try:
        return x.strftime('%d.%m.%Y')
    except AttributeError:
        return x
    except Exception:
        raise


xlsx = pd.ExcelFile(input_file)
writer = pd.ExcelWriter(process_file, engine='xlsxwriter')

for sheet_name in xlsx.sheet_names:
    if not xlsx.parse(sheet_name).empty:
        for key, value in xlsx.parse(sheet_name).items():
            df_frame = pd.DataFrame(value.apply(undate)).to_excel(writer, sheet_name=sheet_name, index=False)
            worksheet = writer.sheets[sheet_name]
            # pd.concat(df_frame, axis=0, ignore_index=True).to_excel(writer, sheet_name=sheet_name, index=False)


writer.save()
writer.close()
xlsx.close()
Kann man einzelne Spalte auch nebeneinander setzen und dann an den writer geben?
(pd.concat setzt die spalten glaub ich untereinander?)
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

`apply` ist die falsche Funktion, ebenso die for-Schleife. Nimm `applymap`. Den Rückgabewert von to_excel and df_frame zu binden ist quatsch.
Mehrmals `parse` aufzurufen ist falsch. Exceptions sollten wirklich Ausnahmen sein.

Code: Alles auswählen

import pandas as pd

INPUT_FILENAME = "C:\\Users\\xxx\\Desktop\\DM-Dateiimport\\Testdatei.xlsx"
OUTPUT_FILENAME = "C:\\Users\\xxx\\Desktop\\DM-Dateiimport\\Testdatei - Kopie.xlsx"

def undate(x):
    return x.strftime('%d.%m.%Y') if hasattr(x, 'strftime') else x

def main():
    xlsx = pd.ExcelFile(INPUT_FILENAME)
    writer = pd.ExcelWriter(OUTPUT_FILENAME, engine='xlsxwriter')
    for sheet_name in xlsx.sheet_names:
        sheet = xlsx.parse(sheet_name)
        if not sheet.empty:
            sheet.applymap(undate).to_excel(writer, sheet_name=sheet_name, index=False)
    writer.save()
    writer.close()
    xlsx.close()

if __name__ == '__main__':
    main()
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

vielen dank für deine hilfe.
aber ich hab da noch eine frage zu der zeile:
return x.strftime('%d.%m.%Y') if hasattr(x, 'strftime') else x
kannst du mir erklären was if hasattr(x, 'strftime') bewirkt?
soweit ich das verstehe, bedeutet es:
gib das datum in form '%d.%m.%Y' zurück, wenn (es möglich ist, äh !?if hasattr(x, 'strftime')?!), ansonsten den wert der angegeben ist.
ich versteh das hasattr nicht.
Sirius3
User
Beiträge: 18272
Registriert: Sonntag 21. Oktober 2012, 17:20

hasattr fragt ab, ob es die Methode (eigentlich das Attribut) strftime gibt.
DMD-OS
User
Beiträge: 165
Registriert: Freitag 28. Dezember 2018, 13:52

also
sheet.applymap(undate)
und
hasattr(x, 'strftime')
haben mir gefehlt.
vielen dank nochmal :D
Antworten