Pandas DataFrame-Validierung mit Engarde#
Engarde befindet sich nicht mehr in aktiver Entwicklung Schaut Euch das Bulwark-Tool für ähnliche Funktionen an.
In diesem Notebook überprüfen wir pandas.DataFrame
-Objekte mit der Bibliothek engarde. Mit engarde könnt ihr sowohl Decorators für Funktionen schreiben als auch integrierte Funktionen verwenden, um euren DataFrame mit bestimmten Validierungsregeln oder -definitionen zu testen.
1. Importe#
[1]:
import pandas as pd
import engarde.decorators as ed
from datetime import datetime
2. Daten lesen#
[2]:
sales = pd.read_csv('https://raw.githubusercontent.com/kjam/data-cleaning-101/master/data/sales_data_duped_with_nulls.csv')
3. Daten überprüfen#
[3]:
sales.head()
[3]:
timestamp | city | store_id | sale_number | sale_amount | associate | |
---|---|---|---|---|---|---|
0 | 2017-09-15T06:17:10 | Alexandrabury | 18 | 1043.0 | 15.0 | Stacey Daniels |
1 | 2017-09-11T16:16:30 | East Jesusport | 2 | 1729.0 | 396.0 | Haley Pitts |
2 | 2017-07-12T15:00:18 | New Douglasmouth | 13 | 2028.0 | -78.0 | Carlos French |
3 | 2017-07-29T13:04:55 | West Carriemouth | 19 | 1245.0 | 1149.0 | Jeffrey Ford |
4 | 2017-11-07T21:35:58 | Port Timothy | 1 | 2365.0 | 724.0 | Christopher West |
[4]:
sales.dtypes
[4]:
timestamp object
city object
store_id int64
sale_number float64
sale_amount float64
associate object
dtype: object
Datentypen überprüfen#
Engarde lässt uns Datentypen nachverfolgen. In einer ersten Funktion sollten wir also unsere erwarteten Ergebnisse überpfüfen.
[5]:
new_dtypes = {
'timestamp': object,
'city': object,
'store_id': int,
'sale_number': float,
'sale_amount': float,
'associate': object
}
[6]:
@ed.has_dtypes(new_dtypes)
@ed.is_shape((None, 6))
def update_dtypes(sales):
sales.timestamp = sales.timestamp.map(
lambda x: datetime.strptime(
x, '%Y-%m-%dT%H:%M:%S').date())
return sales
[7]:
sales = update_dtypes(sales)
[8]:
sales.timestamp.iloc[0]
[8]:
datetime.date(2017, 9, 15)
5. Entfernen ungenügender Daten#
Um Daten von schlechter Qualität zu entfernen, entfernen wir zunächst Duplikate und fehlende Einträge.
[9]:
@ed.has_dtypes(new_dtypes)
@ed.is_shape((None, 6))
@ed.none_missing()
def remove_poor_quality_data(sales):
sales = sales.drop_duplicates()
sales = sales.dropna(subset=['sale_amount', 'store_id',
'sale_number',
'city', 'associate'])
return sales
[10]:
sales = remove_poor_quality_data(sales)
[11]:
sales.isnull().any()
[11]:
timestamp False
city False
store_id False
sale_number False
sale_amount False
associate False
dtype: bool
[12]:
final_types = new_dtypes.copy()
final_types.update({
'store_total': float,
'associate_total': object,
'city_total': float
})
[13]:
@ed.has_dtypes(final_types)
@ed.none_missing()
def calculate_store_sales(sales):
sales['store_total'] = sales.groupby(
'store_id').transform(sum)['sale_amount']
sales['associate_total'] = sales.groupby(
'associate').transform(sum)['sale_amount']
sales['city_total'] = sales.groupby('city')[
'sale_amount'].transform(sum)
return sales
[14]:
sales.head()
[14]:
timestamp | city | store_id | sale_number | sale_amount | associate | |
---|---|---|---|---|---|---|
0 | 2017-09-15 | Alexandrabury | 18 | 1043.0 | 15.0 | Stacey Daniels |
1 | 2017-09-11 | East Jesusport | 2 | 1729.0 | 396.0 | Haley Pitts |
2 | 2017-07-12 | New Douglasmouth | 13 | 2028.0 | -78.0 | Carlos French |
3 | 2017-07-29 | West Carriemouth | 19 | 1245.0 | 1149.0 | Jeffrey Ford |
4 | 2017-11-07 | Port Timothy | 1 | 2365.0 | 724.0 | Christopher West |
[15]:
sales = calculate_store_sales(sales)