Изучаем pandas. Урок 4. Работа с пропусками в данных
Очень часто большие объемы данных, которые подготавливаются для последующего анализа, имеют пропуски. Для того, чтобы можно было использовать алгоритмы машинного обучения, строящие модели по этим данным, в большинстве случаев, необходимо эти пропуски чем-то и как-то заполнить. На вопрос “чем заполнять?” мы не будем отвечать в рамках данного урока, а вот на вопрос “как заполнять?” ответим.
- pandas и отсутствующие данные
- Замена отсутствующих данных
- Удаление объектов/столбцов с отсутствующими данными
pandas и отсутствующие данные
Для начала, хочется сказать, что в документации по библиотеке pandas есть целый раздел, посвященный данной тематике.
Для наших экспериментов создадим структуру DataFrame , которая будет содержать пропуски. Для этого импортируем необходимые нам библиотеки.
После этого создадим объект в формате csv . CSV – это один из наиболее простых и распространенных форматов хранения данных, в котором элементы отделяются друг от друга запятыми, более подробно о нем можете прочитать здесь.
Полученный объект df – это DataFrame с пропусками.
В нашем примере, у объектов с индексами 0 и 2 отсутствуют данные в поле percent . Отсутствующие данные помечаются как NaN . Добавим к существующей структуре еще один объект (запись), у которого будет отсутствовать значение в поле count.
Для начала обратимся к методам из библиотеки pandas , которые позволяют быстро определить наличие элементов NaN в структурах. Если таблица небольшая, то можно использовать библиотечный метод isnull . Выглядит это так.
Таким образом мы получаем таблицу того же размера, но на месте реальных данных в ней находятся логические переменные, которые принимают значение False , если значение поля у объекта есть, или True , если значение в данном поле – это NaN . В дополнение к этому можно посмотреть подробную информацию об объекте, для этого можно воспользоваться методом info() .
В нашем примере видно, что объект df имеет три столбца ( count , percent и price ), при этом в столбце price все объекты значимы – не NaN , в столбце count – один NaN объект, в поле percent – два NaN объекта. Можно воспользоваться следующим подходом для получения количества NaN элементов в записях.
Замена отсутствующих данных
Отсутствующие данные объектов можно заменить на конкретные числовые значения, для этого можно использовать метод fillna() . Для экспериментов будем использовать структуру df , созданную в предыдущем разделе.
Этот метод не изменяет текущую структуру, он возвращает структуру DataFrame , созданную на базе существующей, с заменой NaN значений на те, что переданы в метод в качестве аргумента. Данные можно заполнить средним значением по столбцу.
В зависимости от задачи используется тот или иной метод заполнения отсутствующих элементов, это может быть нулевое значение, математическое ожидание, медиана и т.п. Для замены NaN элементов на конкретные значения, можно использовать интерполяцию, которая реализована в методе interpolate(), алгоритм интерполяции задается через аргументы метода.
Удаление объектов/столбцов с отсутствующими данными
Довольно часто используемый подход при работе с отсутствующими данными – это удаление записей (строк) или полей (столбцов), в которых встречаются пропуски. Для того, чтобы удалить все объекты, которые содержат значения NaN воспользуйтесь методом dropna() без аргументов.
Вместо записей, можно удалить поля, для этого нужно вызвать метод dropna с аргументом axis=1 .
pandas позволяет задать порог на количество не- NaN элементов. В приведенном ниже примере будут удалены все столбцы, в которых количество не- NaN элементов меньше трех.
P.S.
Изучаем pandas. Урок 4. Работа с пропусками в данных : 4 комментария
Полезная статья, решила одну из моих проблем с кодом)
Интересно будет узнать, ЧЕМ заполнять пропуски?
В начале написал комментарий, частично повторив содержимое статьи))) Чем заполнять, определяется задачей, т.е. если можно заполнить средним значением, то заполняйте средним, если данные чувствительны к таким махинациям, то можно просто их выбросить.
Для этого импортируем необходимые нам библиотеки.
In [1]: import pandas as pd
In [2]: from io import StringIO
с первым понятно, про второе ничего не сказано – что, для чего….
Pandas fill missing values in dataframe from another dataframe
I cannot find a pandas function (which I had seen before) to substitute the NaN’s in a dataframe with values from another dataframe (assuming a common index which can be specified). Any help?
6 Answers 6
If you have two DataFrames of the same shape, then:
Will do the trick.
Only locations where df.isnull() evaluates to True (highlighted in green) will be eligible for assignment.
In practice, the DataFrames aren’t always the same size / shape, and transforming methods (especially .shift() ) are useful.
Data coming in is invariably dirty, incomplete, or inconsistent. Par for the course. There’s a pretty extensive pandas tutorial and associated cookbook for dealing with these situations.
As I just learned, there is a DataFrame.combine_first() method, which does precisely this, with the additional property that if your updating data frame d2 is bigger than your original df , the additional rows and columns are added, as well.
This should be as simple as
A dedicated method for this is DataFrame.update :
Quoted from the documentation:
Modify in place using non-NA values from another DataFrame.
Aligns on indices. There is no return value.
Important to note is that this method will modify your data inplace. So it will overwrite your updated dataframe.
Example:
Notice the updated NaN values at intersect aaa, A and eee, B
However, sometimes you want to fill/replace/overwrite some of the non-missing (non-NaN) values of DataFrame A with values from DataFrame B. That question brought me to this page, and the solution is DataFrame.mask()
When condition is true, the values from A will be used, otherwise B’s values will be used.
For example, you could solve the OP’s original question with mask such that when an element from A is non-NaN, use it, otherwise use the corresponding element from B.
Работа с отсутствующими значениями в Pandas
Отсутствующее значение в наборе данных отображается как вопросительный знак, ноль, NaN или просто пустая ячейка. Но как можно справиться с недостающими данными?
Конечно, каждая ситуация отличается и должна оцениваться по-разному.
Есть много способов справиться с недостающими значениями. Рассмотрим типичные варианты на примере набора данных — ‘Titanic’. Эти данные являются открытым набором данных Kaggle.
Для анализа необходимо импортировать библиотеки Python и загрузить данные.
Для загрузки используется метод Pandas read.csv(). В скобках указывается путь к файлу в кавычках, чтобы Pandas считывал файл во фрейм данных (Dataframes — df) с этого адреса. Путь к файлу может быть URL адрес или вашим локальным адресом файла.
Показывает первые 2 строки загруженного фрейма данных
Посмотрим на размер данных (количество строк, колонок):
Для просмотра статистической сводки каждого столбца, чтобы узнать распределение данных в каждом столбце используется метод describe( ). Этот метод показывает нам количество строк в столбце — count, среднее значение столбца — mean, столбец стандартное отклонение — std, минимальные (min) и максимальные (max) значения, а также границу каждого квартиля — 25%, 50% и 75%. Любые значения NaN автоматически пропускаются.
метод describe( )
По умолчанию, метод describe( ) пропускает строки и столбцы не содержащие чисел — категориальные признаки. Чтобы включить сводку по всем столбцам нужно в скобках добавить аргумент — include = «all».
метод describe(include = «all»)
Для категориальных признаков этот метод показывает: — Сколько уникальных значений в наборе данных — unique; top значения; частота появления значений — freg.
Метод info( ) — показывает информацию о наборе данных, индекс, столбцы и тип данных, ненулевые значения и использование памяти.
показывает информацию о наборе данных, индекс, столбцы и тип данных, ненулевые значения и использование памяти.
В результате мы видим, что все колонки, кроме колонок ‘Age’, ‘Cabin’ и ‘Embarked’, содержат по 891 строк.
Колонка ‘Survived’ — это целевое значение. Показывает, кто выжил, а кто — нет. Эта колонка заполнена бинарными значениями:
Метод — value_counts(). Подсчет значений — это хороший способ понять, сколько единиц каждой характеристики / переменной у нас есть.
подсчет значений в колонке ‘Survived’
Из 891 пассажира выжило 342.
график подсчет значений в колонке ‘Survived’
Из 891 пассажира выжило 342 это 38%.
График подсчет значений в колонке ‘Survived’
Визуализация: Графики подсчета значений в колонках — «Survived», «Pclass», «Sex», «SibSp», «Parch», «Embarked»
Графики подсчета значений в колонках — «Survived», «Pclass», «Sex», «SibSp», «Parch», «Embarked»
Теперь посмотрим на колонки которые имеют пропущенные значения.
Есть два метода обнаружения недостающих данных: — isnull() и notnull().
Результатом является логическое значение, указывающее, действительно ли значение, переданное в аргумент, отсутствует. «Истина» ( True ) означает, что значение является отсутствующим значением, а «Ложь» ( False ) означает, что значение не является отсутствующим.
True — пропущенные значения
Используя цикл for в Python, мы можем быстро определить количество пропущенных значений в каждом столбце. Как упоминалось выше, «Истина» представляет отсутствующее значение, а «Ложь» означает, что значение присутствует в наборе данных. В теле цикла for метод «.value_counts ()» подсчитывает количество значений «True».
количество пропущенных значений в каждом столбце.
количество пропущенных значений в каждом столбце.
Посмотрим — сколько пропущенных значений в каждой колонке.
количество пропущенных значений в каждом столбце.
В колонке возраст — ‘Age’ не указано 177 значений. И нужно понять — это систематическая ошибка или какая-то случайная погрешность.
Н-р, может у пассажиров 1 класса (или у женщин) не спрашивали про возраст ( т. к. это было не прилично), или случайно пропустили. Понимание о причине пропущенных значений, определит — как работать с этими отсутствующими данными.
Нужно сгруппировать возраст, относительно того, отсутствует возраст или нет. Для группировки используем метод groupby().
True — отсутствует возраст
False — значение заполнено
метод groupby(). True — отсутствует возраст, False — значение заполнено
Среди пассажиров, у которых значение возраста отсутствовало, были выжившие (около 30%) и погибшие (около 70%) — колонка ‘Survived’, True = 0.29 .
Эти пассажиры были в более низком классе:
колонка ‘Pclass’ — True = 2.59 (это среднее значение класса)
колонка ‘Fare’ — True = 22.15 (это среднее значение стоимости билета)
Подсчет значений в колонке ‘Pclass’:
Подсчет значений в колонке ‘Pclass’
Например, в 3 классе было 491 пассажира (это 55%)
Выживаемость пассажиров по классам
Для более детального анализа, создадим новую колонку ‘Age_NaN’ (бинарный классификатор). Используем метод where(), где прописываем условие: — если значение в колонке ‘Age’ отсутствует, то присваиваем в колонке ‘Age_NaN’ — значение 0, если присутствует, то 1.
первые 6 строк фрейма данных с новой колонкой ‘Age_NaN’
Подсчет значений в колонке ‘Age_NaN’
Подсчет значений в колонке ‘Age_NaN’
Выживаемость пассажиров в зависимости от наличия записи о возрасте.
Выживаемость пассажиров в зависимости от наличия записи о возрасте.
И снова мы видим: — что, среди пассажиров, у которых значение возраста отсутствовало, были выжившие (около 30%) и погибшие (около 70%).
Выживаемость пассажиров в зависимости от наличия записи о возрасте и класса.
Выживаемость пассажиров в зависимости от наличия записи о возрасте и класса.
зависимость от наличия записи о возрасте и класса.
В первом классе запись отсутствует у 30 пассажиров. Из 30 пассажиров выжило — 46%(14 пассажиров), погибло — 53%(16 пассажиров). Всего пассажиров было в первом классе — 216 (в данном наборе данных).
Во втором классе запись отсутствует у 11 пассажиров. Из 11 пассажиров выжило — 36%(4 пассажира), погибло — 63% (7 пассажиров). Всего пассажиров было во втором классе — 184 (в данном наборе данных).
В третьем классе запись отсутствует у 136 пассажиров. Из 136 пассажиров выжило — 25% (34 пассажира), погибло — 75% (102 пассажира). Всего пассажиров было в третьем классе — 491 (в данном наборе данных).
Выживаемость пассажиров в зависимости от наличия записи о возрасте и пола.
Выживаемость пассажиров в зависимости от наличия записи о возрасте и пола.
зависимость от наличия записи о возрасте и пола.
У 53 женщин нет записи о возрасте. Из 53 женщин выжило 68% (36 женщин), погибло 32% (17 женщин). Всего женщин было — 314 (в данном наборе данных).
У 124 мужчин нет записи о возрасте. Из 124 мужчин выжило 13% (16 мужчин), погибло 87% (108 мужчин). Всего мужчин было — 577 (в данном наборе данных)
Пассажиров было много в 3 классе и много погибло. Пассажиры — мужчины, у которых был более дешевый билет и более низкий класс — имели меньше шансов выжить.
Т.к. среди пассажиров, у которых значение возраста отсутствовало, были выжившие (около 30%) и погибшие (около 70%), и пассажиры были с разных классов( из 3 класса было значительно больше), и среди пассажиров были мужчины и женщины (мужчин было значительно больше), то при опросе у выживших и при осмотре тел погибших могли случайно пропустить возраст пассажира.
Следовательно делаем вывод, что возраст случайно не занесли.
Решение: Пропущенные значения заполнить средним значением.
график выживаемости пассажиров в зависимости от возраста
Посмотрим на график выживаемости пассажиров в зависимости от класса и возраста
график выживаемости пассажиров в зависимости от класса и возраста
В колонке каюта ( ‘Cabin’) не указано 687 значений. Т. к. пропущенных значений много, можно удалить полностью колонку ‘Cabin’, а можно и оставить отсутствующие данные как — отсутствующие данные. Здесь важно понять: — Существует ли какая-то систематическая взаимосвязь между выживанием и тем, была ли у пассажира отдельная каюта.Для группировки используем метод groupby().
True — отсутствует упоминание о каюте
False — значение заполнено
метод groupby(). True — отсутствует упоминание о каюте, False — значение заполнено
Те, пассажиры у кого запись отсутствует — выжили около 30%. А у кого запись о наличии каюты есть — выжило 67%.
Вывод: Есть взаимосвязь между выживанием и наличием каюты.
Создать новую колонку ‘Cabin_available’ (бинарный классификатор).Используем метод where(), где прописываем условие: — Если значение в колонке ‘Cabin’ отсутствует, то присваиваем в колонке ‘Cabin_available’ — значение 0, если присутствует, то 1.
показывает первые 6 строк фрейма данных с новой колонкой ‘Cabin_available’
Выживаемость пассажиров в зависимости от наличия записи о каюте:
Выживаемость пассажиров в зависимости от наличия записи о каюте
График выживаемости пассажиров в зависимости от наличия записи о каюте
Теперь колонку ‘Cabin’ можно удалить.
фрейм данных без колонки ‘Cabin’
В колонке порт посадки на борт (‘Embarked’) не указано два значения. Это категориальный признак.
Решение: Заменить пропущенные значения по частоте. Заменить отсутствующее значение значением, которым чаще всего встречается в конкретном столбце.
подсчет значений в колонке ‘Embarked’
Чаще всего встречается значение S — 644. Нужно заменить пропущенные значения на S.
метод describe() для колонки ‘Embarked’, после замены пропущенных значений.
Good! Now, we have a dataset with no missing values. (Хорошо! Теперь у нас есть набор данных без пропущенных значений.)
набор данных без пропущенных значений
Обработка пропусков в Pandas
К примеру, можно использовать число -9999 или редко встречающееся сочетание битов. Более часто встречающийся способ — условное обозначение через NaN. NaN — это специальное значение, определенное спецификацией IEEE для чисел с плавающей точкой и используется во многих ЯП.
У метода есть ограничения. Во-первых использование значений индикаторов может привести к дополнительным не оптимизированным расчетам. Во-вторых NaN доступен не для всех типов данных.
Использование масок
Можно создать отдельный булевый массив, индицирующий пропущенные значения. В ряде языков выделяется отдельный бит для разметки пропусков в массиве данных локально. Оба подхода влекут за собой перерасход памяти.
Как это реализовано в Pandas?
Pandas построена на NumPy, в котором отсутствует понятие пропуска для всех данных кроме данных с плавающей точкой. NumPy поддерживает маски, но использование такого подходжа в Pandas влечет значительные накладные расходы на хранение, вычисление и поддержку кода.
В итоге в Pandas используется:
Объект None
None — объект python. Его нельзя использовать в NumPy и во всех производных массивах Pandas. None используется только в массивах с типом object. Когда мы создаем массив, используя None, автоматически создается массив с типом object.
Тип object означает, что NumPy не смог установить тип объектов массива, единственное что он знает — это то, что это объекты python. Операции с такими массивами будут производится на уровне языка python, т.е. со всеми накладными расходами, присущими языку с динамической типизацией. Оптимизация NumPy работать не будет.
Кроме того, функции агрегирования по массиву, например, massive.sum() или massive.min() выбросят ошибку, так как операции между численным значением и значением None не определены
Объект NaN
Объект NaN определяет отсутствие числового значения с плавающей точкой. Это вызывает некоторые проблемы — если NaN попадает в массив, все данные приводятся к числам с плавающей точкой. Кроме того, все операции с NaN приводят к NaN, в том числе и функции агрегирования.
Не забудьте, что для вызова объекта NaN нужен NumPy
Nan и None
Pandas преобразует None в NaN, если оба будут встречены в одном массиве. Естественно, осуществляется и повышающее преобразование с приведением всех непустых числовых значений к числу с плавающей точкой, а всех остальных к NaN.
Правила повышающих преобразований типов в Pandas (строки всегда хранятся как object)
Typeclass | Conversion When Storing NAN | NAN Sentinel Value |
---|---|---|
floating | No change | np.nan |
object | No change | None or np.nan |
integer | Cast to float64 | np.nan |
boolean | Cast to object | None or np.nan |
Операции над пустыми значениями
В Pandas доступно несколько методов:
isnull() — генерирует булеву маску для отсутствующих значений
notnull() — тоже для непустых
dropna() — фильтрация данных по отсутствующим значениям
fillna() — замена пропусков с возвратом копии
Методы доступны как для объектов Series так и для dataFrame (с выбором измерения).
Кроме того, для dropna() ожно задать дополнительные параметры. how=’any’ задан по дефолту, можно переопределить как ‘all’ — будут отбрасываться только полностью пустые строки/столбцы. thresh задает минимальное значение непустых значений, выше которого строки/столбцы не отбрасываются.
Для fillna() доступно несколько аргументов. method=’ffill’ и method=’bfill’ определяют какими значениями будут заполняться пропуски (предыдущими или последующими в массиве).
Все статьи с тегом pandas
- (25 Jul 2020)
(18 Apr 2020)
(30 Mar 2020)
(04 Mar 2020)
Как понять translating алгоритмы для графов?
Translating алгоритмы (а точнее TransE), рассматриваются в курсе cs224w, про них есть домашка и они фигурируют в нескольких последних лекциях.
Обозначения в анализе алгоритмов
В асимптотическом анализе алгоритмов принято использовать базовые обозначения, позволяющие формализовать сложность алгоритма. Все термины сводятся к устранению постоянных коэффициентов, так.