Haushaltsbuch

Geldsäcke

In diesem Kapitel unseres Pandas-Tutorials werden wir uns mit einfachen Ausgaben- und Einkommenstabellen für den privaten Gebrauch befassen. Einige sagen, wenn man Geld erfolgreich verwalten möchte, muss man die Einnahmen und Ausgaben genau verfolgen. Die Überwachung des Geldflusses ist wichtig, um die eigene finanzielle Situation besser zu verstehen. Man muss genau wissen, wie viel ein- und ausgeht. Dazu bedient man sich üblicherweise eines Haushaltsbuches, indem alle Ein- und Ausgaben protokolliert sind. Dieser Artikel will niemanden von der Notwendigkeit überzeugen, dies zu tun. Das Hauptaugenmerk liegt vielmehr auf den Möglichkeiten, die Python und Pandas bieten, um die erforderlichen Tools zu programmieren. Wir zeigen Verfahren, um eine Haushaltsbuch auszuwerten.

Wir beginnen mit einem kleinen Beispiel, das für private Zwecke geeignet ist. Im folgenden Kapitel unseres Pandas-Tutorials wird ein ausführlicheres Beispiel behandelt, welches für kleine Unternehmen geeignet ist.

Private Haushaltsplanung mit Python und Pandas

Nehmen wir an, Sie haben bereits eine CSV-Datei, die Ihre Ausgaben und Einnahmen über einen bestimmten Zeitraum enthält. Dieses Tagebuch könnte folgendermaßen aussehen:

Datum;Beschreibung;Kategorie;Ausgaben;Einnahmen
2020-06-02;Gehalt Frank;Einkommen;0;4896.44
2020-06-03;Supermarkt;Essen und Getränke;132.40;0
2020-06-04;Gehalt Laura;Einkommen;0;4910.14
2929-06-04;Stadtwerke (Strom);Betriebskosten;87.34;0
2020-06-09;Stadtwerke (Wasser und Abwasser);Betriebskosten;60.56;0
2020-06-10;Fitnessstudio, Jane;Gesundheit und Sport;19.00;0
2020-06-11;Bank;Kredittilgung;1287.43;0
2020-06-12;LeGourmet Restaurant;Restaurants und Hotels;145.00;0
2020-06-13;Supermarkt;Essen und Getränke;197.42;0
2020-06-13;Pizzeria da Pulcinella;Restaurants und Hotels;60.00;0
2020-06-26;Supermarkt;Essen und Getränke;155.42;0
2020-06-27;Theatertickets;education and culture;125;0
2020-07-02;Gehalt Frank;Einkommen;0;4896.44
2020-07-03;Supermarkt;Essen und Getränke;147.90;0
2020-07-05;Gehalt Laura;Einkommen;0;4910.14
2020-07-08;Golf Club, jährliche Zahlung;Gesundheit und Sport;612.18;0
2020-07-09;Hausversicherung;Versicherungen;167.89;0
2020-07-10;Fitnessstudio, Jane;Gesundheit und Sport;19.00;0
2020-07-10;Supermarkt;Essen und Getränke;144.12;0
2020-07-11;Banküberweisung;Kredittilgung;1287.43;0
2020-07-18;Supermarkt;Essen und Getränke;211.24;0
2020-07-13;Pizzeria da Pulcinella;Restaurants und Hotels;33.00;0
2020-07-23;Kinobesuch;Kultur und Weiterbildung;19;0
2020-07-25;Supermarkt;Essen und Getränke;186.11;0

Die oben genannte CSV-Datei wird unter dem Namen ein_und_ausgaben.csv im Ordner data gespeichert. Es ist einfach, sie mit Pandas einzulesen, wie wir in unserem Kapitel Dateien lesen und schreiben mit Pandas sehen können:

In [34]:
import pandas as pd

import os
print(os.getcwd())

exp_inc = pd.read_csv("data1/ein_und_ausgaben.csv", sep=";")
exp_inc
/data/Dropbox (Bodenseo)/notebooks/pandas_de
Out[34]:
Datum Beschreibung Kategorie Ausgaben Einnahmen
0 2020-06-02 Gehalt Frank Einkommen 0.00 4896.44
1 2020-06-03 Supermarkt Essen und Getränke 132.40 0.00
2 2020-06-04 Gehalt Laura Einkommen 0.00 4910.14
3 2929-06-04 Stadtwerke (Strom) Betriebskosten 87.34 0.00
4 2020-06-09 Stadtwerke (Wasser und Abwasser) Betriebskosten 60.56 0.00
5 2020-06-10 Fitnessstudio, Jane Gesundheit und Sport 19.00 0.00
6 2020-06-11 Bank Kredittilgung 1287.43 0.00
7 2020-06-12 LeGourmet Restaurant Restaurants und Hotels 145.00 0.00
8 2020-06-13 Supermarkt Essen und Getränke 197.42 0.00
9 2020-06-13 Pizzeria da Pulcinella Restaurants und Hotels 60.00 0.00
10 2020-06-26 Supermarkt Essen und Getränke 155.42 0.00
11 2020-06-27 Theatertickets Kultur und Weiterbildung 125.00 0.00
12 2020-07-02 Gehalt Frank Einkommen 0.00 4896.44
13 2020-07-03 Supermarkt Essen und Getränke 147.90 0.00
14 2020-07-05 Gehalt Laura Einkommen 0.00 4910.14
15 2020-07-08 Golf Club, jährliche Zahlung Gesundheit und Sport 612.18 0.00
16 2020-07-09 Hausversicherung Versicherungen und Steuern 167.89 0.00
17 2020-07-10 Fitnessstudio, Jane Gesundheit und Sport 19.00 0.00
18 2020-07-10 Supermarkt Essen und Getränke 144.12 0.00
19 2020-07-11 Banküberweisung Kredittilgung 1287.43 0.00
20 2020-07-18 Supermarkt Essen und Getränke 211.24 0.00
21 2020-07-13 Pizzeria da Pulcinella Restaurants und Hotels 33.00 0.00
22 2020-07-23 Kinobesuch Kultur und Weiterbildung 19.00 0.00
23 2020-07-25 Supermarkt Essen und Getränke 186.11 0.00

Durch Lesen der CSV-Datei haben wir ein DataFrame-Objekt erstellt. Was können wir damit machen oder mit anderen Worten: Welche Informationen interessieren Frank und Laura? Natürlich interessieren sie sich für den Kontostand. Sie wollen wissen, wie hoch das Gesamteinkommen war, und sie wollen die Summe aller Ausgaben sehen.

Die Salden ihrer Ausgaben und Einnahmen können leicht berechnet werden, indem die Funktion sum auf das DataFrameexp_inc[['Out', 'In']]-Objekt angewendet:

In [35]:
exp_inc[['Ausgaben', 'Einnahmen']].sum()
Out[35]:
Ausgaben      5097.44
Einnahmen    19613.16
dtype: float64

Welche weiteren Informationen möchten sie aus den Daten gewinnen? Sie könnten daran interessiert sein, die Ausgaben nach den verschiedenen Kategorien zusammengefasst zu sehen. Dies lässt sich mittels groupby und sum bewerkstelligen:

In [36]:
category_sums = exp_inc.groupby("Kategorie").sum()
category_sums
Out[36]:
Ausgaben Einnahmen
Kategorie
Betriebskosten 147.90 0.00
Einkommen 0.00 19613.16
Essen und Getränke 1174.61 0.00
Gesundheit und Sport 650.18 0.00
Kredittilgung 2574.86 0.00
Kultur und Weiterbildung 144.00 0.00
Restaurants und Hotels 238.00 0.00
Versicherungen und Steuern 167.89 0.00
In [37]:
category_sums.index
Out[37]:
Index(['Betriebskosten', 'Einkommen', 'Essen und Getränke',
       'Gesundheit und Sport', 'Kredittilgung', 'Kultur und Weiterbildung',
       'Restaurants und Hotels', 'Versicherungen und Steuern'],
      dtype='object', name='Kategorie')
In [38]:
import matplotlib.pyplot as plt

ax = category_sums.plot.bar(y="Ausgaben")
plt.xticks(rotation=45)
Out[38]:
(array([0, 1, 2, 3, 4, 5, 6, 7]), <a list of 8 Text xticklabel objects>)
haushaltsbuch_mit_pandas: Graph 0

Wir können dies auch als Tortendiagramm darstellen:

In [39]:
ax = category_sums.plot.pie(y="Ausgaben")
ax.legend(loc="upper left", bbox_to_anchor=(1.5, 1))
Out[39]:
<matplotlib.legend.Legend at 0x7fc2c20966d0>
haushaltsbuch_mit_pandas 2: Graph 1

Alternativ können wir dasselbe Kreisdiagramm mit dem folgenden Code erstellen:

In [40]:
ax = category_sums["Ausgaben"].plot.pie()
ax.legend(loc="upper left", bbox_to_anchor=(1.5, 1))
Out[40]:
<matplotlib.legend.Legend at 0x7fc2c2011ed0>
haushaltsbuch_mit_pandas 3: Graph 2

If you imagine that you will have to type in all the time category names like "household goods and service" or "rent and mortgage interest", you will agree that it is very likely to have typos in your journal of expenses and income.

So it will be a good idea to use numbers (account numbers) for your categories. The following categories are available in our example.

The following categories are provided:

Wenn man sich vorstellt, dass man die ganze Zeit Kategorienamen wie "Essen und Getränke" oder "Restaurants und Hotels" eingeben muss, kann man sich leicht vorstelltn, dass sich leicht Tippfehler im Ausgaben- und Einnahmenjournal einschleichen können.

Es ist daher eine gute Idee, Nummern (Kontonummern) für die Kategorien zu verwenden. Die folgenden Kategorien sind in unserem Beispiel verfügbar:

Kategorie Kontonummer
Kredittilgung 200
Versicherungen und Steuern 201
Essen und Getränke 202
Kultur und Weiterbildung 203
Transport 204
Gesundheit und Sport 205
Haushalt und Dienstleistungen 206
Kleidung 207
Kommunikationskosten 208
Restaurants und Hotels 209
Betriebskosten (Heizung, Strom, Wasser, Müll) 210
andere Ausgaben 211
Einkommen 400

Wir können dies als Python dictionary implementieren, das Kategorien in Kontonummern abbildet:

In [41]:
category2account = {"Kredittilgung": "200",
                    "Versicherungen und Steuern": "201",
                    "Essen und Getränke": "202",
                    "Kultur und Weiterbildung": "203",
                    "Transport": "204",
                    "Gesundheit und Sport": "205",
                    "Haushalt und Dienstleistungen": "206",
                    "Kleidung": "207",
                    "Kommunikationskosten": "208",
                    "Restaurants und Hotels": "209",
                    "Betriebskosten": "210",
                    "andere Ausgaben": "211",
                    "Einkommen": "400"}

Der nächste Schritt besteht darin, unsere "unhandlichen" Kategorienamen durch die Kontonummern zu ersetzen. Die Ersetzungsmethode replace von DataFrame ist für diesen Zweck ideal. Wir können alle Vorkommen der Kategorienamen in unserem DataFrame durch die entsprechenden Kontonamen ersetzen:

In [42]:
exp_inc.replace(category2account, inplace=True)
exp_inc.rename(columns={"Category": "Accounts"}, inplace=True)
exp_inc
Out[42]:
Datum Beschreibung Kategorie Ausgaben Einnahmen
0 2020-06-02 Gehalt Frank 400 0.00 4896.44
1 2020-06-03 Supermarkt 202 132.40 0.00
2 2020-06-04 Gehalt Laura 400 0.00 4910.14
3 2929-06-04 Stadtwerke (Strom) 210 87.34 0.00
4 2020-06-09 Stadtwerke (Wasser und Abwasser) 210 60.56 0.00
5 2020-06-10 Fitnessstudio, Jane 205 19.00 0.00
6 2020-06-11 Bank 200 1287.43 0.00
7 2020-06-12 LeGourmet Restaurant 209 145.00 0.00
8 2020-06-13 Supermarkt 202 197.42 0.00
9 2020-06-13 Pizzeria da Pulcinella 209 60.00 0.00
10 2020-06-26 Supermarkt 202 155.42 0.00
11 2020-06-27 Theatertickets 203 125.00 0.00
12 2020-07-02 Gehalt Frank 400 0.00 4896.44
13 2020-07-03 Supermarkt 202 147.90 0.00
14 2020-07-05 Gehalt Laura 400 0.00 4910.14
15 2020-07-08 Golf Club, jährliche Zahlung 205 612.18 0.00
16 2020-07-09 Hausversicherung 201 167.89 0.00
17 2020-07-10 Fitnessstudio, Jane 205 19.00 0.00
18 2020-07-10 Supermarkt 202 144.12 0.00
19 2020-07-11 Banküberweisung 200 1287.43 0.00
20 2020-07-18 Supermarkt 202 211.24 0.00
21 2020-07-13 Pizzeria da Pulcinella 209 33.00 0.00
22 2020-07-23 Kinobesuch 203 19.00 0.00
23 2020-07-25 Supermarkt 202 186.11 0.00

Wir werden dieses DataFrame-Objekt jetzt in einer Excel-Datei speichern. Diese Excel-Datei enthält zwei Blätter: eines mit dem Journal "Ausgaben und Einnahmen" und das andere mit der Zuordnung von Kontonummern zu Kategorienamen. Zu diesem Zweck verwandeln wir das category2account-Dictionary in ein Series-Objekt. Als Index dienen die Kontonummern:

We will save this DataFrame object now in an excel file. This excel file will have two sheets: One with the "expenses and income" journal and the other one with the mapping of account numbers to category names. We will turn the category2account dictionary into a Series object for this purpose. The index will be the account numbers:

In [48]:
account_numbers = pd.Series(list(category2account.keys()), index=category2account.values())
account_numbers.name = "Beschreibung"
account_numbers.rename("Kontonummern")
Out[48]:
200                    Kredittilgung
201       Versicherungen und Steuern
202               Essen und Getränke
203         Kultur und Weiterbildung
204                        Transport
205             Gesundheit und Sport
206    Haushalt und Dienstleistungen
207                         Kleidung
208             Kommunikationskosten
209           Restaurants und Hotels
210                   Betriebskosten
211                  andere Ausgaben
400                        Einkommen
Name: Kontonummern, dtype: object
In [49]:
exp_inc.insert(1, "Kontonummern", account_numbers)
In [45]:
with pd.ExcelWriter('data1/expenses_and_income_2020.xlsx') as writer:
    account_numbers.to_excel(writer, "account numbers")
    exp_inc.to_excel(writer, "journal")
    writer.save()