Mit Pandas CSV-Datei bearbeiten

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
d_StaR
User
Beiträge: 7
Registriert: Donnerstag 9. November 2023, 14:39

Hallo zusammen,

ich möchte mir eine fortlaufende Liste erstellen, die so aussieht:

Code: Alles auswählen

     Datum    Online    Bar   Kunden  Touren
0   2112023        10     12       5       1
1   6112023         9      5      12       1
2   7112023        47     13      25       2
und die ich so erstellt habe:

Code: Alles auswählen

import pandas as pd

#define list of lists
data = [[2112023, 10, 12, 5, 1], [6112023, 9, 5, 12,1], [7112023, 47,13, 25, 2]]

#convert list into DataFrame
df = pd. DataFrame (data, columns=[' Datum ', ' Online ', ' Bar ', 'Kunden', 'Touren'], 

#view resulting DataFrame
print (df)
Jetzt möchte ich die Liste wie folgt erweitern und dann abspeichen. Bis hier auch kein Problem.

Code: Alles auswählen

     Datum    Online    Bar   Kunden  Touren
0   2112023        10     12       5       1
1   6112023         9      5      12       1
2   7112023        47     13      25       2
0  10112023        24     10      13       1
Nur wenn ich dann die CSV lade und dann eine Zeile dazu schreibe ensteht Murks. Dazu nutze ich diesen Code:

Code: Alles auswählen

import pandas as pd


df = pd. read_csv ('c:/Users\Tobi\Documents/tipdata_test.csv' )

neue= [10112023, 24, 10, 13, 1]

df = df._append(pd.DataFrame([neue], columns=[' Datum ', ' Online ', ' Bar ', 'Kunden', 'Touren']))

df.to_csv('c:/Users\Tobi\Documents/tipdata_test.csv')


#view resulting DataFrame
print (df)
Dann sieht das ganze danach so aus:

Code: Alles auswählen

   Unnamed: 0    Datum    Online    Bar   Kunden  Touren
0         0.0   2112023        10     12       5       1
1         1.0   6112023         9      5      12       1
2         2.0   7112023        47     13      25       2
3         0.0  10112023        24     10      13       1
0         NaN  10112023        24     10      13       1
An der Stelle komme ich dann auch nicht weiter, hab jetzt schon einen halben Tag verschiedenste Varianten probiert, und im Netz gelesen.
-append sollte ja eigentlich die einfachere Variante zu sein um Zeilen hinzuzufügen, aber ich komm damit nicht klar. Ich hoffe es kann/mag mir jemmand helfen, mir raucht gerade mein Kopf :wink:

Liebe Grüße

Tobi (dstar)
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

muss es CSV sein? Das ist ja das "dünnste" Format überhaupt. Warum speicherst du den DataFrame nicht via pickle als solchen ab (https://pandas.pydata.org/docs/referenc ... ickle.html) und schreibst ihn bei Bedarf in eine CSV Datei?

Zu deinem Problem: die Spalte ganz links ohne Überschrift ist der Index. Den schreibt Pandas halt mit in den CSV-Datei. Beim Lesen musst du Pandas sagen, ob eine Spalte der Index ist, sonst wird ein neuer angelegt - und dann kommt das dabei raus, was du hast.
Du musst keinen eigenen Index nutzen, kann aber nützlich sein. Wenn bei dir z.B. jedes Datum nur 1x vorkommen kann (oder darf) wäre das ein Kandidat für den Index.

Das Datumsformat von dir ist auch echt ungünstig. Wirst du spätestens dann merken, wenn du darüber Suchen oder sortieren willst. Pandas kennt einen dtype für das Datum. Und wenn du den nicht nutzen willst oder kannst, dann solltest du das Datum minimal im ISO 8601 Format schreiben, also 2023-11-09 oder meinetwegen auch 20231109. Vorteil: ist wenigst ohne Probleme aufsteigend und absteigend sortierbar.

Gruß, noisefloor

Nachtrag: wenn du nicht mehr hast bzw. brauchst, als das, was in deinem Beispiel gezeigt ist, dann brauchst du kein Pandas. Das geht auch ohne Probleme mit dem csv-Modul, was Python standardmäßig an Bord hat.
d_StaR
User
Beiträge: 7
Registriert: Donnerstag 9. November 2023, 14:39

HI noisefloor,

danke für deine Anwort. CSV hab ich nur ausgewählt weil ich dachte das es einfacher wäre, was sich bisher nicht bestätigt hat. Mit pickle müsste ich mal probieren, da muss ich mich erstmal mit auseinandersetzen.

Das der Index das Probleme ist habe ich auch vermutet, das Datum als Index hatte ich auch schon im Kopf, nur hats (bisher) nicht geklappt. Und ja jedes Datum darf / muss nur einmal vorkommen. Das Format werde ich dann auch noch anpassen.

Das ganze ist nur ein Teil meines "kleinen" Programms mit den ich meine Tip-Kasse verwalten möchte. Daher auch Pandas, weil ich die Daten gerne auswerten möchte und dafür sich das csv-Modul eher schlecht eignet. Bisher arbeite ich erstmal an einen simplen Grundgerüst das ich dann nach und nach erweitere und anpasse. Wollt halt mal was mit Python machen und stelle fest das es doch viel arbeit, aber auch Spaß macht. Obwohl es viel "Hirnschmalz" braucht :D

Liebe Grüße

Tobi
d_StaR
User
Beiträge: 7
Registriert: Donnerstag 9. November 2023, 14:39

Also ich habe es hinbekommen, meine Tabelle sieht jetzt so aus:

Code: Alles auswählen

 Online Bar Kunden Touren
Datum
2112023      10  12      5      1
6112023       9   5     12      1
7112023      47  13     25      2
nun möchte ich Zahlen in der Spalte addieren, also alles was bei "online" steht, mit diesen Befehl:

Code: Alles auswählen

print(df['Online'].sum())    
oder mit:

Code: Alles auswählen

sum = df['Online'].sum()
print(sum)
Funktioniert aber beides nicht. Was ich im Netz gefunden habe scheint nicht mehr aktuell zu sein, siehe Quellen oder was mach ich falsch?

So erhalten Sie die Summe der Pandas-Spalte
summe-zeilen-pandas
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@d_StaR: Was heisst ”funktioniert nicht”? Was passiert? Wie weicht das vom Erwarteten ab?
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
d_StaR
User
Beiträge: 7
Registriert: Donnerstag 9. November 2023, 14:39

Sorry vergessen, ich bekomme diesen Fehler:

Code: Alles auswählen

Traceback (most recent call last):
  File "c:\Users\Tobi\Documents\Tip-Verwaltung.py", line 129, in <module>
    Abfrage()
  File "c:\Users\Tobi\Documents\Tip-Verwaltung.py", line 125, in Abfrage
    Abfrage()
  File "c:\Users\Tobi\Documents\Tip-Verwaltung.py", line 115, in Abfrage
    Eingeben()
  File "c:\Users\Tobi\Documents\Tip-Verwaltung.py", line 63, in Eingeben
    print(df['Online'].sum())
          ^^^^^^^^^^^^^^^^^^
  File "C:\Users\Tobi\anaconda3\Lib\site-packages\pandas\core\generic.py", line 11512, in sum
    return NDFrame.sum(self, axis, skipna, numeric_only, min_count, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Tobi\anaconda3\Lib\site-packages\pandas\core\generic.py", line 11280, in sum
    return self._min_count_stat_function(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Tobi\anaconda3\Lib\site-packages\pandas\core\generic.py", line 11263, in _min_count_stat_function
    return self._reduce(
           ^^^^^^^^^^^^^
  File "C:\Users\Tobi\anaconda3\Lib\site-packages\pandas\core\series.py", line 4670, in _reduce
    return op(delegate, skipna=skipna, **kwds)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Tobi\anaconda3\Lib\site-packages\pandas\core\nanops.py", line 96, in _f
    return f(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^
  File "C:\Users\Tobi\anaconda3\Lib\site-packages\pandas\core\nanops.py", line 421, in new_func
    result = func(values, axis=axis, skipna=skipna, mask=mask, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Tobi\anaconda3\Lib\site-packages\pandas\core\nanops.py", line 494, in newfunc
    return func(values, axis=axis, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Tobi\anaconda3\Lib\site-packages\pandas\core\nanops.py", line 652, in nansum
    the_sum = values.sum(axis, dtype=dtype_sum)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\Users\Tobi\anaconda3\Lib\site-packages\numpy\core\_methods.py", line 49, in _sum
    return umr_sum(a, axis, dtype, out, keepdims, initial, where)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@d_StaR: Sieht so aus als wenn die Spalte keine Zahlen sondern Zeichenketten enthält.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

das liegt auch wieder am Import aus einer CSV-Datei. CSV ist einfach nur Text = alles ist ein String. Nur weil wir 5 oder 23456 als Zahl erkennen weiß Python / Pandas nicht automagisch, dass das Zahlen sind. Beim Import ist das erstmal der String "5" oder "23456". Lass' dir mal nach dem Import in einen DataFrame den dtype der Spalten anzeigen, bekommst du über `df.dtypes`. Dann siehst du, welche Spalten welchen Typ hat.

`read_csv` kennt einen Haufen optionaler Argumente, siehe https://pandas.pydata.org/docs/referenc ... d_csv.html. Du kannst beim Import den dtype pro Spalte vorgeben oder - falls nötig - auch eigene Konverter pro Spalte vorgeben.

Gruß, noisefloor
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@noisefloor Wobei zumindest das gezeigte Beispiel automatisch als Zahlenspalte enden sollte. Das heisst das muss irgend etwas enthalten sein was anders aussieht als hier gezeigt. Wobei dann auch komisch ist, dass das gezeigte rechtsbündig ausgerichtet ist, was auch auf Zahlen statt Zeichenketten hindeutet.

@d_StaR: Zeig mal ein minimales, aber lauffähiges Beispiel was man nachvollziehen kann, und dass dieses Verhalten zeigt.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
d_StaR
User
Beiträge: 7
Registriert: Donnerstag 9. November 2023, 14:39

Danke, es lag tatsächlich daran das es als String in die CSV geschrieben wurde, da hab ich nicht mitgedacht. :roll:
Damit:

Code: Alles auswählen

df['Online'] = pd.to_numeric(df['Online'])
konnte ich das beheben.
d_StaR
User
Beiträge: 7
Registriert: Donnerstag 9. November 2023, 14:39

Hi,

mein bisheriges Programm läuft nun soweit und ich habe es noch etwas erweitert. In einem neuen DatenFrame habe ich eine Gesamt Auswertung bei der Durchschnitt pro Kunde und Tour angezeigt werde soll. Die Ausgabe ist allerdings mit vielen Nachkommastellen, daher möchte ich die Ausgabe auf 2 Nachkommastellen kürzen. Dazu verwende ich:

Code: Alles auswählen

format_mapping = {"Ø Tour": "{:.2f}", "Ø Kunde": "{:.2f}"}

df.style.format(format_mapping)
leider bleibt die Ausgabe aber unverändert.

[cod] Gesamt Kunden Touren Ø Tour Ø Kunde
Monat
2023-11 189 93 9 21.0 2.032258[/code]

Um Tips wäre ich dankbar, ich kapiers mal wieder nicht und es hängt wahrscheinlich auch von der Pandas Version ab, was ich so gelesen habe.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Wie benutzt Du den Styler? Der ist ja dazu da HTML-Tabellen zu erzeugen.

Die willst wahrscheinlich nur to_string benutzen:

Code: Alles auswählen

print(df.to_string(formatters={'Ø Tour':'{:.2f}'.format, 'Ø Kunde':'{:.2f}'.format}))
d_StaR
User
Beiträge: 7
Registriert: Donnerstag 9. November 2023, 14:39

@Sirius3

danke! aber das Ergebnis ist jetzt:

Code: Alles auswählen

2023-11     247     112      11  22.454545  2.205357
es sollte aber bis auf die 2.Nachkommastelle gekürzt werden. Also irgendwie haut die Formatierung nicht hin.
Sirius3
User
Beiträge: 17754
Registriert: Sonntag 21. Oktober 2012, 17:20

Also hast Du irgendwas falsch gemacht.
Poste ein vollständiges Beispiel, damit man nachvollziehen kann, was Du gemacht hast.
Antworten