При обработке данных исходного DataSet часто попадаются аномальные значения, которые поставлены вместо пропусков, и мало того, что они скрываются, так ещё и несут вред общему делу. В данной статье будет разобран практический пример избавления от аномальных значений в связанных с географией данных при помощи инструментов известной библиотеки Pandas.
В качестве примера возьмём достаточно известный соревновательный DataSet «Pump it Up: Data Mining the Water Table».
Сначала войдём в курс проблемы. Стоит задача определить состояние пункта водоснабжения («водоколонки») в Танзании по различным данным об этих пунктах: кто построил, когда построил, кол-во населения в округе и т.д. Однако особый интерес представляют longtitude и latitude (долгота и широта), т.е. конкретное место расположения той или иной водоколонки на карте.
Longtitude и latitude очень ценные показатели для нашей будущей модели-классификатора, однако если вывести их на график, то картинка покажется немного странной:
Вряд ли свыше двух тысяч водоколонок было построено за пределами Танзании, да ещё и в Атлантическом океане. Поэтому неплохо было бы заменить данные аномалии на осознанные значения, что несомненно поможет нашей модельке добиться лучших результатов.
В нашем DataSet есть такие территориальные единицы как region (регион) и subvillage (деревня). Регион состоит из деревень.
Напомню, что нам нужно восстановить данные о расположении водоколонок, и в этом нам как раз и поможет принадлежность водоколонки к какому-либо региону или деревне.
Восстановление географических данных логично производить по subvillage, т.к. это обеспечит большую точность в сравнении с регионом.
Идея проста:
Определяем к какой деревне принадлежит данная водоколонка
Считаем среднее расположение по всем водоколонкам, координаты которых НЕ ошибочны
Записываем получившиеся значения в longtitude и latitude для текущей водоколонки
И так для всех водоколонок, одиноко плавающих в океане
Вот мы и добрались до кода:
################################################################
# Получаем таблицу средних расположений водоколонок по деревням.
################################################################
average_coords_subvillage = data_all[data_all.longitude!=0].groupby(
'subvillage')[['longitude', 'latitude']].mean()
С помощью метода groupby производим группировку по subvillage c подсчётом средних значений по долготе и широте.
В итоге получаем таблицу, где каждому subvillage соответствуют средние координаты широты и долготы по всем водоколонкам, координаты которых были известны (поэтому и используется срез [data_all.longitude!=0]).
Столбец subvillage становится индексным столбцом. Как раз посредством него и будет происходит последующая магия.
#################################
# Заполняем пропуски по деревням.
#################################
data_all.longitude[data_all.longitude==0] = data_all[data_all.longitude==0].subvillage.map(
average_coords_subvillage['longitude']
)
data_all.latitude[data_all.latitude==-0.00000002] = data_all[data_all.latitude==-0.00000002].subvillage.map(
average_coords_subvillage['latitude']
)
# *где 0 - аномальное значение по долготе, 2е-8 - аномальное значение по широте
Далее с помощью метода map происходит замена названия деревни на среднее значение широты, которое ей соответствует (срез [data_all.longitude==0] означает, что мы производим замену только для тех водоколонок, где долгота была ошибочна). Затем данные значения благополучно помещаются на места ошибочных значений долготы в столбец longtitude исходного DataSet.
Та же самая процедура происходит и с широтами.
И если теперь по новым значениям longtitude и latitude построить карту расположения водоколонок, то картинка получается куда приятнее:
Подведём итоги:
Очень важно обращать внимание не только на пропуски в данных, но и на аномальные значения, которые так же могут отрицательно повлиять на результат работы модели.
Неизвестные данные о расположении объектов можно заполнить посредством их принадлежности к какому-либо классу (привязанному к географии).
Методы groupby и map довольно удобные и мощные инструменты для решения такого рода задач.
P.S.:
На практике некоторые деревни:
содержали только одну водоколонку
данная водоколонка была с ошибочными координатами
Поэтому срез [data_all.longitude!=0] при формировании таблицы средних координат исключил такие деревни вовсе. А после применения map вместо координат долготы и широты в одинокие водоколонки записались NaN.
Данная проблема была решена :)
Но как бы вы решили её? Пишите в комментариях!