Dateien lesen und schreiben

Digits as File Input and Output

All die starken Daten-Strukturen wie Series und DataFrames würden fast nichts nützen, wenn das Pandas-Modul keine Funktionalitäten unterstützen würde, um Daten einzulesen und rauszuschreiben. Dabei geht es nicht um die einfache Möglichkeit mit Dateien umzugehen. Damit der Nutzen für Data-Scientists sichtbar wird, müssen die wichtigsten Daten-Formate unterstützt werden, wie z.B.:

Trennerseparierte Werte

Die meisten Menschen verwenden den Namen "CSV-Datei" als Synonym für eine trennerseparierte-Datei. Sie beachten nicht die Tatsache, das CSV ein Akronym ist für "comma separated values" (also in Deutsch "kommaseparierte-Liste"), was in den meisten Situationen nicht der Fall ist. Pandas verwendet "csv" ebenfalls in Zusammenhängen, in denen "dsv" die passendere Bezeichnung wäre.

Trennerseparierte Werte (Delimiter-separated values - DSV) sind definiert und abgelegt in zweidimensionalen Arrays, bei denen die Werte mit zweckmäßig definierten Trennzeichen in jeder Zeile getrennt sind. Diese Arte und Weise wird oft in Kombination mit Tabellenprogrammen eingesetzt, die Daten als DSV ein- und auslesen können. Auch wird die Implementierung in allgemeinen Datenaustauschformaten verwendet.

Bei der Datei dollar_euro.txt handelt es sich um eine DSV-Datei, die Tabulatoren (\t) als Trennzeichen benutzt.

CSV und DSV Dateien lesen

Pandas bietet zwei Wege um CSV/DSV Dateien zu lesen. Das bedeutet konkret:

Es gibt zwischen beiden Methoden keinen grossen Unterschied, d.h. es gibt in manchen Fällen verschiedene Default-Werte und read_csv hat mehr Parameter. Wir konzentrieren uns auf read_csv, weil DataFrame.from_csv nur wegen Auf- und Abwärtskompatibilität innerhalb von Pandas gehalten wird.

import pandas as pd
exchange_rates = pd.read_csv("data1/dollar_euro.txt",
                             sep="\t")
print(exchange_rates)
    Year   Average  Min USD/EUR  Max USD/EUR  Working days
0   2016  0.901696     0.864379     0.959785           247
1   2015  0.901896     0.830358     0.947688           256
2   2014  0.753941     0.716692     0.823655           255
3   2013  0.753234     0.723903     0.783208           255
4   2012  0.778848     0.743273     0.827198           256
5   2011  0.719219     0.671953     0.775855           257
6   2010  0.755883     0.686672     0.837381           258
7   2009  0.718968     0.661376     0.796495           256
8   2008  0.683499     0.625391     0.802568           256
9   2007  0.730754     0.672314     0.775615           255
10  2006  0.797153     0.750131     0.845594           255
11  2005  0.805097     0.740357     0.857118           257
12  2004  0.804828     0.733514     0.847314           259
13  2003  0.885766     0.791766     0.963670           255
14  2002  1.060945     0.953562     1.165773           255
15  2001  1.117587     1.047669     1.192748           255
16  2000  1.085899     0.962649     1.211827           255
17  1999  0.939475     0.848176     0.998502           261

Wie wir gesehen haben, benutzt read_csv() automatisch die erste Zeile als Überschriften bzw. Spaltennamen für die Spalten. Wir können den Spalten auch beliebige andere Namen geben. Dazu muss die erste Zeile überprungen werden header = 0 und eine Liste mit Spalten-Namen an den Parameter names zugewiesen werden:

import pandas as pd
exchange_rates = pd.read_csv("data1/dollar_euro.txt",
                             sep="\t",
                             header=0,
                             names=["year", "min", "max", "days"])
print(exchange_rates.head())
          year       min       max  days
2016  0.901696  0.864379  0.959785   247
2015  0.901896  0.830358  0.947688   256
2014  0.753941  0.716692  0.823655   255
2013  0.753234  0.723903  0.783208   255
2012  0.778848  0.743273  0.827198   256

Schreiben von CSV-Dateien

Writing CSV Files

CSV-Dateien können wir mit der Methode to_csv schreiben. Wir werden dies an einem Beispiel demonstrieren. Zuerst erzeugen wir jedoch Daten, die wir dann rausschreiben werden. Im Verzeichnis data1 liegen die beiden Dateien countries_male_population.csv und countries_male_population.csv die entsprechend die männlichen und weiblichen Bevölkerungszahlen von Ländern enthalten.

column_names = ["Country"] + list(range(2003, 2013))
male_pop = pd.read_csv("data1/countries_male_population.csv",
                       header=None,
                       index_col=0,
                       names=column_names)
female_pop = pd.read_csv("data1/countries_female_population.csv",
                         header=None,
                         index_col=0,
                         names=column_names)
population = male_pop + female_pop
population.head()
Wir können die folgenden Ergebnisse erwarten, wenn wir den obigen Python-Code ausführen:
2003 2004 ... 2011 2012
Country
Australia 19872646 20091504 ... 22620554 22683573
Austria 8067289 8140122 ... 8404252 8443018
Belgium 10355844 10396421 ... 10366843 11035958
Canada 31361611 31372587 ... 33927935 34492645
Czech Republic 10203269 10211455 ... 10532770 10505445

5 rows × 10 columns

Nun schreiben wir das eben erzeugte DataFrame population in eine Datei countries_total_population.csv im Verzeichnis data1:

population.to_csv("data1/countries_total_population.csv")

Wir möchten nun ein DataFrame bzw. eine Datei erzeugen, die alle Informationen enthalten soll, also sowohl die weibliche und die männliche Bevölkerung als auch die Gesamtbevölkerung. Dazu konkatenieren wir die drei DataFrames:

pop_complete = pd.concat([population, 
                          male_pop,
                          female_pop], 
                          keys=["total", "male", "female"])

Um das Ergebnis der vorigen Konkatenation besser zu verstehen, geben wir im Folgenden nur die interessanten Indizes aus:

pop_complete.iloc[[0, 1, 2, 29, 30, 31, 32, 59, 60, 61, 62]]
Der obige Python-Code führt zu folgender Ausgabe:
2003 2004 ... 2011 2012
Country
total Australia 19872646 20091504 ... 22620554 22683573
Austria 8067289 8140122 ... 8404252 8443018
Belgium 10355844 10396421 ... 10366843 11035958
United States 288774226 290810719 ... 309989078 312232049
male Australia 9873447 9990513 ... 11260747 11280804
Austria 3909120 3949825 ... 4095337 4118035
Belgium 5066885 5087176 ... 5370234 5413801
United States 141957038 143037260 ... 152449134 153596908
female Australia 9999199 10100991 ... 11359807 11402769
Austria 4158169 4190297 ... 4308915 4324983
Belgium 5288959 5309245 ... 4996609 5622157

11 rows × 10 columns

Wir wollen nun den hierarchischen Index umdrehen, sodass man für jedes Land direkt alle Bevölkerungsinformationen im Blick hat:

df = pop_complete.swaplevel()
df.sort_index(inplace=True)
df.head(12)
Wir können die folgenden Ergebnisse erwarten, wenn wir den obigen Python-Code ausführen:
2003 2004 ... 2011 2012
Country
Australia female 9999199 10100991 ... 11359807 11402769
male 9873447 9990513 ... 11260747 11280804
total 19872646 20091504 ... 22620554 22683573
Austria female 4158169 4190297 ... 4308915 4324983
male 3909120 3949825 ... 4095337 4118035
total 8067289 8140122 ... 8404252 8443018
Belgium female 5288959 5309245 ... 4996609 5622157
male 5066885 5087176 ... 5370234 5413801
total 10355844 10396421 ... 10366843 11035958
Canada female 15829173 15834015 ... 17101813 17379104
male 15532438 15538572 ... 16826122 17113541
total 31361611 31372587 ... 33927935 34492645

12 rows × 10 columns

df.to_csv("data1/countries_total_population.csv")

Lesen und Schreiben von Excel-Dateien

Es ist auch möglich Microsoft-Excel-Dateien zu lesen und zu schreiben. Pandas benutzt um diese Funktionalitäten bereitzustellen die Module xlrd und openpyxl. Diese Module werden automatisch von Pandas installiert, sodass man sie nicht extra installieren muss.

Wir werden ein einfaches Excel-Dokument benutzen, um Lesemöglichkeiten von Pandas zu demonstrieren. Das Dokument sales.xls enthält zwei Blätter (englisch "sheet"), das eine mit dem Namen 'week1' und das andere 'week2'.
Eine Excel-Datei lässt sich mit der Funktion "read_excel" einlesen. Wir zeigen dies mit dem folgenden Python-Programm:

excel_file = pd.ExcelFile("data1/sales.xls")
sheet = pd.read_excel(excel_file)
sheet
Wir erhalten die folgende Ergebnisse:
Weekday Sales
0 Monday 123432.980000
1 Tuesday 122198.650200
2 Wednesday 134418.515220
3 Thursday 131730.144916
4 Friday 128173.431003

Von den beiden Blättern der Datei "sales.xls" haben wir nur eine mit read_excel eingelesen. Eine Excel-Datei, die aus zahlreichen Blättern bestehen kann, kann mit allen Blättern wie folgt eingelesen werden:

document = {}
excel_file = pd.ExcelFile("data1/sales.xls")
for sheet_name in excel_file.sheet_names:
    document[sheet_name] = excel_file.parse(sheet_name)
for sheet_name in document:
    print("\n" + sheet_name + ":\n", document[sheet_name])
week1:
      Weekday          Sales
0     Monday  123432.980000
1    Tuesday  122198.650200
2  Wednesday  134418.515220
3   Thursday  131730.144916
4     Friday  128173.431003
week2:
      Weekday          Sales
0     Monday  223277.980000
1    Tuesday  234441.879000
2  Wednesday  246163.972950
3   Thursday  241240.693491
4     Friday  230143.621590