AutoScout24 Mining (Teil 2) – Data Cleaning
In Teil 1 des Tutorials habe ich dir gezeigt, wie du pro Tag Daten von ca. 30.000 Automobil-Inseraten von autoscout24 sammeln kannst. Diese Daten haben wir jetzt. Eine Hürde müssen wir jedoch noch überwinden, bevor wir die Daten analysieren können. Der von vielen unterschätzte Teil der Arbeit mit Rohdaten: Data Cleaning.
Daten säubern
Unsere Rohdaten liegen momentan als CSV-Dateien im Ordner data/autos
. Grob haben wir die Daten beim Scrapen zwar schon gereinigt, als saubere Daten kann man sie jedoch noch nicht bezeichnen. Doch das ändern wir jetzt.
Spaltennamen
Laden wir erst einmal die Daten. Da die Daten in mehreren CSV-Dateien vorliegen, laden wir alle CSVs in einer List Comprehension und konkatenieren die entstandene Liste.
df = pd.concat([pd.read_csv("data/autos/"+file,sep=";") for file in os.listdir("data/autos/")],axis=0,sort=True)
Gucken wir uns mal die ersten drei Zeilen an.
df.head(3)
Andere Energieträger | Angebotsnummer | Antriebsart | Anzahl Türen | Ausstattung | Außenfarbe | Bilder | CO2-Emissionen | CO2-EmissionenWeitere Informationen zum offiziellen Kraftstoffverbrauch und den offiziellen spezifischen CO2-Emissionen neuer Personenkraftwagen können dem „Leitfaden über den Kraftstoffverbrauch, die CO2-Emissionen und den Stromverbrauch neuer Personenkraftwagen“ entnommen werden, der an allen Verkaufsstellen und bei der Deutschen Automobil Treuhand GmbH unter www.dat.de unentgeltlich erhältlich ist. | Erstzulassung | Fahrzeugbeschreibung | Fahrzeughalter | Farbe laut Hersteller | Feinstaubplakette | Garantie | Getriebe | Getriebeart | Gänge | HU Prüfung | HU/AU neu | Hubraum | Innenausstattung | Karosserieform | Kilometerstand | Kraftstoff | Kraftstoffverbr.* | KraftstoffverbrauchWeitere Informationen zum offiziellen Kraftstoffverbrauch und den offiziellen spezifischen CO2-Emissionen neuer Personenkraftwagen können dem „Leitfaden über den Kraftstoffverbrauch, die CO2-Emissionen und den Stromverbrauch neuer Personenkraftwagen“ entnommen werden, der an allen Verkaufsstellen und bei der Deutschen Automobil Treuhand GmbH unter www.dat.de unentgeltlich erhältlich ist. | Lackierung | Leergewicht | Leistung | Letzter Kundendienst | Letzter Wechsel des Zahnriemens | Länderversion | Marke | Marke, Modell | Modell | Modellvarianten | Nichtraucherfahrzeug | Region | Schadstoffklasse | Scheckheftgepflegt | Schlüsselnummer | Serviceleistungen | Sitzplätze | Spezielle Umbauten | StromverbrauchWeitere Informationen zum offiziellen Kraftstoffverbrauch und den offiziellen spezifischen CO2-Emissionen neuer Personenkraftwagen können dem „Leitfaden über den Kraftstoffverbrauch, die CO2-Emissionen und den Stromverbrauch neuer Personenkraftwagen“ entnommen werden, der an allen Verkaufsstellen und bei der Deutschen Automobil Treuhand GmbH unter www.dat.de unentgeltlich erhältlich ist. | Verfügbar ab | Verfügbarkeit | Verkäufer | Zustand | Zylinder | ausstattung_liste | country | date | haendler | ort | price | privat | url | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | NaN | NaN | NaN | 4.0 | 29 Ausstattungsmerkmale | Silber | Tipp:Inseratsbilder werden nicht in die Preisb… | NaN | 159 g CO2/km (komb) | 2010 | Tipp:Die Beschreibung des Fahrzeugs fließt nic… | 1.0 | NaN | NaN | NaN | Automatik | Automatik | NaN | NaN | Ja | 1.997 cm³ | Stoff, Schwarz | Van/Kleinbus | 157.000 km | Diesel | 5.9 l/100 km (komb) | 5,9 l/100 km (komb)8 l/100 km (innerorts)4,8 l… | Metallic | NaN | 81 kW / 110 PS | NaN | NaN | NaN | Ford | Ford C-Max | C-Max | Tipp:Spezielle Ausstattungspakete, Modellvaria… | NaN | Tipp:Regionale Angebots- und Nachfrageuntersch… | Euro 4 | NaN | 8566/AOI | Tipp:Erkundigen Sie sich beim Verkäufer nach z… | 5.0 | Tipp:Prüfen Sie das Fahrzeug bei der Besichtig… | NaN | NaN | NaN | Händler | Tipp:Prüfen Sie das Fahrzeug bei der Besichtig… | NaN | [“, ‚ABS‘, ‚Alufelgen‘, ‚Armlehne‘, ‚Beifahre… | Deutschland | 2020-01-14 11:18:56.582630 | True | 85643 Steinhöring, OT Tulling | 4490 | False | /angebote/ford-c-max-titanium-tempomat-tuev-ne… |
1 | Super E10 95 | *618016 | Front | 5.0 | NaN | Grau | NaN | NaN | 118 g CO2/km (komb) | NaN | NaN | 0.0 | Star Dust | 4 (Grün) | NaN | NaN | Automatik | 7.0 | NaN | Ja | 998 cm³ | Stoff, Sonstige | Limousine | NaN | Super 95 / Super E10 95 / Normal/Benzin E10 91 | NaN | 5,2 l/100 km (komb)5,9 l/100 km (innerorts)4,7… | Metallic | 1.185 kg | NaN | NaN | NaN | Deutsche Ausführung | Hyundai | NaN | i20 | NaN | NaN | NaN | Euro 6d-TEMP | NaN | 5984/ABG | NaN | 5.0 | NaN | NaN | 20.02.20 | NaN | NaN | Neu | 3.0 | [“, ‚ABS‘, ‚Alarmanlage‘, ‚Alufelgen‘, ‚Behei… | Deutschland | 2020-01-14 11:18:57.637573 | True | 88074 Meckenbeuren-Liebenau | 16880 | False | /angebote/hyundai-i20-blue-1-0-t-gdi-dct-yes-r… |
2 | NaN | 136519191 | Front | NaN | NaN | Gold | NaN | NaN | NaN | 1977 | NaN | NaN | gold | NaN | NaN | NaN | Schaltgetriebe | 4.0 | NaN | Ja | 2.734 cm³ | Beige | Coupé | NaN | Super 95 | NaN | NaN | Metallic | NaN | NaN | NaN | NaN | NaN | Oldtimer | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | Oldtimer | NaN | [“, ‚Klimaanlage‘, ‚Komfort‘] | Deutschland | 2020-01-14 11:18:59.257405 | True | 74076 Heilbronn | 49900 | False | /angebote/oldtimer-others-sonstige-benzin-gold… |
Nach einem bisschen Scrollen nach rechts fällt gleich auf, dass wir dringend die Spaltennamen umbenennen müssen.
df = df.rename(columns={"Kraftstoffverbr.*":"kraftstoffverbrauch", 'KraftstoffverbrauchWeitere Informationen zum offiziellen Kraftstoffverbrauch und den offiziellen spezifischen CO2-Emissionen neuer Personenkraftwagen können dem "Leitfaden über den Kraftstoffverbrauch, die CO2-Emissionen und den Stromverbrauch neuer Personenkraftwagen" entnommen werden, der an allen Verkaufsstellen und bei der Deutschen Automobil Treuhand GmbH unter\xa0www.dat.de\xa0unentgeltlich erhältlich ist.':"kraftstoffverbrauch_detail", 'CO2-Emissionen':"co2_emissionen_1", 'CO2-EmissionenWeitere Informationen zum offiziellen Kraftstoffverbrauch und den offiziellen spezifischen CO2-Emissionen neuer Personenkraftwagen können dem "Leitfaden über den Kraftstoffverbrauch, die CO2-Emissionen und den Stromverbrauch neuer Personenkraftwagen" entnommen werden, der an allen Verkaufsstellen und bei der Deutschen Automobil Treuhand GmbH unter\xa0www.dat.de\xa0unentgeltlich erhältlich ist.':"co2_emissionen_2", 'StromverbrauchWeitere Informationen zum offiziellen Kraftstoffverbrauch und den offiziellen spezifischen CO2-Emissionen neuer Personenkraftwagen können dem "Leitfaden über den Kraftstoffverbrauch, die CO2-Emissionen und den Stromverbrauch neuer Personenkraftwagen" entnommen werden, der an allen Verkaufsstellen und bei der Deutschen Automobil Treuhand GmbH unter\xa0www.dat.de\xa0unentgeltlich erhältlich ist.':"stromverbrauch", "Hubraum":"hubraum_ccm", "Garantie":"garantie_monate", "Leergewicht":"leergewicht_kg"})
Damit haben wir uns nicht nur der viel zu langen Spaltennamen entledigt. Außerdem haben wir bei ein paar Spalten für die bessere Verständlichkeit auch gleich noch Maßeinheiten hinzugefügt. Jetzt sehen die Spaltennamen so aus:
‚Angebotsnummer‘,
‚Antriebsart‘,
‚Anzahl Türen‘,
‚Ausstattung‘,
‚Außenfarbe‘,
‚Bilder‘,
‚co2_emissionen_1‘,
‚co2_emissionen_2‘,
‚Erstzulassung‘,
‚Fahrzeugbeschreibung‘,
‚Fahrzeughalter‘,
‚Farbe laut Hersteller‘,
‚Feinstaubplakette‘,
‚garantie_monate‘,
‚Getriebe‘,
‚Getriebeart‘,
‚Gänge‘,
‚HU Prüfung‘,
‚HU/AU neu‘,
‚hubraum_ccm‘,
‚Innenausstattung‘,
‚Karosserieform‘,
‚Kilometerstand‘,
‚Kraftstoff‘,
‚kraftstoffverbrauch‘,
‚kraftstoffverbrauch_detail‘,
‚Lackierung‘,
‚leergewicht_kg‘,
‚Leistung‘,
‚Letzter Kundendienst‘,
‚Letzter Wechsel des Zahnriemens‘,
‚Länderversion‘,
‚Marke‘,
‚Marke, Modell‘,
‚Modell‘,
‚Modellvarianten‘,
‚Nichtraucherfahrzeug‘,
‚Region‘,
‚Schadstoffklasse‘,
‚Scheckheftgepflegt‘,
‚Schlüsselnummer‘,
‚Serviceleistungen‘,
‚Sitzplätze‘,
‚Spezielle Umbauten‘,
’stromverbrauch‘,
‚Verfügbar ab‘,
‚Verfügbarkeit‘,
‚Verkäufer‘,
‚Zustand‘,
‚Zylinder‘,
‚ausstattung_liste‘,
‚country‘,
‚date‘,
‚haendler‘,
‚ort‘,
‚price‘,
‚privat‘,
‚url‘]
Schon besser. Aber noch nicht genau das, was wir wollen. Grundsätzlich ist es für die Arbeit mit Pandas hilfreich, wenn Spaltennamen keine Leerzeichen beinhalten. Bei Pandas kann man Spalten nämlich auf zwei Arten ansprechen.
df.spalte
df["spalte"]
Die erste Variante geht viel leichter von der Hand, funktioniert jedoch nur bei Namen ohne Leerzeichen.
Außerdem erhöht es die Lesbarkeit und senkt die Fehleranfälligkeit, weder Umlaute noch irgendwelche Sonderzeichen in Feldnamen zu haben. Also löschen wir diese auch. Und zwar so:
replace_dict = {"ä":"ae", "ö":"oe", "ü":"ue", " ":"_", "/":"_"} for column in enumerate(columns): for key in replace_dict: columns[column[0]] = columns[column[0]].replace(key,replace_dict[key]).lower() df.columns = columns
Spalteninhalt
Jetzt gucken wir uns die eigentlichen Daten an säubern sie. Eine der arbeitsintensivsten Aufgaben ist es meist, die Daten ins richtige Format zu bringen. Schauen wir uns also mal die Datentypen im DataFrame an.
df.dtypes
angebotsnummer object
antriebsart object
anzahl_tueren float64
ausstattung object
außenfarbe object
bilder object
co2_emissionen_1 object
co2_emissionen_2 object
erstzulassung object
fahrzeugbeschreibung object
fahrzeughalter float64
farbe_laut_hersteller object
feinstaubplakette object
garantie_monate object
getriebe object
getriebeart object
gaenge float64
hu_pruefung object
hu_au_neu object
hubraum_ccm object
innenausstattung object
karosserieform object
kilometerstand object
kraftstoff object
kraftstoffverbrauch object
kraftstoffverbrauch_detail object
lackierung object
leergewicht_kg object
leistung object
letzter_kundendienst object
letzter_wechsel_des_zahnriemens object
laenderversion object
marke object
marke,_modell object
modell object
modellvarianten object
nichtraucherfahrzeug float64
region object
schadstoffklasse object
scheckheftgepflegt float64
schluesselnummer object
serviceleistungen object
sitzplaetze float64
spezielle_umbauten object
stromverbrauch object
verfuegbar_ab object
verfuegbarkeit object
verkaeufer object
zustand object
zylinder float64
ausstattung_liste object
country object
date object
haendler bool
ort object
price int64
privat bool
url object
dtype: object
Und natürlich sind meisten Werte als Strings gespeichert, auch die eigentlich numerischen Werte wie Erstzulassung und Kilometerstand.
CO2-Emissionen
Die ersten auffälligen Spalten beinhalten die CO2-Emission der Fahrzeuge. Diese Werte sollten eigentlich numerisch sein.
df.co2_emissionen_1.value_counts(normalize=True, dropna=False)
NaN 0.995674 0 g CO2/km (komb) 0.004326
df.co2_emissionen_2.value_counts(normalize=True, dropna=False)
NaN 0.156345 119 g CO2/km (komb) 0.030031 109 g CO2/km (komb) 0.020954 139 g CO2/km (komb) 0.018409 129 g CO2/km (komb) 0.017815 120 g CO2/km (komb) 0.017221 ... 1.190 g CO2/km (komb) 0.000085
Das Feld co2_emissionen_1 ist praktisch unbrauchbar, also können wir es löschen.
df = df.drop("co2_emissionen_1",axis=1)
Das andere Feld ist in über 84% der Fälle befüllt, allerdings im jetzigen Format auch nicht wirklich zu gebrauchen. Da die Einträge jedoch alle gleich formatiert sind, können wir relativ einfach alles außer dem Zahlenwert löschen.
df["co2_emissionen_2"] = df["co2_emissionen_2"].str.replace(".","").str.split(" ").str.get(0).astype(float)
Wir haben das Tausendertrennzeichen gelöscht, alles ab dem Leerzeichen weggeworfen und den String in eine Zahl umgewandelt. Jetzt können wir damit arbeiten.
Erstzulassung
Das Jahr der Erstzulassung muss natürlich auch numerisch sein. Hier sehen wir, warum die Spalte als Strings gespeichert wurde:
df.erstzulassung.value_counts(dropna=False,normalize=True)
2019 0.159315 2016 0.095775 2015 0.081099 ... 2011 0.044961 NaN 0.043095 ... 2006 0.021887 2005 0.019342 2004 0.017051 Nicht angegeben 0.017051 ...
Hier ist der Wert „Nicht angegeben“ das Problem. Wandeln wir ihn mal in NaN um.
df.erstzulassung = df.erstzulassung.str.replace("Nicht angegeben","NaN").astype(float)
Warum wandeln wir den die Spalten in Dezimalzahlen und nicht in Integerwerte um? Jahreszahlen sind doch eh immer Ganzzahlen. Ja, aber die Formatierung als Integer bei Pandas kann nicht mit leeren Zellen (NaN
) umgehen. Deshalb sagen wir astype(float)
und nicht astype(int)
.
Garantie
df.garantie_monate.value_counts(normalize=True,dropna=False)
NaN 0.648711 12 Monate 0.217933 24 Monate 0.080590 6 Monate 0.023838 36 Monate 0.011537 60 Monate 0.006193 3 Monate 0.004411 ...
Auch hier löschen wir wieder alles ab dem Leerzeichen.
df.garantie_monate = df.garantie_monate.str.split(" ").str.get(0).astype(float) df.garantie_monate.value_counts(normalize=True,dropna=False)
NaN 0.648711 12.0 0.217933 24.0 0.080590 6.0 0.023838 36.0 0.011537 60.0 0.006193 ...
Hubraum
df.hubraum_ccm.value_counts(normalize=True,dropna=False)
1.598 cm³ 0.082117 1.968 cm³ 0.074483 1.995 cm³ 0.056413 999 cm³ 0.052426 NaN 0.043773 1.242 cm³ 0.034866 2.143 cm³ 0.025110 1.997 cm³ 0.024516
Hier löschen wir einfach alles, was keine Zahl ist. Das löst auch gleichzeitig das Problem mit dem Punkt als Tausendertrennzeichen, der in Pandas eigentlich der Dezimaltrenner ist.
df.hubraum_ccm = df.hubraum_ccm.str.findall(r'[0-9]+').str.join("").astype(float) df.hubraum_ccm.value_counts(normalize=True,dropna=False)
1598 0.082117 1968 0.074483 1995 0.056413 999 0.052426 NaN 0.043773 1242 0.034866 ...
Kilometerstand
df.kilometerstand.value_counts(normalize=True,dropna=False)
NaN 0.784781 10 km 0.009501 Nicht angegeben 0.007720 15 km 0.003308 5 km 0.001951 3.000 km 0.001612 100 km 0.001527 50 km 0.001018 9.900 km 0.000933
df.kilometerstand = df.kilometerstand.str.replace("Nicht angegeben","NaN").str.replace(".","").str.replace(" km","").astype(float) df.kilometerstand.value_counts(normalize=True,dropna=False)
NaN 9342 10.0 112 15.0 39 5.0 23 3000.0 19 100.0 18 50.0 12 9900.0 11 4449.0 9 9500.0 9 160000.0 9
Kraftstoffverbrauch
Hier gibt es mehre Spalten.
df.kraftstoffverbrauch.value_counts(normalize=True,dropna=False)
NaN 0.784781 Nicht angegeben 0.019342 6.0 l/100 km (komb) 0.008483 5.0 l/100 km (komb) 0.008059 5.3 l/100 km (komb) 0.007211 5.9 l/100 km (komb) 0.006956 5.1 l/100 km (komb) 0.006702 5.5 l/100 km (komb) 0.006193 5.2 l/100 km (komb) 0.005938 4.9 l/100 km (komb) 0.005853 6.2 l/100 km (komb) 0.005853 4.8 l/100 km (komb) 0.005769 4.5 l/100 km (komb) 0.005514
Nur 78% der Zellen sind befüllt, suboptimal. Wie sieht’s in der anderen Spalte aus?
df.kraftstoffverbrauch_detail.value_counts(normalize=True,dropna=False)
NaN 0.149050 5,6 l/100 km (komb)6,8 l/100 km (innerorts)4,9 l/100 km (außerorts) 0.005344 5,2 l/100 km (komb)5,9 l/100 km (innerorts)4,7 l/100 km (außerorts) 0.005090 4,1 l/100 km (komb)4,9 l/100 km (innerorts)3,7 l/100 km (außerorts) 0.004326 4,8 l/100 km (komb)5,8 l/100 km (innerorts)4,2 l/100 km (außerorts) 0.003987 4,7 l/100 km (komb) 0.003733 5,9 l/100 km (komb)7,5 l/100 km (innerorts)5 l/100 km (außerorts) 0.003648 5,3 l/100 km (komb)6,6 l/100 km (innerorts)4,5 l/100 km (außerorts) 0.003563 4,1 l/100 km (komb)5 l/100 km (innerorts)3,6 l/100 km (außerorts) 0.003393 5,8 l/100 km (komb)7 l/100 km (innerorts)5 l/100 km (außerorts) 0.003224 4,9 l/100 km (komb)5,8 l/100 km (innerorts)4,4 l/100 km (außerorts) 0.003224 4,6 l/100 km (komb)5,5 l/100 km (innerorts)4,1 l/100 km (außerorts) 0.003139
Hier stehen gleich mehrere relevante Zahlen in einer Zelle. Nämlich der Verbrauch innerorts, außerorts und der kombinierte Kraftstoffverbrauch.
Wir tun jetzt zwei Dinge. Zuerst löschen wir die erste der beiden Spalten. Denn wenn man die beiden Spalten Zeile für Zeile miteinander vergleicht, dann fällt einem auf, dass der Wert aus der ersten Spalte auch immer in der zweite Spalte steht, sofern in der ersten Spalte überhaupt etwas steht.
df = df.drop("kraftstoffverbrauch", axis=1)
Weil uns alle drei Eigenschaften des Kraftstoffverbrauchs interessieren, splitten wir die eine Spalte in drei Teile. Das machen wir so:
df["kraftstoffverbrauch_komb"], df["kraftstoffverbrauch_inner"], df["kraftstoffverbrauch_außer"] = df.kraftstoffverbrauch_detail.str.split(")",2).str
Wir haben die schließende Klammer als die Stelle genommen, an der gesplittet werden soll. Jetzt haben wir drei einzelne Spalten, die wir wieder säubern. Das gestaltet sich aber gar nicht so einfach. Die meisten Zellen sind mit Strings wie z.B. „4,6 l/100km (innerorts“ oder „7,1 kg/100km(innerorts“ befüllt. Bei beiden Einträgen könnte man einfach alles ab dem ersten Leerzeichen löschen und den Teil davor zu einem Float-Wert konvertieren. Manche Zellen haben aber keine Leerzeichen, weil sie entweder nur aus einem leeren String oder anderem Unsinn bestehen. Deshalb habe ich eine kleine Hilfsfunktion gebaut.
def extract_verbrauch(cell): cell_str = str(cell) value_list = [] if len(cell_str)>0 and cell_str!="nan" and cell_str[0].isnumeric(): i = cell_str[0] while i.isnumeric() or i==",": value_list.append(i) cell_str = cell_str[1:] i = cell_str[0] joined = "".join(value_list).replace(",",".") return float(joined) else: return np.nan
Die Funktion können wir dann mit .apply()
auf die Spalten anwenden.
df["kraftstoffverbrauch_komb"] = df["kraftstoffverbrauch_komb"].apply(extract_verbrauch) df["kraftstoffverbrauch_inner"] = df["kraftstoffverbrauch_inner"].apply(extract_verbrauch) df["kraftstoffverbrauch_außer"] = df["kraftstoffverbrauch_außer"].apply(extract_verbrauch)
Und weiter zur Motorleistung!
Leistung
df.leistung.value_counts(normalize=True,dropna=False)
NaN 0.784781 110 kW / 150 PS 0.026468 140 kW / 190 PS 0.011622 85 kW / 116 PS 0.008907 103 kW / 140 PS 0.007974 66 kW / 90 PS 0.006023 81 kW / 110 PS 0.005853 92 kW / 125 PS 0.005769 100 kW / 136 PS 0.005599 125 kW / 170 PS 0.005344 55 kW / 75 PS 0.005005 135 kW / 184 PS 0.004920
Auch hier haben wir wieder verschiedene Merkmale, die in einer Spalte zusammengefasst sind. Und wieder splitten und säubern wir sie.
df["leistung_kw"], df["leistung_ps"] = df.leistung.str.replace("[kW,PS," "]","",regex=True).str.split("/",1).str df = df.drop("leistung",axis=1)
Leergewicht
df.leergewicht_kg.value_counts(dropna=False,normalize=True).iloc[:10]
NaN 3110 1.320 kg 221 1.505 kg 157 1.395 kg 115 1.385 kg 103 960 kg 95 1.055 kg 84 1.165 kg 82 1.250 kg 76 1.615 kg 75
Hier schmeißen wir wieder alles raus, was nicht numerisch ist.
df["leergewicht_kg"] = df["leergewicht_kg"].str.findall(r'[0-9]+').str.join("").values.astype(float)
Datumsangaben
Im DataFrame existieren mehrere Spalten, die Datumsangaben enthalten. Diese sind
- hu_pruefung
- letzter_kundendienst
- letzter_wechsel_des_zahnriemens
Alle genannten Datumsangaben haben das Format „MM/YYYY“ und sind als Strings gespeichert. Damit können wir nicht viel anfangen. Um diese Informationen auswerten zu können, bringen wir sie mit der Funktion pd.to_datetime()
in ein von Pandas erkennbares Datumsformat.
date_columns = ["hu_pruefung", "letzter_kundendienst", "letzter_wechsel_des_zahnriemens"] for column in date_columns: print(column) df[column] = pd.to_datetime(df[column])
Und schon können wir mir den Datumsangaben auch etwas anfangen.
Leere und unnötige Spalten löschen
Zum Schluss löschen wir noch Spalten, mit denen wir eh nichts anfangen können. Schauen wir uns mal an, welche Spalten leer sind.
for col in df: if df[col].isnull().mean()==1.0: print(col)
nichtraucherfahrzeug scheckheftgepflegt
Die beiden Spalten oben sind leer und können entfernt werden. Es ist natürlich möglich, dass bei deinem Projekt andere oder gar keine Spalten leer sind. Das hängt auch davon ab, wie viele Daten du letztendlich sammelst.
df = df.drop("nichtraucherfahrzeug", axis=1) df = df.drop("scheckheftgepflegt", axis=1)
Außerdem können wir mit der Spalte „marke,_modell“ nichts anfangen, weil hier nur die Information aus zwei anderen Spalten, die schon vorhanden sind, zusammengeworfen werden.
df = df.drop("marke,_modell",axis=1)
Das war’s
So, die Daten sind jetzt erst mal grundlegend gesäubert. Was haben wir alles gemacht?
- Spalten, die numerisch sein sollen, auch wirklich in Zahlenwerte umgewandelt
- Spalten mit mehreren Merkmalen voneinander getrennt
- Datumsangaben konvertiert
- Leere Spalten gelöscht
Mit den gesäuberten Daten kannst du jetzt entweder direkt weiter arbeiten oder sie wieder als CSV abspeichern. Beim erneuten Einlesen musst du dann allerdings die Datumsspalten wieder in ein von Pandas lesbares Format bringen (wie oben), weil diese Spalten als Strings abgespeichert werden.
gibt es hier auch den vollständigen Code?