Эффективный рентген таблицы
Разберем возможности получения важных описательных характеристик таблицы в библиотеке Pandas, а затем соберем их вместе и напишем функцию для многократного использования. Она поможет сэкономить колоссальное время в будущем при изучении новых таблиц с данными, а также позволит своевременно выявлять в них малозаметные ошибки.
Для демонстрации работы будем использовать игрушечную таблицу (код для генерации представлен в конце статьи), содержащую информацию о поломках машин, а именно - тип машины, флаг наличия дефекта, дату поломки, дату поставки (начала эксплуатации), разницы между этими датами (в месяцах):
Перечислим, какие общие сведения о колонках нас могут интересовать:
- тип данных;
- количество уникальны значений;
- список уникальных значений;
- максимальное и минимальное значение;
- максимальная и минимальная длина поля.
Тип данных можно получить с помощью свойства столбца dtype, уникальные значения посредством вызова метода drop_duplicates, их число - вызвав свойство shape. Остальные сведения извлекаются в зависимости от типа. В object хранятся данные смешанного типа и строки, а с остальными грубо будем работать как с числами и датами. В результате, для диагностики столбца получим следующую функцию:
def df_col_info(df_col): info={} info['type'] = df_col.dtype unique = df_col.drop_duplicates() info['uniq_num'] = unique.shape[0] info['uniq'] = unique if df_col.dtype=='object': info['len_max'] = df_col.str.len().max() info['len_min'] = df_col.str.len().min() info['min'] = df_col.astype(str).min() info['max'] = df_col.astype(str).max() else: info['min'] = df_col.min() info['max'] = df_col.max() return info
Рассмотрим ее работу на примере вывода значения столбца дата_поломки:
Обобщая применение df_col_info для каждой колонки датафрейма создадим еще пару функций:
def df_info(df): return get_df_info(df, df_col_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)