Мусорная реформа данных
Разберем диагностические средства библиотеки Pandas для определения мусора в данных. Полученные результаты агрегируем и напишем функцию, чтобы избавить себя от рутинной работы.
В качестве примера воспользуемся игрушечным набором (рассмотрен при изучении описательных характеристик таблицы), содержащим информацию о поломках машин, а именно - тип машины, флаг наличия дефекта, дату поломки, дату поставки (начала эксплуатации), разницы между этими датами (в месяцах):
В качестве мусорных нас прежде всего интересуют незаполненные и нулевые значения, пустые строки. Для получения незаполненных значений можно воспользоваться методом isnull, а пустых и нулевых - операциями сравнения. Кроме того, нас могут интересовать индексы "мусорных" строк, которые можно получить, обратившись к свойству index.
На этой базе напишем следующую функцию:
def df_col_rubbish_info(df_col): info={} info['null_idx'] = df_col[df_col.isnull()].index info['null_num'] = df_col[df_col.isnull()].shape[0] info['null_pct'] = df_col[df_col.isnull()].shape[0]/df_col.shape[0] if df_col.dtype!='object': info['zero_idx'] = df_col[df_col == 0].index info['zero_num'] = df_col[df_col == 0].shape[0] info['zero_pct'] = df_col[df_col == 0].shape[0]/df_col.shape[0] else: info['empty_idx'] = df_col[df_col == ''].index info['empty_num'] = df_col[df_col == ''].shape[0] info['empty_pct'] = df_col[df_col == ''].shape[0]/df_col.shape[0] return info
Рассмотрим ее применение на примере столбца дата_поломки:
Для применения df_col_rubbish_info ко всей таблице потребуется в цикле вызвать ее на каждой колонке, что и сделано в приведенных ниже функциях:
def df_rubbish_info(df): return get_df_info(df, df_col_rubbish_info) def get_df_info(df, df_col_f): info_d = {} for col in df.columns: info_d[col] = df_col_f(df[col]) return info_d
Код для генерации набора представлен ниже:
import pandas as pd import numpy as np # генерируем список типов машин np.random.seed(0) car_types = ['type1', 'type2', 'type3', 'type4'] car_nums = np.random.randint(25, 100, size=len(car_types)) cars_l = [[car_type]*car_num for car_type, car_num \ in zip(car_types, car_nums)] cars_l = [item for sub_l in cars_l for item in sub_l] # генерируем в случайном порядке флаги наличия поломок для машин разных типов defects_num = [np.random.randint(car_num+1) for car_num in car_nums] defects_ar = np.array([]) for i, car_num in enumerate(car_nums): defects_car = np.zeros(car_num) idx = np.random.choice(np.arange(car_num),size=defects_num[i], replace=False) defects_car[idx]=1 defects_ar = np.concatenate((defects_ar,defects_car)) # формируем датафрейм data = pd.DataFrame({'типы_машин':cars_l, 'наличие_дефекта':defects_ar}) # задаем даты поломок произвольно из заданного периода defects_dates = pd.date_range(start='2019-01-01',end='2020-12-31',freq='D') idx = np.random.choice(np.arange(len(defects_dates)), size=int(sum(defects_ar)), replace=True) defects_dates_col=pd.Series(data=defects_dates[idx], index=data[data['наличие_дефекта']==1].index) data['дата_поломки'] = defects_dates_col # задаем в случайном порядке даты ввода в эксплуатацию машин start_dates = pd.date_range(start='2018-06-01', end='2019-01-01', freq='D') idx = np.random.choice(np.arange(len(start_dates)), size=data.shape[0], replace=True) data['дата_поставки'] = pd.Series(data=start_dates[idx]) # считаем разницу в месяцах между датами поломок и поставок машин data['разница'] = data['дата_поломки'] - data['дата_поставки'] data['разница'] = data['разница'].map(lambda s: np.ceil(s.days/30)) # перемешиваем данные data = data.sample(frac=1)