Когнитивные искажения у аналитика данных: найти и починить

df.head() — с этого момента вы начинаете работу с данными и полагаетесь на увиденное? Я тоже. Так мы наступаем в феномен what you see is all there is. У ограниченного набора данных, возможно, отсортированного, мы видим ещё более ограниченный набор данных. Мы сами этого не понимаем, но дальше нашу работу строим только на увиденном. 

Как починить себя? Принять как данность, что все подвержены когнитивным искажениям. От них нельзя избавиться полностью. Можно «пойти на компромисс: научиться распознавать ситуации, в которых возможны ошибки. И стараться избегать серьёзных ошибок, если ставки высоки». В этой фразе скрыт рецепт для нас: понимаем, где происходят значимые действия во время работы с данными → пробуем распознать «ситуации, в которых возможны ошибки» → придумываем, как можно избежать этих ошибок. 

Я работаю с данными почти 20 лет, и из них семь набирала и растила джунов, три — наставник в Практикуме на курсе «Аналитик данных». По работам начинающих аналитиков (чужие ошибки проще увидеть, чем свои) я пробовала понять, где происходят «значимые действия» и «возможны ошибки» во время предобработки данных. Для починки исходила из одной мысли: нам нужно вовремя заткнуть Систему 1 и помочь Системе 2.  В этой статье предложу свои варианты борьбы, но, зная об эффекте уровня обработки, скажу, что придумать своё будет более полезным ;)

26f7037c7042d064caf2d1ea1eaf88f8.png

df.head ()

Итак, df.head () и какие у нас есть варианты:

  1. Простое, частичное решение: посмотреть не первые 5 строк, а случайные 5 строк df.sample (5). На протяжении всей работы пользоваться df.sample (5), надеяться, что каждый раз будут приходить новые мысли.

  2. Посложнее, поинтереснее, но тоже частичное: написать свою функцию предварительного просмотра (как вариант, список того, что всегда должно быть проверено) или воспользоваться готовыми решениями (например, pandas-profiling).

  3. Хорошее решение: вначале думать, потом смотреть в данные. Пресловутый .head () всё-таки придётся написать, если нет описания, но мы уже настроились, что он нам не про предобработку будет рассказывать, а продемонстрирует состав данных. Остается вопрос, что именно думать, да?  

Не уверена, что про все данные на свете это можно обобщить. Даже на одних и тех же данных в зависимости от задачи и конечной цели может быть разная глубина проработки. Возможные варианты вопросов «на подумать» есть в этой статье. Поймала себя на мысли, что для этапа предобработки данных, которые вижу впервые, обычно иду от источника данных и моих знаний об этом мире (если они у меня есть, если нет — то из общения с экспертом). 

Разберём на примере датасета (файл .csv) Общественное питание в Москве и признаков Longitude_WGS84 и Latitude_WGS84. 

Источник: «данные, связанные с контрольной (надзорной) деятельностью». Это сведения, подаваемые в госорганы, возможно, есть ещё другие средства мониторинга. Судя по обилию кнопок «сообщить» — информация от пользователей и владельцев бизнеса. 

Методологии сбора и обработки — не нашла. Буду предполагать, что адрес (Address) — в большинстве случаев изначальный признак, координаты получены с помощью геокодирования из адреса, округ и район «рассчитаны» по координатам.  

Мне нужен эксперт, т.к. я ничего не знаю про геокодинг (погуглить проблемы геокодинга, попробовать геокодировать самостоятельно, например, с помощью плагинов для google sheets). Исходя из этих мыслей и знаний начнёт вырисовываться какая-то картинка мира (не обязательно такая и на истинность и полноту не претендую):  

21efca916ac509d5eb5bd1207207019c.png

Возможно, вы сейчас воскликнули: «ну, ёжику понятно, что нужно проверить количество уникальных адресов на геоточку», и, возможно, попали в знание задним числом ;) Последствия попадания могут быть положительными, если выводом не станет «мне не нужно заранее думать, я в моменте всё могу». 

Вернёмся к нашим изысканиям. В таком подходе есть масса плюсов помимо подстраховки от «что вижу, то пою»:  

  • Не будем делать лишних телодвижений: вместо странной проверки «из разных источников = один адрес в разных видах» на адресах —  простенький код на координатах.

  • На каждом блоке (дубли, пропущенные значения, аномалии и т.п.) не придётся каждый раз как в первый раз тупить в признак.

  • В отличие от «проверяю, что пришло в голову в моменте», сейчас гипотезы можно приоритизировать (например, по последствиям и сложности проверки). В условиях ограниченного времени (а оно всегда ограничено) проверять только гипотезы с высокими приоритетами.   

  • Заметили, что есть одинаковые или почти одинаковые проверки на разные проблемы? Как правило, обнаружив проблему, мы останавливаемся на первой пришедшей в голову гипотезе, когда пытаемся понять, что случилось. А тут у нас заранее есть разные варианты — приятный бонус.

  • Если проект не одноразовый, то происходит накопление знаний. Плюс есть информация, что сделал (на моей картинке отмечено серым то, что я точно сделала бы), — не нужно копаться в коде.

  • Начинаем понимать, какие дополнительные источники нам, возможно, нужны и с какими ограничениями столкнёмся.  

df.drop_duplicates ()

Что ещё обязательно сделать в предобработке? df.duplicated () → df.drop_duplicates (). Очень быстро df.duplicated () выпадает совсем. Зачем смотреть на эти строки (и не всегда что-то можно высмотреть, да?), врубаем сразу drop и постепенно уходим в искажение золотой молоток. 

Смотрим карту. Что думаете по этому поводу?  

232c9884020c5b0ccf45f10bf693df25.png

Основная проблема, когда мы работаем с дубликатами, — мы рассматриваем только одну гипотезу: «дубликаты — ошибки в наших данных». А что если в этом месте заставлять себя придумывать хотя бы ещё одну? Например, вытаскивать из нашей «картины мира».

Офтоп: в удалении дублей есть ещё параметр subset. Признавайтесь, вы уже пытались перебором вывести разные вариации группировок и что-то с этим сделать? На самом деле хорошая идея для тренировки понимания данных и процессов. Но если мы сейчас не об этом, то предлагаю вернуться в «картину мира» и посмотреть в наши проверки с точки зрения дублей. Например, «существует похожий адрес, и геокодер унесло туда» в контексте дублей можно проверить: на один адрес (Address) должен быть один уникальный район (District). Наши игры с subset скорей всего не позволили бы это уловить. 

nan

Начинаем работать с пропущенными значениями: df.isnull ().mean (). И дальше наша работа с данными основывается только на том, что мы увидели? Что насчёт na, N/A, null, nan (текстом), tbd, unknown, неизвестно, -1, -9999, 0, ***, — , «пробел», . (точка) и в том же духе, в зависимости от креативности создателя данных и ПО. Про этот момент достаточно знать, если данные получены из источника, который мог такое накуролесить, и читать документацию, если она есть. В рабочей жизни ещё и смотреть на код, написанный до нас.

В нашем случае документации нет, к коду доступа нет, момент «куролеса» — есть. История про «точка на другом здании», «сервис геокодинга не нашёл дом и поставил точку в начало, середину улицы», «не нашёл улицу и поставил в центр города» — это заполнение (недопущение) пустых значений. 

Предлагаю пройтись по всем переменным с, наверное, странным вопросом: «А почему нет пропущенных значений? Как мы этого добились?» Эти вопросы разбивают нашу изначальную установку «там, где нет пропусков, — все хорошо».

Про пропущенные значения можно говорить долго и с упоением, но остановимся на одном шуточном примере. Представьте, вы провели опрос: «Ковыряетесь ли вы в носу?» и получили 20 ответов «нет» и 220 пропусков. Чем будете заполнять? Обычно методы заполнения исходят из информации, которая есть. Но иногда пропуски — информация, которой нет. Так называемая ошибка выжившего).

Пара слов про графики

Моё знакомство с когнитивными искажениями когда-то началось с графиков, вы тоже скорей всего натыкались на статьи «Как обманывать с помощью графиков». Давайте попробуем: что вы видите на этом графике?  

0e48da8d50c58ee85d8df09a3b3acbc4.png

Что я вижу: в воскресенье у нас значительно падает средний чек.

Что произошло: .plot () по умолчанию отрисовывает график от минимального значения, которое есть в данных. Нуля там нет, вот мы и любуемся в разорванный график (torn graph), значительно переоценивая различия.

Что можно сделать:  

  • Собираем информацию о том, как графики могут обманывать (пример). 

  • Проверяем в контексте используемого инструмента. Например, для Google-таблиц torn graph-проблема не будет актуальной (при настройках по умолчанию), но будут актуальны другие.

  • Пока мы будем собирать и проверять, сработает эффект уровня обработки, возможно, мы даже хорошо запомним весь набор. 

  • Каждый раз перед тем, как интерпретировать график, будем сверяться со списком возможных ошибок. Или будем сразу писать код с учётом всех замечаний.

  • Предполагаем, что со временем будем делать это на автомате и Системе 2 останется только интерпретация без дополнительных нагрузок.

Признаюсь, что сама так не делаю. Мне кажется, что в таком подходе нет гармонии. Как будто мы вскакиваем «проверить утюг». В своё оправдание скажу, что инструменты меняются (я за 20 лет сменила пять). В инструментах что-то меняется, хочется по-другому, без утюга. 

Эти пункты, конечно, будет полезно сделать, чтобы не обманывать других и не давать другим обмануть себя, но в контексте предобработки данных (не обманываю сам себя) предложу другой вариант. Что если до запуска кода с графиком заранее представлять, что мы там можем увидеть? Или, если возможно, смотреть в таблицу. 

В обсуждаемом графике просится запустить сначала pivot_table (мы ведь всё равно его написали) и только потом визуализировать таблицу. Заодно мы, возможно, поймём, что линейный график здесь явно плохое решение;)

abfee2817a2dbbc2ddd36ee3343e4fb5.png

Заключение, или Как перестать беспокоиться 

07dbaad38362d9ffa614f11c91b232ba.png

Верить в себя (но не безоговорочно себе). Я что-то знаю об этом мире и лучше я поспорю с данными, чем быстро, но неверно «спою о том, что вижу». Человеческий мозг способен многое объяснить и принять как данность. Я встречала объяснения графику выше (в зависимости от того, как почистить аномалии, будут разные дни «падения» среднего чека): «понедельник — день тяжелый», «среда — середина недели, и люди устали», «тяпница». Уверена, что если изначально подумать, ожидаю ли я какую-то взаимосвязь дня недели со средним чеком, то график вызвал бы недоумение.

Понимать задачу. Мы, как правило, рассуждаем о предобработке для применения методов машинного обучения, но, возможно, у вас исследовательский вопрос и те же пропуски вам не мешают. Также понимание задачи будет нам помогать определять «значимые действия». Для подготовки статьи я сосредоточилась на глобально значимых действиях начинающего аналитика. Учёба и поиск работы — это постоянно новые данные и задачи со своими сюрпризами. 

Искать разные фреймворки работы и брать из них полезное для вашей задачи. Упомянутый уже pandas-profiling — замечательный инструмент. Проверка случайным образом — тоже один из используемых вариантов. Проверка по известной информации. Например, мы работаем в «Якитории», можем посмотреть, насколько хорошо данные описывают нас, возможно, увидеть закономерности (придумываю: отдельно стоящие заведения описаны хорошо, в БЦ и ТЦ — плохо). Ещё можно подсматривать решения в других науках (для примера, подход в социальных). 

Создавать конфликты. Может ли хорошее быть плохим и наоборот? Я так привык, какой-то метод, автор этой статьи или все вокруг сказали, что надо делать так. А что если в данной конкретной задаче мы не правы?

© Habrahabr.ru