Aus Raspberry Pi Geek 10/2020

Tabellenbearbeitung mit DataFrames (Seite 2)

Elemente auslesen

Die Funktion names() liefert ein Array mit den Bezeichnern der Spalten. Die Funktion size() gibt, wie bei allen Array-artigen Typen, die Dimensionen als Tupel zurück (Listing 5).

Listing 5

> data = DataFrame(A=1:4, B=5:8)
4x2 DataFrame
| Row | A     | B     |
|     | Int32 | Int32 |
+-----+-------+-------+
| 1   | 1     | 5     |
| 2   | 2     | 6     |
| 3   | 3     | 7     |
| 4   | 4     | 8     |
> names(data)
2-element Array{String,1}:
 "A"
 "B"
> size(data)
(4, 2)

Der Zugriff auf DataFrames ähnelt oft dem auf ein zweidimensionales Array. So sprechen Sie einzelne Elemente oder Bereiche mit Ausdrücken wie data[X, Y] oder data[1:2, :] an. Dieses Vorgehen dürfte aber nur in seltenen Fällen sinnvoll sein, weil Sie dabei die Vorteile des Adressierens über die Bezeichner der Spalten nicht nutzen.

Sie dürfen Spalten gleichwertig per String oder Symbol adressieren. Listing 6 zeigt drei im Ergebnis identische Ausdrücke, die die Spalte A als Array zurückgeben. Beachten Sie, dass diese Ausdrücke eine Referenz auf A liefern, Modifikationen also den Inhalt der ursprünglichen Tabelle ändern. Der Ausdruck data[:, :B] hingegen liefert eine von der Tabelle unabhängige Kopie. Daher ändert in diesem Fall die Zuweisung nicht den Wert in data.

Listing 6

> data.A
4-element Array{Int32,1}:
 1
 2
 3
 4
> data[!, :A]
...
> data[!, "A"]
...
> data[!, :A][1] = 23;
> data
4x2 DataFrame
| Row | A     | B     |
|     | Int64 | Int64 |
+-----+-------+-------+
| 1   | 23    | 5     |
| 2   | 2     | 6     |
...
> data[:, :B][2] = 42;
> data
4x2 DataFrame
| Row | A     | B     |
|     | Int64 | Int64 |
+-----+-------+-------+
| 1   | 23    | 5     |
| 2   | 2     | 6     |
...

Mit der Funktion eachcol() iterieren Sie über die Spalten eines DataFrames (Listing 7). Listing 8 zeigt den Zugriff auf einzelne Zeilen, die Sie über den bereits erwähnten Datentyp DataFrameRow ansprechen. Er bietet die Möglichkeit, über die Bezeichner der Spalten auf die einzelnen Elemente zuzugreifen. Dabei ist sowohl die Punkt- als auch Indexnotation erlaubt. Analog zu eachcol() iterieren Sie per eachrow() über die Zeilen.

Listing 7

> data = DataFrame(A=1:6, B='a':'f')
6x2 DataFrame
| Row | A     | B    |
|     | Int32 | Char |
+-----+-------+------+
| 1   | 1     | 'a'  |
| 2   | 2     | 'b'  |
| 3   | 3     | 'c'  |
...
> for col in eachcol(data)
    println(col)
  end
[1, 2, 3, 4, 5, 6]
['a', 'b', 'c', 'd', 'e', 'f']

Listing 8

> data = DataFrame(
    NAME=["Alice", "Bob"],
    ALTER=[42, 27],
    HOBBY=["malen", "lesen"])
2x3 DataFrame
| Row | NAME   | ALTER | HOBBY  |
|     | String | Int32 | String |
+-----+--------+-------+--------+
| 1   | Alice  | 42    | malen  |
| 2   | Bob    | 27    | lesen  |
> bob = data[2, :]
DataFrameRow
| Row | NAME   | ALTER | HOBBY  |
|     | String | Int32 | String |
+-----+--------+-------+--------+
| 2   | Bob    | 27    | lesen  |
> bob[:HOBBY]
"lesen"
> bob.ALTER
27
> for row in eachrow(data)
    println("Name: ", row.NAME)
    println("Hobby: ", row.HOBBY)
  end
Name: Alice
Hobby: malen
Name: Bob
Hobby: lesen

Fehlende Daten

Ob defekte Messfühler, unvollständig ausgefüllte Formulare oder das Zusammenführen heterogen formatierter Datensätze im Rahmen von Metastudien: In der realen Welt gibt es viele Ursachen für unvollständige Daten. Dieser Tatsache wird Julia mit dem Datentyp Missing und seinem einzigen Vertreter missing gerecht.

Die Spalte A vom Typ Any (Listing 9) akzeptiert ohne Weiteres Einträge vom Typ Missing. Bei präziser typisierten Spalten ist es dagegen nötig, die Aufnahme fehlender Werte explizit zuzulassen. In Listing 9 setzt die Funktion allowmissing!() dieses Recht für die gesamte Tabelle – mit einem zweiten Argument gelingt das für eine bestimmte Spalte. Die Typbezeichnung von Spalte BInt32? – signalisiert anschließend per angehängtem Fragezeichen, dass diese nun fehlende Werte enthalten darf.

Listing 9

> data = DataFrame(A=[], B=Int[]);
> push!(data, [missing, 1])
1x2 DataFrame
| Row | A       | B     |
|     | Any     | Int32 |
+-----+---------+-------+
| 1   | missing | 1     |
> push!(data, [1, missing])
ERROR: MethodError: Cannot `convert` an object of type Missing to an object of type Int32
> allowmissing!(data);
> push!(data, [1, missing])
2x2 DataFrame
| Row | A       | B       |
|     | Any     | Int32?  |
+-----+---------+---------+
| 1   | missing | 1       |
| 2   | 1       | missing |
> typeof(data.B)
Array{Union{Missing, Int64},1}

Nebenbei bemerkt: Die Ausgabe von typeof(data.B) zeigt einen Union-Typ an. Neben den in Teil 2 der Julia-Einführung [3] vorgestellten abstrakten Basistypen sind Union-Typen eine alternative Möglichkeit, unterschiedliche Typen zur gemeinschaftlichen Behandlung zusammenzufassen.

Speichern und Laden

Julia stellt über Packages wie CSV oder SQLite Schnittstellen zu diversen Formaten für Dateien und Datenbanken bereit. Wir beschränken uns hier auf ein einfaches Beispiel, den Im- und Export von CSV-Dateien (Listing 10).

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 7 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
RASPBERRY PI GEEK KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Raspberry Pi Geek bei Google Play Readly Logo
Nach oben