Pandas DataFrame-Validierung mit Bulwark#
Bulwark ist ein Paket zum eigenschaftsbasierten Testen von pandas-Dataframes. Das Projekt wurde stark von der nicht mehr unterstützten Engarde-Bibliothek beeinflusst.
1. Installation#
$ pipenv install bulwark
Installing bulwark…
Adding bulwark to Pipfile's [packages]…
✔ Installation Succeeded
Locking [dev-packages] dependencies…
✔ Success!
Updated Pipfile.lock (0d075a)!
2. Verwendung#
2.1 Überprüfungen#
Mit dem bulwark.checks-Modul könnt ihr viele gängige Annahmen überprüfen, z.B.
has_columns
überprüft, ob bestimmte Spalten so oder so ähnlich vorhanden und in der richtigen Reihenfolge sindhas_dtypes
überprüft die Datentypen von Spaltenhas_no_infs
überprüft, ob keine numpy.inf im DataFrame vorhanden sindhas_no_nans
überprüft, ob es keine numpy.nan im DataFrame vorhanden sindhas_set_within_vals
überprüft, ob die in einem dict angegebenen Werte eine Teilmenge der zugehörigen Spalte sindhas_unique_index
überprüft, ob der Index eindeutig istis_monotonic
überprüft, ob Werte einer Spalte aufsteigend oder absteigend sindone_to_many
überprüft, ob zwischen zwei Spalten eine n:1-Beziehung besteht
Die Überprüfungen sind dann sehr simpel, z.B. der Check, ob in der Spalte pipe
keine numpy.nan
vorhanden sind mit
import bulwark.checks as ck
df.pipe(ck.has_no_nans())
2.2 Decorators#
Für jeden Check erstellt bulwark.decorators, z.B. @dc.IsShape((-1, 10))
oder @dc.IsMonotonic(strict=True)
.
CustomCheck
#
Ihr könnt auch eure eigenen benutzerdefinierten Funktionen erstellen, z.B.:
[1]:
import bulwark.checks as ck
import bulwark.decorators as dc
import numpy as np
import pandas as pd
def len_longer_than(df, l):
if len(df) <= l:
raise AssertionError("df is not as long as expected.")
return df
@dc.CustomCheck(len_longer_than, 10)
def append_a_df(df, df2):
return df.append(df2, ignore_index=True)
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
df2 = pd.DataFrame({"a": [1, np.nan, 3, 4], "b": [4, 5, 6, 7]})
append_a_df(df, df2)
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
/var/folders/f8/0034db6d78s5r6m34fxhpk7m0000gp/T/ipykernel_96383/314667641.py in <module>
16 df2 = pd.DataFrame({"a": [1, np.nan, 3, 4], "b": [4, 5, 6, 7]})
17
---> 18 append_a_df(df, df2)
~/cusy/trn/jupyter-tutorial-de/lib/python3.9/site-packages/bulwark/decorators.py in decorated(*args, **kwargs)
79 if self.enabled:
80 # differs from BaseDecorator
---> 81 ck.custom_check(df, self.check_func, **self.check_func_params)
82 return df
83 return decorated
~/cusy/trn/jupyter-tutorial-de/lib/python3.9/site-packages/bulwark/checks.py in custom_check(df, check_func, *args, **kwargs)
586 """
587 try:
--> 588 check_func(df, *args, **kwargs)
589 except AssertionError as e:
590 msg = "{} is not true.".format(check_func.__name__)
/var/folders/f8/0034db6d78s5r6m34fxhpk7m0000gp/T/ipykernel_96383/314667641.py in len_longer_than(df, l)
6 def len_longer_than(df, l):
7 if len(df) <= l:
----> 8 raise AssertionError("df is not as long as expected.")
9 return df
10
AssertionError: len_longer_than is not true.
MultiCheck
#
Mit MultiCheck
könnt ihr mehrere Tests gleichzeitig ausführen und alle Fehler auf einmal sehen, z.B.:
[2]:
@dc.MultiCheck(checks={ck.has_no_nans: {"columns": None},
len_longer_than: {"l": 6}},
warn=False)
def append_a_df(df, df2):
return df.append(df2, ignore_index=True)
df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]})
df2 = pd.DataFrame({"a": [1, np.nan, 3, 4], "b": [4, 5, 6, 7]})
append_a_df(df, df2)
---------------------------------------------------------------------------
AssertionError Traceback (most recent call last)
/var/folders/f8/0034db6d78s5r6m34fxhpk7m0000gp/T/ipykernel_96383/128872624.py in <module>
8 df2 = pd.DataFrame({"a": [1, np.nan, 3, 4], "b": [4, 5, 6, 7]})
9
---> 10 append_a_df(df, df2)
~/cusy/trn/jupyter-tutorial-de/lib/python3.9/site-packages/bulwark/decorators.py in decorated(*args, **kwargs)
22 df = f(*args, **kwargs)
23 if self.enabled:
---> 24 self.check_func(df, **self.check_func_params)
25 return df
26 return decorated
~/cusy/trn/jupyter-tutorial-de/lib/python3.9/site-packages/bulwark/checks.py in multi_check(df, checks, warn)
568 return df
569 elif error_msgs:
--> 570 raise AssertionError("\n".join(str(i) for i in error_msgs))
571
572 return df
AssertionError: (4, 'a')