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)