Runde 1b: Verschachtelte Datenstrukturen mit Tiefe 2

Runde 1b: Verschachtelte Datenstrukturen mit Tiefe 2#

Darum geht es: In Runde 1a: grundlegende Datentypen und Datenstrukturen haben wir die wichtigsten der grundlegenden Python-Konstrukte kennengelernt.

Wir bleiben mit den Sprachmitteln in Runde 1 und wenden sie auf etwas komplexere Datenstrukturen an: Listen (oder Dicts etc.), die Listen oder Dicts etc. enthalten. Mit solch einer „verschachtelten“ Datenstruktur können wir z.B. Excel-Tabellen darstellen (und natürlich auch importieren und exportieren).

Ziel ist es, ein erstes einfaches Programm zu schreiben, in dem algorithmisch mehrere Schritte aufeinander folgen.

Dieses Notebook präsentiert zuerst das Problem, und zeigt dann akribisch Schritt für Schritt, wie man sich als Programmier-Anfänger in Runde 1 der Problemlösung nähert.

Melbourne Housing#

Wir lesen die ersten n Zeilen eines gut bekannten Original-Datensatzes aus der Wirtschaftsinformatik als Pandas Dataframe ein.

Download:

  • melb_data.csv

  • Wohin speichern? Am einfachsten in das selbe Verzeichnis legen, in dem dieses Notebook liegt.

Über diesen Datensatz:

Doku Pandas:

import pandas as pd

nrows = 3
usecols = [ 'Landsize', 'Rooms', 'Price', 'Date', 'Address', 'Type']
melb_df = pd.read_csv( "./melb_data.csv", 
            usecols = usecols,
            nrows = nrows # eigentlich sind es 13580 Datensätze ;-)
         )

# Was haben wir eingelesen? # Anzahl Zeilen, Spalten
melb_df.shape
(3, 6)
melb_df
Address Rooms Type Price Date Landsize
0 85 Turner St 2 h 1480000.0 3/12/2016 202.0
1 25 Bloomburg St 2 h 1035000.0 4/02/2016 156.0
2 5 Charles St 3 h 1465000.0 4/03/2017 134.0

Mit Pandas Dataframes zu arbeiten kann in der ersten Runde Python-101 nicht Inhalt sein. Aber man kann solch ein DataFrame in Datenstrukturen überführen, die für eine Einführung in Python 101 sehr instruktuv sind.

Die einfachste alle Darstellungen verwirft die Spaltenüberschriften völlig:

# jede Zeile eine Liste
melb_df.values.tolist()
[['85 Turner St', 2, 'h', 1480000.0, '3/12/2016', 202.0],
 ['25 Bloomburg St', 2, 'h', 1035000.0, '4/02/2016', 156.0],
 ['5 Charles St', 3, 'h', 1465000.0, '4/03/2017', 134.0]]

Informationserhaltende Darstellungen nutzen Mischungen aus Listen und dicts.

Aufgabe: Vergegenwärtigen Sie sich für list, dict und index, ins welche konkrete Datenstruktur die abstrakte Datenstruktur „Tabelle“ jeweils überführt wird!

# jede Spalte eine Liste
melb_orient_list = melb_df.to_dict(orient='list')
melb_orient_list
{'Address': ['85 Turner St', '25 Bloomburg St', '5 Charles St'],
 'Rooms': [2, 2, 3],
 'Type': ['h', 'h', 'h'],
 'Price': [1480000.0, 1035000.0, 1465000.0],
 'Date': ['3/12/2016', '4/02/2016', '4/03/2017'],
 'Landsize': [202.0, 156.0, 134.0]}
# jede Spalte ein Dict
melb_orient_dict = melb_df.to_dict(orient='dict') # orient='dict': default
melb_orient_dict
{'Address': {0: '85 Turner St', 1: '25 Bloomburg St', 2: '5 Charles St'},
 'Rooms': {0: 2, 1: 2, 2: 3},
 'Type': {0: 'h', 1: 'h', 2: 'h'},
 'Price': {0: 1480000.0, 1: 1035000.0, 2: 1465000.0},
 'Date': {0: '3/12/2016', 1: '4/02/2016', 2: '4/03/2017'},
 'Landsize': {0: 202.0, 1: 156.0, 2: 134.0}}
# jede Zeile ein Dict
melb_orient_index = melb_df.to_dict(orient='index')
melb_orient_index
{0: {'Address': '85 Turner St',
  'Rooms': 2,
  'Type': 'h',
  'Price': 1480000.0,
  'Date': '3/12/2016',
  'Landsize': 202.0},
 1: {'Address': '25 Bloomburg St',
  'Rooms': 2,
  'Type': 'h',
  'Price': 1035000.0,
  'Date': '4/02/2016',
  'Landsize': 156.0},
 2: {'Address': '5 Charles St',
  'Rooms': 3,
  'Type': 'h',
  'Price': 1465000.0,
  'Date': '4/03/2017',
  'Landsize': 134.0}}

Aufgabenstellung#

Gegeben: Der Melbourne Housing Datensatz.

Gesucht:

  • Price_avg: berechne das arithmetisches Mittel („Durchschnitt“) des Preises aller Häuser.

  • Lege neue Spalte Price_centered an: Subtrahiere vom jeweiligen Preis den Durchschnittspreis.

  • Bestimme zur neuen Spalte Price_centered die https://de.wikipedia.org/wiki/Empirische_Varianz.

  • neue Spalte Price_standardized: Dividiere jeden Wert aus Price_centered durch die Standardabweichung (Wurzel der Varianz).

Lösen Sie diese Aufgabe zunächst auf Basis der Variablen melb_orient_list.

Lösen Sie diese Aufgabe nur mit den Mittel aus Runde 1. Insbesondere stehen Ihnen Funktionen wie min() oder max() in Runde 1 ja nicht zur Verfügung. Deshalb programmieren wir diese zur Übung hier einfach selbst.

# meine Spalte: p

p = melb_orient_list["Price"]
p
[1480000.0, 1035000.0, 1465000.0]
p_sum = 0
for x in p:
    p_sum += x
p_sum
3980000.0
p_avg = p_sum / len(p)
p_avg
1326666.6666666667
p_zentriert = [ x - p_avg for x in p ]
p_zentriert
[153333.33333333326, -291666.66666666674, 138333.33333333326]
p_standardabweichung = ( sum( [ x**2  for x in p_zentriert ] ) / len(p) ) ** 0.5
p_standardabweichung
206330.3715457863
p_standardisiert = [  x / p_standardabweichung  for x in p_zentriert]
melb_orient_list["Price_centered"] = p_zentriert
melb_orient_list["Price_standardized"] = p_standardisiert

Erweiterung#

Wir wollen alle Spalten mit Zahlen standardisieren.

def standard(p):
    """Standardisiert eine Liste: avg abziehen und durch Standardabweichung teilen."""
    
    # Summe
    p_sum = 0
    for x in p:
        p_sum += x
    
    # arithmetisches Mittel
    p_avg = p_sum / len(p)
    print("p_avg:", p_avg)
    
    # zentrieren
    p_zentriert = [ x - p_avg for x in p ]
    
    # standardisieren
    p_standardabweichung = ( sum( [ x**2  for x in p_zentriert ] ) / len(p) ) ** 0.5
    p_standardisiert = [  x / p_standardabweichung  for x in p_zentriert]
    
    return p_standardisiert
#mein_test = [1,2,3,4,5]
#mein_test_standardisiert = standard(mein_test)
#mein_test_standardisiert
for Spalte in ["Price", "Landsize"]:
    Spaltenname_neu = Spalte + "_standardisiert"
    melb_orient_list[Spaltenname_neu] = standard( melb_orient_list[Spalte] )
p_avg: 1326666.6666666667
p_avg: 164.0

Kontrolle#

Natürlich kann man das so entstandene dict auch wieder in ein DataFrame umwandeln, Doku:

melb2_list_df = pd.DataFrame.from_dict(melb_orient_list, orient = 'columns')
melb2_list_df
Address Rooms Type Price Date Landsize Price_centered Price_standardized Price_standardisiert Landsize_standardisiert
0 85 Turner St 2 h 1480000.0 3/12/2016 202.0 153333.333333 0.743145 0.743145 1.341269
1 25 Bloomburg St 2 h 1035000.0 4/02/2016 156.0 -291666.666667 -1.413591 -1.413591 -0.282372
2 5 Charles St 3 h 1465000.0 4/03/2017 134.0 138333.333333 0.670446 0.670446 -1.058897

Für Lernwillige: Wenn Sie mit Ihrer Lösung zufrieden sind, lösen Sie zur Übung diese Aufgabe auch in den anderen zwei Orientierungen dict und index (kniffeliger, weil der Datentyp nicht so gut passt, aber gut möglich.)