Эффективный рентген таблицы
Разберем возможности получения важных описательных характеристик таблицы в библиотеке 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)