Daten laden, kombinieren und prüfen#

Mit pandas können Daten aus verschiedenen Dateiformaten eingelesen und kombiniert werden. Zusätzlich wollen wir uns ansehen, wie eine erste Qualitätsprüfung der Daten durchgeführt werden kann.

Wir nutzen für die folgenden Übungen Teile eines Datensatzes mit Nachrichtenartikeln, veröffentlicht von:

  • Misra, Rishabh. “News Category Dataset.” arXiv preprint arXiv:2209.11429 (2022).

  • Misra, Rishabh and Jigyasa Grover. “Sculpting Data for ML: The first act of Machine Learning.” ISBN 9798585463570 (2021).

  • Lizenz: CC-BY 4.0

  • Kaggle: https://www.kaggle.com/datasets/rmisra/news-category-dataset

# pandas importieren
import pandas as pd
# Import und Initialisierung von bia-bob
from bia_bob import bob
# API Key wird aus condas Umgebungsvariable gelesen
bob.initialize(endpoint='blablador', model='alias-fast')
This notebook may contain text, code and images generated by artificial intelligence. Used model: alias-fast, vision model: None, endpoint: https://helmholtz-blablador.fz-juelich.de:8000/v1, bia-bob version: 0.26.1.. Do not enter sensitive or private information and verify generated contents according to good scientific practice. Read more: https://github.com/haesleinhuepf/bia-bob#disclaimer

Daten aus einer Datei laden#

Schauen wir uns zunächst an, wie Daten aus einer JSON-Datei geladen werden. Hierfür nutzen wir read_json(). Der damit erstellte DataFrame wird in der Variable df1 gespeichert.

df1 = pd.read_json('../data/news_category_data_2020.json', lines=True)

Wir können unseren KI-Assistenten nutzen, um zunächst einen kurzen Überblick über die Daten zu bekommen.

%%bob
Beschreibe mir kurz den Inhalt und die Spalten des DataFrame df1 mit {df1.columns} und {df1.index}.
KEIN Code, antworte in Deutsch
Die Daten enthalten Bemeldungen aus verschiedenen Kategorien. Jede Zeile des Datensatzes stellt eine einzelne Meldung dar, die durch einen Link auf eine Webseite referenziert wird. Hier sind die Spalten und deren Inhalte im Detail:
  • headline: Diese Spalte enthält den Titel der Meldung.

  • category: Diese Spalte gibt die Kategorie der Meldung an, z.B. POLITIK, COMEDY, ENTERTAINMENT, WORLD NEWS, U.S. NEWS, WELLNESS.

  • short_description: Diese Spalte gibt eine kurze Beschreibung der Meldung.

  • authors: Diese Spalte gibt die Autoren der Meldung an.

  • date: Diese Spalte gibt das Datum der Meldung an.

Die Spalten sind alle als string oder datetime definiert.

Lass dir mit den aus der vorhergehenden Übung bekannten Methoden des DataFrame weitere detaillierte Infos zum Datensatz anzeigen

# Ausgabe der Metadaten
# Ausgabe der ersten n Zeilen
# Ausgabe beschreibender Statistiken für alle Spalten mit Datentyp "object"
# Ausgabe der vorhandenen Kategorien in der Spalte "category"

Zusammenführen von DataFrames#

Oft müssen Daten für eine Analyse aus verschiedenen Datenquellen zusammengeführt werden. pandas unterstützt das Zusammenführen von DataFrames durch verschiedene Methoden. Siehe dazu auch den entsprechenden User Guide: Merge, Join, Concatenate.

Wir wollen uns das am Beispiel zwei weiterer Datensätze in teils unterschiedlichen Formaten ansehen, die wir hierzu laden.

Beginnen wir mit dem Datensatz /data/news_category_data_2021.json.

df2 = pd.read_json('../data/news_category_data_2021.json', lines=True)
# Ausgabe der Metadaten
df2.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2066 entries, 0 to 2065
Data columns (total 6 columns):
 #   Column             Non-Null Count  Dtype         
---  ------             --------------  -----         
 0   link               2066 non-null   object        
 1   headline           2066 non-null   object        
 2   category           2066 non-null   object        
 3   short_description  2066 non-null   object        
 4   authors            2066 non-null   object        
 5   date               2066 non-null   datetime64[ns]
dtypes: datetime64[ns](1), object(5)
memory usage: 97.0+ KB

Der Datensatz für 2021 scheint das gleiche Format (Spaltennamen, Datentypen) zu haben, wie der vorhergehende.

Hier bietet sich concat() für ein einfaches Aneinanderfügen an.

df12 = pd.concat([df1, df2])
# Ausgabe der Metadaten
df12.info()
<class 'pandas.core.frame.DataFrame'>
Index: 4120 entries, 0 to 2065
Data columns (total 6 columns):
 #   Column             Non-Null Count  Dtype         
---  ------             --------------  -----         
 0   link               4120 non-null   object        
 1   headline           4120 non-null   object        
 2   category           4120 non-null   object        
 3   short_description  4120 non-null   object        
 4   authors            4120 non-null   object        
 5   date               4120 non-null   datetime64[ns]
dtypes: datetime64[ns](1), object(5)
memory usage: 225.3+ KB
# Überprüfen des Index auf Duplikate (soll keine Duplikate enthalten)
df12.index.duplicated().any()
True

Sehen wir uns jetzt den dritten Datensatz an: /data/news_category_data_2022.csv. Dieser liegt im Dateiformat CSV vor und kann mit read_csv() eingelesen werden.

df3 = pd.read_csv('../data/news_category_data_2022.csv', sep='|')
# Ausgabe der Metadaten
df3.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1398 entries, 0 to 1397
Data columns (total 6 columns):
 #   Column       Non-Null Count  Dtype 
---  ------       --------------  ----- 
 0   link         1398 non-null   object
 1   headline     1398 non-null   object
 2   category     1398 non-null   object
 3   description  1398 non-null   object
 4   authors      1258 non-null   object
 5   date         1398 non-null   object
dtypes: object(6)
memory usage: 65.7+ KB

Hier zeigen sich folgende Unterschiede / Problempunkte:

  • Eine Spalte ist anders bezeichnet

  • Der Datentyp in date ist ein anderer

  • Es scheinen einige Einträge bei authors zu fehlen (dazu später mehr)

pd.concat([df12, df3]).info()
<class 'pandas.core.frame.DataFrame'>
Index: 5518 entries, 0 to 1397
Data columns (total 7 columns):
 #   Column             Non-Null Count  Dtype 
---  ------             --------------  ----- 
 0   link               5518 non-null   object
 1   headline           5518 non-null   object
 2   category           5518 non-null   object
 3   short_description  4120 non-null   object
 4   authors            5378 non-null   object
 5   date               5518 non-null   object
 6   description        1398 non-null   object
dtypes: object(7)
memory usage: 344.9+ KB

Bei einem einfachen concat() werden beide Spalten mit unterschiedlichem Namen behalten, diese beinhalten dann entsprechend viele Fehlwerte. Zudem wurde der Datentyp in date jetzt zu dem allgemeinen Typ object zusammengefasst.

Es bietet sich daher vor den Zusammenfügen an in df3

  • …die Spalte description in short_description umzunennen

  • …den Datentyp der Spalte date in datetime64 umzuwandeln

Lass dir hier vom KI-Assistenten helfen

%%bob

Mit dem angepassten dritten Datensatz können jetzt alle Daten zusammengeführt werden. Überprüfe das Ergebnis.

# df_all = pd.concat(...)

Speichere den aktuellen DataFrame als Zwischenergebnis als CSV unter ../data/news_category_data_all.csv

# df_all.to_csv(...)

Prüfen und Bereinigen#

Daten haben oftmals nicht die für eine Analyse notwendige Qualität. Dies betrifft in unserem Fall fehlende Werte in den Daten. Bei numerischen Daten kommen häufig noch Ausreißer dazu.

Wir wollen uns für diesen Datensatz einmal den Punkt Fehlwerte anschauen - also Einträge, die entweder Null oder ein leerer String sind. pandas bietet umfassende Möglichkeiten, Fehlwerte zu erkennen und mit ihnen umzugehen, siehe dazu auch User Guide: Working with missing data

Wir laden uns zunächst das Zwischenergebnis aus /data/news_category_data_all.csv und sehen uns die Metadaten sowie die Zeilen 20 bis 30 an.

df_all = pd.read_csv('../data/news_category_data_all.csv', sep='|', parse_dates=[5])
df_all.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 5518 entries, 0 to 5517
Data columns (total 6 columns):
 #   Column             Non-Null Count  Dtype         
---  ------             --------------  -----         
 0   link               5518 non-null   object        
 1   headline           5518 non-null   object        
 2   category           5518 non-null   object        
 3   short_description  5518 non-null   object        
 4   authors            5061 non-null   object        
 5   date               5518 non-null   datetime64[ns]
dtypes: datetime64[ns](1), object(5)
memory usage: 258.8+ KB
df_all.iloc[20:31]
link headline category short_description authors date
20 https://www.huffpost.com/entry/trump-dc-hotel-... Trump's D.C. Hotel Appears To Concede Election... POLITICS The Trump International Hotel in Washington, D... David Moye 2020-12-28
21 https://www.huffpost.com/entry/best-buys-from-... The 20 Finds That Helped Our Shopping Editors ... HOME & LIVING Including a meal kit for lunch during the work... Ambar Pardilla 2020-12-28
22 https://www.huffpost.com/entry/anthony-quinn-w... Nashville Bombing Suspect Told Neighbor: The W... CRIME Anthony Quinn Werner reportedly made the chill... Kimberlee Kruesi, Michael Balsamo and Michael ... 2020-12-28
23 https://www.huffpost.com/entry/tony-rice-blueg... Tony Rice, Master Bluegrass Guitarist, Dies At 69 ENTERTAINMENT His last live guitar performance was in 2013, ... NaN 2020-12-28
24 https://www.huffpost.com/entry/european-union-... European Union Kicks Off COVID-19 Vaccine Camp... WORLD NEWS The 27-nation bloc began administering the fir... Nicole Winfield and Vanessa Gera, AP 2020-12-27
25 https://www.huffpost.com/entry/the-best-books-... The Best Books Of 2020 CULTURE & ARTS The 10 reads -- from Emily St. John Mandel, Ra... Claire Fallon 2020-12-27
26 https://www.huffpost.com/entry/dan-rather-dona... Dan Rather Rips 'Abject Cruelty' Of Trump's 'M... POLITICS The president, relaxing at Mar-a-Lago, left "d... Mary Papenfuss 2020-12-27
27 https://www.huffpost.com/entry/rockford-illino... Illinois Bowling Alley Shooting Leaves 3 Dead,... CRIME A 37-year-old male suspect was in custody afte... NaN 2020-12-27
28 https://www.huffpost.com/entry/nashville-polic... Nashville Police Believe Man Responsible For C... CRIME Investigators linked Anthony Quinn Warner, 63,... Sanjana Karanth 2020-12-27
29 https://www.huffpost.com/entry/bernie-sanders-... Bernie Sanders: Trump Needs To Stop 'Diddling ... POLITICS "We may be looking at a government shutdown in... Jeremy Blum 2020-12-27
30 https://www.huffpost.com/entry/andrew-kacynski... CNN's Andrew Kaczynski Mourns Death Of Baby Da... U.S. NEWS “We’re heartbroken to have to announce our bea... Mary Papenfuss 2020-12-26

Wie wir sehen, gibt es Zeilen, die NaNs enthalten - die von pandas genutzte Representation von Fehlwerten. Eine Überprüfung, ob irgendwo in einem DataFrame NaNs enthalten sind, ist eine wichtige erste Qualitätsprüfung vor jeder Datenanalyse. Pandas’ isna() bietet hierfür eine boolesche Maskierung des DataFrame mit True / False Werten, wobei True ein NaN anzeigt.

df_all.isna().iloc[20:31]
link headline category short_description authors date
20 False False False False False False
21 False False False False False False
22 False False False False False False
23 False False False False True False
24 False False False False False False
25 False False False False False False
26 False False False False False False
27 False False False False True False
28 False False False False False False
29 False False False False False False
30 False False False False False False

Mit dieser booleschen Maskierung können wir weitere Analysen zu Fehlwerten durchführen. Und da True / False auch als 1 / 0 interpretiert wird, können wir damit auch rechnen.

# Ausgeben, ob Fehlwerte enthalten sind
df_all.isna().values.any()
True
# Spaltenweises Zählen der NaN
df_all.isna().sum()
link                   0
headline               0
category               0
short_description      0
authors              457
date                   0
dtype: int64

Nutze den KI-Assistenten, um dir eine Liste der Indizes aller Zeilen mit NaN zu erstellen

%%bob

Es gibt mehrere Wege, mit Fehlwerten umzugehen. Diese können insbesondere bei numerischen Daten z.b. durch Interpolation oder Einsetzen eines Mittelwertes aufgefüllt werden. Bei diesen Ansätzen sollte aber immer beachtet werden, dass ein Auffüllen fehlender Werte den Datensatz und seine statistischen Eingenschaften verzerren kann. Im Gegensatz dazu können Einträge mit Fehlwerten auch einfach aus dem Datensatz entfernt werden, insofern dieser dann für die weitere Analyse nicht zu stark augedünnt wird.

In unseren Fall lassen wir pandas mittels dropna() einfach alle Zeilen aus dem Datensatz entfernen, welche ein NaN enthalten, und speichern das Ergebnis als CSV unter /data/news_category_data_prep.csv.

# df_all.dropna(...)
# ...