Category: Data Science

28
Апр
2022

🗄️ ✔️ 10 лучших практик написания SQL-запросов

Делимся рекомендациями по решению распространенных проблем с SQL, с которыми часто сталкиваются специалисты по работе с данными.

Статья является переводом. Оригинал доступен по ссылке.

Я работаю с данными уже 3 года, и меня до сих пор удивляет, что есть люди, которые хотят стать аналитиками, практически не зная SQL. Хочу особо подчеркнуть, что SQL является фундаментальным языком независимо от того, кем вы будете работать в сфере анализа данных.

Конечно, я видел исключения, когда люди, обладающие впечатляющими знаниями в других областях, помимо SQL, получают работу, но при этом после получения оффера им все равно приходится изучать SQL. Я думаю, что почти невозможно быть профессионалом в сфере анализа данных без знаний SQL.

Данные советы предназначены для всех специалистов, независимо от опыта. Я перечислил самые распространенные случаи в моей практике, разместив в порядке возрастания сложности.

Для примеров я буду использовать базу данных SQLite: sql-practice.com

1. Проверка уникальных значений в таблице

        SELECT count(*), count(distinct patient_id) FROM patients

    

В этом примере показано, как проверить, является ли ваш столбец первичным ключом в таблице. Конечно, это обычно используется в создаваемых вами таблицах, поскольку в большинстве баз данных есть возможность указать первичный ключ в метаданных информационной схемы.

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

Однако становится немного сложнее, когда у вас есть несколько столбцов, которые создают первичный ключ. Чтобы решить эту проблему, просто объедините столбцы, составляющие первичный ключ, после ключевого слова DISTINCT. Простой пример — объединение имени и фамилии для создания первичного ключа.

        SELECT count(*), count(distinct first_name || last_name) FROM patients
    

2. Поиск повторяющихся записей

        SELECT 
    first_name 
    , count(*) as ct
    
FROM patients
GROUP BY
    first_name
HAVING
    count(*) > 1
ORDER BY 
    COUNT(*) DESC
;
    

Таблица из примера — это упрощенная версия баз данных, которые вы будете использовать в своей работе. В большинстве случаев вы захотите выяснить причины дублирования значений в базе данных. Для этого вам пригодится данный запрос.

Вы можете использовать ключевое слово HAVING для сортировки повторяющихся значений. В таком случае вы заметите, что чаще всего дублируется имя Джон. Затем вы запустите еще один запрос, чтобы увидеть причину повторяющихся значений, и увидите, что все пациенты имеют разные фамилии и ID.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека программиста»

3. Обработка NULL с DISTINCT

        with new_table as (
select patient_id from patients
UNION
select null
)

select 
    count(*)
  , count(distinct patient_id)
  , count(patient_id) 

from new_table
    

Результатом запроса будет значение 4531 для столбца COUNT(*) и 4530 для двух оставшихся столбцов. Когда вы указываете столбец, ключевое слово COUNT исключает нулевые значения. Однако, при использовании звездочки в подсчет включаются значения NULL. Это может сбивать с толку при проверке, является ли столбец первичным ключом, поэтому я посчитал нужным упомянуть об этом.

4. CTE > Подзапросы

        -- Use of CTE
with combined_table as (
select
  *
 
FROM patients p
JOIN admissions a 
  on p.patient_id = a.patient_id
)

, name_most_admissions as (
select
    first_name || ' ' || last_name as full_name
  , count(*)                       as admission_ct
  
FROM combined_table
)

select * from name_most_admissions
;

-- Use of sub-queries :(
select * from 
   (select
        first_name || ' ' || last_name as full_name
      , count(*)                       as admission_ct
  
    FROM (select
             *
 
          FROM patients p
          JOIN admissions a 
              on p.patient_id = a.patient_id
          ) combined_table
    ) name_most_admissions
;
    

Когда я впервые начал работать аналитиком данных 3 года назад, я писал SQL-запросы с большим количеством подзапросов, чем это было необходимо. Я быстро понял, что это не приводит к читабельному коду. В большинстве ситуаций вы хотите использовать общее табличное выражение вместо подзапроса. Зарезервируйте подзапросы для однострочников, которые вы хотите использовать.

5. Использование SUM и CASE WHEN вместе

        select 
     sum(case when allergies = 'Penicillin' and city = 'Burlington' then 1 else 0 end) as allergies_burl
   , sum(case when allergies = 'Penicillin' and city = 'Oakville' then 1 else 0 end)   as allergies_oak
  
from patients
    

Предложение WHERE может работать, если вы хотите суммировать количество пациентов, отвечающих определенным условиям. Но если вы хотите проверить несколько условий, вы можете использовать ключевые слова SUM и CASE WHEN вместе. Это делает код лаконичным и легко читаемым.

Данную комбинацию также можно использовать в выражении WHERE, как в примере ниже.

        select
  * 
FROM patients
WHERE TRUE
  and 1 = (case when allergies = 'Penicillin' and city = 'Burlington' then 1 else 0 end)
    

6. Будьте осторожны с датами

        with new_table as (
select
    patient_id
  , first_name
  , last_name
  , time(birth_date, '+1 second') as birth_date

from patients
where TRUE
   and patient_id = 1

UNION
  
select
    patient_id
  , first_name
  , last_name
  , birth_date 

from patients
WHERE TRUE
  and patient_id != 1
)

select 
  birth_date 
  
from new_table 
where TRUE 
  and birth_date between '1953-12-05' and '1953-12-06'
    

В этой базе данных все даты сокращены до дня. Это означает, что все значения времени столбца Birthday_date в этом примере равны 00:00:00. Однако в реальных наборах данных это обычно не так.

В зависимости от среды разработки SQL ваши настройки могут скрыть отображение времени. Но то, что время скрыто, не означает, что оно не является частью данных.

В приведенном выше примере я искусственно добавил секунду к пациенту №1. Как видите, этой 1-й секунды было достаточно, чтобы исключить пациента из результатов при использовании ключевого слова BETWEEN.

Еще один распространенный пример, который чаще всего упускают из вида специалисты по работе с данными, — это присоединение к датам, в которых все еще есть временной компонент. В большинстве случаев они действительно пытаются присоединиться к столбцам с сокращенной датой и, в конечном итоге, не получают желаемого результата или, что еще хуже, они не осознают, что получили неправильный результат.

7. Не забывайте об оконных функциях

        select
    p.*
  , MAX(weight) over (partition by city) as maxwt_by_city
   
 from patients p
    

Оконные функции — отличный способ сохранить все строки данных, а затем добавить еще один столбец с важными агрегатными сведениями. В этом случае мы смогли сохранить все данные и добавить максимальный вес по столбцу города.

Я видел, как некоторые аналитики пробовали обходные пути, когда оконная функция делала код короче и читабельнее и, скорее всего, также экономила им время.

Существует множество различных оконных функций, но приведенный выше пример является распространенным и простым вариантом использования.

8. По возможности избегайте DISTINCT

Последние 3 совета не содержат примеров программного кода, но они так же важны, как и приведенные выше. По моему опыту, специалисты по работе с данными слишком часто используют distinct, чтобы предотвратить дублирование, не разбираясь в причине.

Это ошибка. Если вы не можете с самого начала объяснить, почему в данных есть дубликаты, возможно, вы исключили из своего анализа какую-то полезную информацию. Вы всегда должны быть в состоянии объяснить, почему вы помещаете distinct в таблицу и почему есть дубликаты. Использование WHERE обычно предпочтительнее, так как вы можете увидеть то, что исключается.

9. Форматирование SQL

Об этом сказано довольно много, но стоит повторить. Обязательно отформатируйте SQL. Лучше создать больше строк с хорошим форматированием, чем пытаться сжать весь код всего в несколько строк. Это позволит ускорить разработку.

Вы можете заметить, что в примерах я использовал TRUE в WHERE выражении. Это было сделано для того, чтобы все аргументы в выражении WHERE начинались с AND. Таким образом, аргументы начинаются с одного и того же места.

Еще один быстрый совет — добавить запятые в начале столбца в выражении SELECT. Это позволяет легко найти пропущенные запятые, поскольку все они будут упорядочены.

10. Совет по отладке

Некоторые SQL-запросы могут быть очень сложными для отладки. Что мне больше всего помогло, когда я сталкивался с этим в прошлом, так это то, что я очень усердно документировал свои шаги.

Чтобы задокументировать шаги, я пронумерую часть кода в комментариях перед запросом. Комментарий описывает, что я пытаюсь сделать в этом разделе запроса. Затем я напишу свой ответ под заголовком комментария после выполнения запроса.

Во время отладки действительно легко увидеть варианты, которые вы уже попробовали, и я обещаю, что с таким подходом вы решите эту проблему быстрее.

***

Надеюсь, вы узнали что-то полезное из приведенных выше советов. Какие из них вы нашли наиболее полезными? Мы также с нетерпением ждем ваших советов и, пожалуйста, дайте ссылки на любые другие полезные статьи в комментариях, спасибо!

Материалы по теме

31
Мар
2022

📊 ТОП-30 ресурсов с данными для машинного обучения

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

Где искать датасеты?

1. Kaggle

Если вы когда-нибудь проходили курсы или хакатоны, связанные с наукой о данных, вы наверняка сталкивались с Kaggle. Это сообщество специалистов по Data Science. Изначально оно было соревновательной платформой, однако со временем на Kaggle появились другие разделы, в том числе возможность делиться данными.

2. Data World

Каталог, о котором редко упоминают – Data world. По способу поиска он похож на поисковик Google. Разница в том, что глубина поиска больше, например, он включает в себя подфайлы, которые могут содержать нужные данные. Это особенно важно при поиске вторичных данных.

3. UCI Machine Learning Repository

Еще один репозиторий с сотнями наборов данных предлагает Калифорнийский университет. Данные в UCI классифицируется по типу задач машинного обучения. Можно найти данные для одномерных и многомерных временных рядов, классификации, регрессии или рекомендательных систем. Некоторые наборы данных в UCI уже очищены и готовы к использованию.

Датасеты общего назначения

Датасеты общего назначения можно использовать в простых Pet-проектах. Для анализа (EDA) или прогнозирования на их основе не нужны углубленные знания Data Science. Например, вы можете использовать простые техники машинного обучения, не углубляясь в Deep Learning.

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

Государственные датасеты

1. Данные федерального правительства США

Этот портал позволяет загружать данные из различных государственных учреждений США – от бюджетов организаций до документов школ. Спектр тем настолько широк, что делает этот ресурс идеальным для применения в разных сферах вашей деятельности, связанной с датой.

При поиске открытых данных на сайте data.gov пользователи могут применять дополнительные фильтры по категориям: темы, тип набора данных, местоположение, теги, формат файла, организации и т. д.

2. Данные министерства здравоохранения РФ

Данные с этого сайта можно использовать без заключения договора с Министерством здравоохранения РФ. Данные находится в открытом доступе. Информацию можно копировать, публиковать, распространять, видоизменять и объединять с другой информацией, использовать в некоммерческих и коммерческих целях.

3. Данные министерства культуры РФ

Этот ресурс предоставляет информацию о данных на тех же условиях, что и Министерство здравоохранения РФ.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека data scientist’а»

Данные о жилье


1. Lincolnshire (UK) House Prices

Среднемесячные цены на жилье (£) для графства Линкольншир (Англия, UK) и округов.

Все цифры включают сделки с недвижимостью от 10 000 фунтов стерлингов до более чем 1 млн. Данные отфильтрованы по типам домов. Набор данных обновляется ежемесячно за 12-месячный период.

2. Zillow Housing data

Этот набор данных состоит из нескольких датасетов:

  • Цена дома (Home values) – скорректированный на сезон показатель стоимости дома и изменения на рынке жилья в данном регионе.

В этом датасете используется мерка ZHVI – Zillow Home Values Index.

Существует ZHVI верхнего уровня (стоимость домов в диапазоне от 65-го до 95-го процентиля для данного региона) и ZHVI нижнего уровня (стоимость домов в диапазоне от 5-го до 35-го процентиля для данного региона). Zillow также публикует ZHVI для всех типов домов и апартаментов, учитывая стоимость, количество спален и метраж.

  • Прогноз цены дома (Zillow Home Values Forecast) – прогноз индекса стоимости жилья Zillow (ZHVI) на один год. ZHVF создается с использованием среза данных ZHVI по всем домам и доступен как в необработанном, так и в скорректированном виде.
  • Аренда (Rentals) – показатель рыночной ставки арендной платы в данном регионе. ZORI (Zillow Observed Rent Index) – индекс арендной платы, который определяется по всей выборке арендного жилья, обеспечивая репрезентативность данных для всего рынка аренды.

Индекс рассчитывается в долларах путем вычисления среднего значения объявленной арендной платы, которая попадает в диапазон от 40-го до 60-го процентиля для всех домов и квартир в данном регионе. Подробную информацию можно найти в методологии ZORI.

Экономика и финансы

1. Глобальный датасет инфляции в мире

Экспертная группа Всемирного банка создала глобальную базу данных инфляции, которая охватывает 196 стран за период с 1970 до 2021 гг. Она включает шесть показателей инфляции с тремя частотами – годовая, квартальная и месячная:

  • общий индекс цен
  • индекс цен на продукты питания
  • индекс цен на энергоносители,
  • базовый индекс потребительских цен
  • индекс цен производителей
  • дефлятор ВВП

Кроме того, база данных представляет совокупную инфляцию по странам мира, странам с развитой экономикой, странам с формирующимся рынком и развивающимся странам, а также показатели мировых цен на сырьевые товары.

2. Рост населения

Производная от общей численности населения. Данные можно загрузить в формате .csv, xml и .excel.

3. Рост ВВП

Данные Всемирного банка и файлы данных национальных счетов ОЭСР (Организация экономического сотрудничества и развития).

Датасеты для глубокого обучения

В сфере Deep Learning данные, в большинстве случаев, выражены не табличной датой, а изображениями, видео или текстом. В настоящее время, во многих научных работах используют запатентованные наборы данных, которые не принято публиковать для широкой публики. Это становится проблемой, если вы хотите учиться и практиковать свои навыки. Ниже мы привели самые интересные датасеты, которые можно использовать в сфере глубокого обучения. Они доступны каждому, а для их использования не требуется никаких дополнительных условий.

Компьютерное зрение

1. CIFAR-10

Набор данных CIFAR-10 состоит из 60 000 цветных изображений 32×32 в 10 классах, по 6000 изображений в каждом классе. Он содержит 50 000 обучающих и 10 000 тестовых изображений. Изображения разделены на пять обучающих и одну тестовую партию по 10 000 изображений. Тестовая партия включает в себя 1000 случайно выбранных изображений из каждого класса. Обучающие партии содержат остальные изображения в случайном порядке. Однако, некоторые из обучающих партий могут содержать больше изображений из одного класса, чем из другого. Между собой обучающие партии включают 5000 изображений из каждого класса.

2. CityScapes

Это новый масштабный набор данных, который содержит разнообразные стерео видеопоследовательности, записанные в уличных сценах из 50 городов. В них содержатся высококачественные аннотации на уровне пикселей (pixel-level) для 5000 кадров, в дополнение к набору из 20 000 слабо аннотированных кадров. Таким образом, CityScapes предлагает значительно большой набор данных, чем аналогичные ресурсы.

CityScapes предназначен:

  1. Для оценки производительности алгоритмов зрения. Решение основных задач семантического понимания городских сцен: на уровне пикселей, экземпляров и паноптической семантической маркировки.
  2. Для поддержки исследований, направленных на использование больших объемов (слабо)аннотированных данных. Например, для обучения глубоких нейронных сетей.

3. Objectron

Набор данных Objectron представляет собой коллекцию коротких, ориентированных на объект видеоклипов, которые сопровождаются метаданными AR-сессии. Они включают в себя расположения камеры, разреженные облака точек и характеристику плоских поверхностей в окружающей среде. В каждом видеоролике камера перемещается вокруг объекта, снимая его под разными углами.

Данные содержат аннотированные вручную трехмерные ограничительные рамки для каждого объекта, которые описывают его положение, ориентацию и размеры. Набор данных состоит из 15 000 аннотированных видеоклипов, дополненных более чем 4 млн аннотированных изображений в следующих категориях: велосипеды, книги, бутылки, камеры, коробки с крупами, стулья, чашки, ноутбуки и обувь.

Для обеспечения географического разнообразия набор данных собран в 10 странах на 5 континентах. Вместе с «датой» ресурс предлагает решение для обнаружения 3D-объектов четырех категорий: обуви, стульев, кружек и камер. Модели, приведенные в качестве примера, обучены с использованием данных Objectron и выпущены в MediaPipe.

Анализ тональности текста


1. Sentiment analysis

Набор различных датасетов, каждый из которых содержит необходимую информацию для анализа тональности текста.

Так, данные, взятые с IMDb – это бинарный набор для анализа настроений. Он состоит из 50 000 отзывов из базы данных фильмов (IMDb), помеченных как положительные или отрицательные. Данные содержат только поляризованные отзывы. Отрицательный отзыв имеет оценку ≤ 4 из 10, положительный – ≥ 7 из 10. На каждый фильм включается не более 30 рецензий. Модели оцениваются по точности.

2. SMS спам

Коллекция SMS-спама v.1 – общедоступный набор SMS-сообщений с метками, которые были собраны для исследования спама с мобильных телефонов. Данные состоят из 5574 англоязычных, реальных и неконсолидированных сообщений, помеченных как легитимные (ham) или спам.

Сообщения SMS-спама были вручную извлечены с веб-сайта Grumbletext. Это британский форум, на котором пользователи мобильных телефонов публично заявляют о спамовых SMS-сообщениях. Идентификация текста спам-сообщений в претензиях – сложная и трудоемкая задача. Она включает тщательное сканирование сотен веб-страниц.

3. WikiQA

WikiQA представляет собой набор пар вопросов и предложений. Они были собраны и аннотированы для исследования ответов на вопросы в открытых доменах.

Большинство предыдущих работ по выбору предложений для ответа сосредоточено на наборе данных, созданном на основе данных TREC-QA, который включает вопросы, созданные редакторами, и предложения-кандидаты для ответа, отобранные по совпадению содержательных слов в вопросе.

WikiQA создана с использованием более естественного процесса. Она включает вопросы, для которых не существует правильных предложений, что позволяет исследователям работать над триггером ответа, критически важным компонентом любой системы QA.

Обработка естественного языка (NLP)


1. Text classification

Классификация текста – это задача присвоения предложению или документу соответствующей категории. Категории зависят от выбранного набора данных и могут варьироваться в зависимости от тем.

Так, TREC – это набор данных для классификации вопросов, который состоит из открытых вопросов, основанных на фактах. Они разделены на широкие семантические категории. Датасет имеет шестиклассную (TREC-6) и пятидесятиклассную (TREC-50) версии. Обе версии включают 5452 обучающих и 500 тестовых примеров.

2. Amazon Reviews dataset

Этот набор данных состоит из нескольких миллионов отзывов покупателей Amazon и их оценок. Датасет используется для возможности обучения fastText, анализируя настроения покупателей. Идея состоит в том, что несмотря на огромный объем данных – это реальная бизнес-задача. Модель обучается за считанные минуты. Именно это отличает Amazon Reviews от аналогов.

3. Yelp dataset

Набор данных Yelp – это множество предприятий, отзывов и пользовательских данных, которые можно применить в Pet-проекте и научной работе. Также можно использовать Yelp для обучения студентов во время работы с базами данных, при изучении NLP и в качестве образца производственных данных. Датасет доступен в виде файлов JSON и является «классикой» в обработке естественного языка.

Автопилоты

1. ONCE Dataset

Набор данных ONCE – крупномасштабный набор данных автономного вождения с аннотациями 2D и 3D объектов.

Включает в себя:

  1. 1 млн кадров LiDAR, 7 млн изображений с камер.
  1. 200 км² регионов вождения, 144 часа вождения.
  1. 15 000 полностью аннотированных сцен с 5 классами: автомобиль, автобус, грузовик, пешеход, велосипедист.
  1. Разнообразные условия: день/ночь, солнце/дождь, город/пригород.

2. Ford AV dataset

Ford AV dataset создан в рамках программы AWS Public Dataset Program. Представленные данные организованы на основе временных рядов. Все разделы содержат подразделы для каждого транспортного средства и карт. Каждый подраздел Vehicle включает журналы в формате rosbag, изображения PNG и файлы калибровки всех датчиков. Калибровочные данные для каждого автомобиля предоставляются отдельно.

3. Canadian Adverse Driving Conditions Dataset

CADC Dataset нацелен на продвижение исследований по улучшению самостоятельного вождения в неблагоприятных погодных условиях. Это первый публичный датасет, который посвящен реальным данным о вождении в снежных погодных условиях.

Включает в себя:

  1. 56 000 изображений с камер
  2. 7 000 разверток LiDAR
  3. 75 сцен по 50-100 кадров в каждой
  4. 10 классов аннотаций
  5. 28 194 Автомобиля
  6. 62 851 Пешеход
  7. 20 441 Грузовик
  8. 4867 Автобусов
  9. 4808 Мусорных контейнеров
  10. 3205 Объектов, направляющих движение
  11. 705 Велосипедов
  12. 638 Пешеходов с объектом
  13. 75 Лошадей и колясок
  14. 26 Животных
  15. Полный набор датчиков: 1 LiDAR, 8 камер, постобработанный GPS/IMU
  16. Неблагоприятные погодные условия вождения, включая снег

Медицинские данные


1. Health Science Library

Клинические данные являются основным источником большинства медицинских исследований. Они собираются в ходе текущего лечения пациентов или в рамках официальной программы клинических исследований.

HSL предлагает клинические данные шести основных типов:

  1. Электронные медицинские карты
  2. Административные данные
  3. Данные о претензиях
  4. Регистры пациентов/заболеваний
  5. Медицинские опросы
  6. Данные клинических исследований

2. DeepLesion

Датасет хронических заболеваний в США (US chronic diseases).

DL предлагает набор данных, которые были получены в результате более 10 тыс. исследований на 4 тыс. уникальных пациентов.

Данные включают в себя информацию о различных типах поражений, таких как: узелки в легких, опухоли печени, увеличенные лимфатические узлы и т.д. Используя DeepLesion, мы обучаем универсальный детектор поражений, который может находить все их типы поражений с помощью единой унифицированной системы.

Список лучших агрегаторов баз данных ML

Лучшие открытые наборы данных (для машинного обучения и анализа)

Приведенные выше датасеты были найдены в результате мониторинга большого количества ресурсов. Поиск этих данных – процесс трудоемкий и требует времени. Он подходит, когда данные нужны вам разово. Однако, в случае, когда данные нужны постоянно, рекомендуется использовать агрегаторы. Наиболее известными из них являются open-data от GitHub, Dataset Search от Google и Microsoft Azure.

Открытые базы данных на Github

1. Congress legislators: база данных людей, избранных в конгресс США

Члены Конгресса США (1789 – настоящее время), комитеты Конгресса (1973 – настоящее время), состав комитетов (только текущий), а также президенты и вице-президенты США в формате YAML, JSON и CSV.

Файлы хранятся в формате YAML в основной ветке этого проекта. YAML – это формат сериализации, схожий по структуре с JSON, но обычно записываемый с одним полем в строке. Как и JSON, он допускает вложенную структуру. Каждый уровень вложенности обозначается отступом или тире.

2. Covid data

Полный набор данных COVID-19 – коллекция данных о коронавирусе, которую ведет компания Our World in Data. Ресурс обновляется ежедневно в течение всего периода пандемии COVID-19.

Dataset Search от Google

Google Dataset Search – это версия поисковой системы Google, которую можно использовать для поиска наборов данных со всего мира в таких областях, как машинное обучение, социальные науки, государственные данные, геонауки, биология, науки о жизни, сельское хозяйство.

По данным Google, их Dataset Search проиндексировал около 25 миллионов наборов данных. Компания считает, что поиск данных поможет создать экосистему обмена, в которой правительства и частные компании смогут обмениваться данными, используя передовые методы хранения и публикации. Большинство открытых датасетов используют schema.org, который является стандартом. Это означает, что любой желающий может свободно загружать и использовать эти наборы данных для исследований, бизнес-аналитики, или обучения ML-модели.

Если у вас есть набор данных, который не находится в открытом доступе, вы можете сделать так, чтобы другие его увидели, добавив описание schema.org.

Открытые наборы данных Microsoft Azure

1. Russian Open Speech To Text

Коллекция образцов речи, полученных из различных аудиоисточников. Набор данных содержит короткие аудиоклипы на русском языке. Все файлы были преобразованы в opus, за исключением тех, которые служат для проверки. Основная цель набора данных – обучение моделей преобразования речи в текст.

Russian speech to text (STT) включает:

  1. ~16 миллионов высказываний
  2. ~20 000 часов
  3. 2,3 ТБ (без сжатия в формате .wav в int16), 356 ГБ

2. TartanAir

Одновременная локализация и картирование (SLAM) – одна из самых фундаментальных возможностей, необходимых для роботов. Благодаря повсеместной доступности изображений, визуальная SLAM (V-SLAM) стала важным компонентом многих автономных систем.

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

Больше о Microsoft azure datasets вы узнаете по этой ссылке.

***

В этом материале мы постарались рассказать о возможностях использования различных датасетов для реализации проектов в самых разных областях Data Science: политики, экономики, жилья, медицины, компьютерного зрения. Мы привели примеры, с помощью которых можно решить как разовые задачи с использованием ограниченного количества данных, так и задачи, которые требуют постоянного притока новой «даты».

Материалы по теме

31
Мар
2022

📊 ТОП-30 ресурсов с данными для машинного обучения

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

Где искать датасеты?

1. Kaggle

Если вы когда-нибудь проходили курсы или хакатоны, связанные с наукой о данных, вы наверняка сталкивались с Kaggle. Это сообщество специалистов по Data Science. Изначально оно было соревновательной платформой, однако со временем на Kaggle появились другие разделы, в том числе возможность делиться данными.

2. Data World

Каталог, о котором редко упоминают – Data world. По способу поиска он похож на поисковик Google. Разница в том, что глубина поиска больше, например, он включает в себя подфайлы, которые могут содержать нужные данные. Это особенно важно при поиске вторичных данных.

3. UCI Machine Learning Repository

Еще один репозиторий с сотнями наборов данных предлагает Калифорнийский университет. Данные в UCI классифицируется по типу задач машинного обучения. Можно найти данные для одномерных и многомерных временных рядов, классификации, регрессии или рекомендательных систем. Некоторые наборы данных в UCI уже очищены и готовы к использованию.

Датасеты общего назначения

Датасеты общего назначения можно использовать в простых Pet-проектах. Для анализа (EDA) или прогнозирования на их основе не нужны углубленные знания Data Science. Например, вы можете использовать простые техники машинного обучения, не углубляясь в Deep Learning.

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

Государственные датасеты

1. Данные федерального правительства США

Этот портал позволяет загружать данные из различных государственных учреждений США – от бюджетов организаций до документов школ. Спектр тем настолько широк, что делает этот ресурс идеальным для применения в разных сферах вашей деятельности, связанной с датой.

При поиске открытых данных на сайте data.gov пользователи могут применять дополнительные фильтры по категориям: темы, тип набора данных, местоположение, теги, формат файла, организации и т. д.

2. Данные министерства здравоохранения РФ

Данные с этого сайта можно использовать без заключения договора с Министерством здравоохранения РФ. Данные находится в открытом доступе. Информацию можно копировать, публиковать, распространять, видоизменять и объединять с другой информацией, использовать в некоммерческих и коммерческих целях.

3. Данные министерства культуры РФ

Этот ресурс предоставляет информацию о данных на тех же условиях, что и Министерство здравоохранения РФ.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека data scientist’а»

Данные о жилье


1. Lincolnshire (UK) House Prices

Среднемесячные цены на жилье (£) для графства Линкольншир (Англия, UK) и округов.

Все цифры включают сделки с недвижимостью от 10 000 фунтов стерлингов до более чем 1 млн. Данные отфильтрованы по типам домов. Набор данных обновляется ежемесячно за 12-месячный период.

2. Zillow Housing data

Этот набор данных состоит из нескольких датасетов:

  • Цена дома (Home values) – скорректированный на сезон показатель стоимости дома и изменения на рынке жилья в данном регионе.

В этом датасете используется мерка ZHVI – Zillow Home Values Index.

Существует ZHVI верхнего уровня (стоимость домов в диапазоне от 65-го до 95-го процентиля для данного региона) и ZHVI нижнего уровня (стоимость домов в диапазоне от 5-го до 35-го процентиля для данного региона). Zillow также публикует ZHVI для всех типов домов и апартаментов, учитывая стоимость, количество спален и метраж.

  • Прогноз цены дома (Zillow Home Values Forecast) – прогноз индекса стоимости жилья Zillow (ZHVI) на один год. ZHVF создается с использованием среза данных ZHVI по всем домам и доступен как в необработанном, так и в скорректированном виде.
  • Аренда (Rentals) – показатель рыночной ставки арендной платы в данном регионе. ZORI (Zillow Observed Rent Index) – индекс арендной платы, который определяется по всей выборке арендного жилья, обеспечивая репрезентативность данных для всего рынка аренды.

Индекс рассчитывается в долларах путем вычисления среднего значения объявленной арендной платы, которая попадает в диапазон от 40-го до 60-го процентиля для всех домов и квартир в данном регионе. Подробную информацию можно найти в методологии ZORI.

Экономика и финансы

1. Глобальный датасет инфляции в мире

Экспертная группа Всемирного банка создала глобальную базу данных инфляции, которая охватывает 196 стран за период с 1970 до 2021 гг. Она включает шесть показателей инфляции с тремя частотами – годовая, квартальная и месячная:

  • общий индекс цен
  • индекс цен на продукты питания
  • индекс цен на энергоносители,
  • базовый индекс потребительских цен
  • индекс цен производителей
  • дефлятор ВВП

Кроме того, база данных представляет совокупную инфляцию по странам мира, странам с развитой экономикой, странам с формирующимся рынком и развивающимся странам, а также показатели мировых цен на сырьевые товары.

2. Рост населения

Производная от общей численности населения. Данные можно загрузить в формате .csv, xml и .excel.

3. Рост ВВП

Данные Всемирного банка и файлы данных национальных счетов ОЭСР (Организация экономического сотрудничества и развития).

Датасеты для глубокого обучения

В сфере Deep Learning данные, в большинстве случаев, выражены не табличной датой, а изображениями, видео или текстом. В настоящее время, во многих научных работах используют запатентованные наборы данных, которые не принято публиковать для широкой публики. Это становится проблемой, если вы хотите учиться и практиковать свои навыки. Ниже мы привели самые интересные датасеты, которые можно использовать в сфере глубокого обучения. Они доступны каждому, а для их использования не требуется никаких дополнительных условий.

Компьютерное зрение

1. CIFAR-10

Набор данных CIFAR-10 состоит из 60 000 цветных изображений 32×32 в 10 классах, по 6000 изображений в каждом классе. Он содержит 50 000 обучающих и 10 000 тестовых изображений. Изображения разделены на пять обучающих и одну тестовую партию по 10 000 изображений. Тестовая партия включает в себя 1000 случайно выбранных изображений из каждого класса. Обучающие партии содержат остальные изображения в случайном порядке. Однако, некоторые из обучающих партий могут содержать больше изображений из одного класса, чем из другого. Между собой обучающие партии включают 5000 изображений из каждого класса.

2. CityScapes

Это новый масштабный набор данных, который содержит разнообразные стерео видеопоследовательности, записанные в уличных сценах из 50 городов. В них содержатся высококачественные аннотации на уровне пикселей (pixel-level) для 5000 кадров, в дополнение к набору из 20 000 слабо аннотированных кадров. Таким образом, CityScapes предлагает значительно большой набор данных, чем аналогичные ресурсы.

CityScapes предназначен:

  1. Для оценки производительности алгоритмов зрения. Решение основных задач семантического понимания городских сцен: на уровне пикселей, экземпляров и паноптической семантической маркировки.
  2. Для поддержки исследований, направленных на использование больших объемов (слабо)аннотированных данных. Например, для обучения глубоких нейронных сетей.

3. Objectron

Набор данных Objectron представляет собой коллекцию коротких, ориентированных на объект видеоклипов, которые сопровождаются метаданными AR-сессии. Они включают в себя расположения камеры, разреженные облака точек и характеристику плоских поверхностей в окружающей среде. В каждом видеоролике камера перемещается вокруг объекта, снимая его под разными углами.

Данные содержат аннотированные вручную трехмерные ограничительные рамки для каждого объекта, которые описывают его положение, ориентацию и размеры. Набор данных состоит из 15 000 аннотированных видеоклипов, дополненных более чем 4 млн аннотированных изображений в следующих категориях: велосипеды, книги, бутылки, камеры, коробки с крупами, стулья, чашки, ноутбуки и обувь.

Для обеспечения географического разнообразия набор данных собран в 10 странах на 5 континентах. Вместе с «датой» ресурс предлагает решение для обнаружения 3D-объектов четырех категорий: обуви, стульев, кружек и камер. Модели, приведенные в качестве примера, обучены с использованием данных Objectron и выпущены в MediaPipe.

Анализ тональности текста


1. Sentiment analysis

Набор различных датасетов, каждый из которых содержит необходимую информацию для анализа тональности текста.

Так, данные, взятые с IMDb – это бинарный набор для анализа настроений. Он состоит из 50 000 отзывов из базы данных фильмов (IMDb), помеченных как положительные или отрицательные. Данные содержат только поляризованные отзывы. Отрицательный отзыв имеет оценку ≤ 4 из 10, положительный – ≥ 7 из 10. На каждый фильм включается не более 30 рецензий. Модели оцениваются по точности.

2. SMS спам

Коллекция SMS-спама v.1 – общедоступный набор SMS-сообщений с метками, которые были собраны для исследования спама с мобильных телефонов. Данные состоят из 5574 англоязычных, реальных и неконсолидированных сообщений, помеченных как легитимные (ham) или спам.

Сообщения SMS-спама были вручную извлечены с веб-сайта Grumbletext. Это британский форум, на котором пользователи мобильных телефонов публично заявляют о спамовых SMS-сообщениях. Идентификация текста спам-сообщений в претензиях – сложная и трудоемкая задача. Она включает тщательное сканирование сотен веб-страниц.

3. WikiQA

WikiQA представляет собой набор пар вопросов и предложений. Они были собраны и аннотированы для исследования ответов на вопросы в открытых доменах.

Большинство предыдущих работ по выбору предложений для ответа сосредоточено на наборе данных, созданном на основе данных TREC-QA, который включает вопросы, созданные редакторами, и предложения-кандидаты для ответа, отобранные по совпадению содержательных слов в вопросе.

WikiQA создана с использованием более естественного процесса. Она включает вопросы, для которых не существует правильных предложений, что позволяет исследователям работать над триггером ответа, критически важным компонентом любой системы QA.

Обработка естественного языка (NLP)


1. Text classification

Классификация текста – это задача присвоения предложению или документу соответствующей категории. Категории зависят от выбранного набора данных и могут варьироваться в зависимости от тем.

Так, TREC – это набор данных для классификации вопросов, который состоит из открытых вопросов, основанных на фактах. Они разделены на широкие семантические категории. Датасет имеет шестиклассную (TREC-6) и пятидесятиклассную (TREC-50) версии. Обе версии включают 5452 обучающих и 500 тестовых примеров.

2. Amazon Reviews dataset

Этот набор данных состоит из нескольких миллионов отзывов покупателей Amazon и их оценок. Датасет используется для возможности обучения fastText, анализируя настроения покупателей. Идея состоит в том, что несмотря на огромный объем данных – это реальная бизнес-задача. Модель обучается за считанные минуты. Именно это отличает Amazon Reviews от аналогов.

3. Yelp dataset

Набор данных Yelp – это множество предприятий, отзывов и пользовательских данных, которые можно применить в Pet-проекте и научной работе. Также можно использовать Yelp для обучения студентов во время работы с базами данных, при изучении NLP и в качестве образца производственных данных. Датасет доступен в виде файлов JSON и является «классикой» в обработке естественного языка.

Автопилоты

1. ONCE Dataset

Набор данных ONCE – крупномасштабный набор данных автономного вождения с аннотациями 2D и 3D объектов.

Включает в себя:

  1. 1 млн кадров LiDAR, 7 млн изображений с камер.
  1. 200 км² регионов вождения, 144 часа вождения.
  1. 15 000 полностью аннотированных сцен с 5 классами: автомобиль, автобус, грузовик, пешеход, велосипедист.
  1. Разнообразные условия: день/ночь, солнце/дождь, город/пригород.

2. Ford AV dataset

Ford AV dataset создан в рамках программы AWS Public Dataset Program. Представленные данные организованы на основе временных рядов. Все разделы содержат подразделы для каждого транспортного средства и карт. Каждый подраздел Vehicle включает журналы в формате rosbag, изображения PNG и файлы калибровки всех датчиков. Калибровочные данные для каждого автомобиля предоставляются отдельно.

3. Canadian Adverse Driving Conditions Dataset

CADC Dataset нацелен на продвижение исследований по улучшению самостоятельного вождения в неблагоприятных погодных условиях. Это первый публичный датасет, который посвящен реальным данным о вождении в снежных погодных условиях.

Включает в себя:

  1. 56 000 изображений с камер
  2. 7 000 разверток LiDAR
  3. 75 сцен по 50-100 кадров в каждой
  4. 10 классов аннотаций
  5. 28 194 Автомобиля
  6. 62 851 Пешеход
  7. 20 441 Грузовик
  8. 4867 Автобусов
  9. 4808 Мусорных контейнеров
  10. 3205 Объектов, направляющих движение
  11. 705 Велосипедов
  12. 638 Пешеходов с объектом
  13. 75 Лошадей и колясок
  14. 26 Животных
  15. Полный набор датчиков: 1 LiDAR, 8 камер, постобработанный GPS/IMU
  16. Неблагоприятные погодные условия вождения, включая снег

Медицинские данные


1. Health Science Library

Клинические данные являются основным источником большинства медицинских исследований. Они собираются в ходе текущего лечения пациентов или в рамках официальной программы клинических исследований.

HSL предлагает клинические данные шести основных типов:

  1. Электронные медицинские карты
  2. Административные данные
  3. Данные о претензиях
  4. Регистры пациентов/заболеваний
  5. Медицинские опросы
  6. Данные клинических исследований

2. DeepLesion

Датасет хронических заболеваний в США (US chronic diseases).

DL предлагает набор данных, которые были получены в результате более 10 тыс. исследований на 4 тыс. уникальных пациентов.

Данные включают в себя информацию о различных типах поражений, таких как: узелки в легких, опухоли печени, увеличенные лимфатические узлы и т.д. Используя DeepLesion, мы обучаем универсальный детектор поражений, который может находить все их типы поражений с помощью единой унифицированной системы.

Список лучших агрегаторов баз данных ML

Лучшие открытые наборы данных (для машинного обучения и анализа)

Приведенные выше датасеты были найдены в результате мониторинга большого количества ресурсов. Поиск этих данных – процесс трудоемкий и требует времени. Он подходит, когда данные нужны вам разово. Однако, в случае, когда данные нужны постоянно, рекомендуется использовать агрегаторы. Наиболее известными из них являются open-data от GitHub, Dataset Search от Google и Microsoft Azure.

Открытые базы данных на Github

1. Congress legislators: база данных людей, избранных в конгресс США

Члены Конгресса США (1789 – настоящее время), комитеты Конгресса (1973 – настоящее время), состав комитетов (только текущий), а также президенты и вице-президенты США в формате YAML, JSON и CSV.

Файлы хранятся в формате YAML в основной ветке этого проекта. YAML – это формат сериализации, схожий по структуре с JSON, но обычно записываемый с одним полем в строке. Как и JSON, он допускает вложенную структуру. Каждый уровень вложенности обозначается отступом или тире.

2. Covid data

Полный набор данных COVID-19 – коллекция данных о коронавирусе, которую ведет компания Our World in Data. Ресурс обновляется ежедневно в течение всего периода пандемии COVID-19.

Dataset Search от Google

Google Dataset Search – это версия поисковой системы Google, которую можно использовать для поиска наборов данных со всего мира в таких областях, как машинное обучение, социальные науки, государственные данные, геонауки, биология, науки о жизни, сельское хозяйство.

По данным Google, их Dataset Search проиндексировал около 25 миллионов наборов данных. Компания считает, что поиск данных поможет создать экосистему обмена, в которой правительства и частные компании смогут обмениваться данными, используя передовые методы хранения и публикации. Большинство открытых датасетов используют schema.org, который является стандартом. Это означает, что любой желающий может свободно загружать и использовать эти наборы данных для исследований, бизнес-аналитики, или обучения ML-модели.

Если у вас есть набор данных, который не находится в открытом доступе, вы можете сделать так, чтобы другие его увидели, добавив описание schema.org.

Открытые наборы данных Microsoft Azure

1. Russian Open Speech To Text

Коллекция образцов речи, полученных из различных аудиоисточников. Набор данных содержит короткие аудиоклипы на русском языке. Все файлы были преобразованы в opus, за исключением тех, которые служат для проверки. Основная цель набора данных – обучение моделей преобразования речи в текст.

Russian speech to text (STT) включает:

  1. ~16 миллионов высказываний
  2. ~20 000 часов
  3. 2,3 ТБ (без сжатия в формате .wav в int16), 356 ГБ

2. TartanAir

Одновременная локализация и картирование (SLAM) – одна из самых фундаментальных возможностей, необходимых для роботов. Благодаря повсеместной доступности изображений, визуальная SLAM (V-SLAM) стала важным компонентом многих автономных систем.

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

Больше о Microsoft azure datasets вы узнаете по этой ссылке.

***

В этом материале мы постарались рассказать о возможностях использования различных датасетов для реализации проектов в самых разных областях Data Science: политики, экономики, жилья, медицины, компьютерного зрения. Мы привели примеры, с помощью которых можно решить как разовые задачи с использованием ограниченного количества данных, так и задачи, которые требуют постоянного притока новой «даты».

Материалы по теме

21
Мар
2022

Интенсив «Как выбрать язык программирования и найти работу»

Познакомитесь с различными языками и направлениями в программировании, узнаете о профессии и карьере разработчика. Поймёте, что вам интереснее, и подберёте подходящую специализацию.
— Читать дальше «Интенсив «Как выбрать язык программирования и найти р…

03
Мар
2022

🎞️ Улучшение видео нейросетью: ТОП 3 программ (бесплатные и платные)

Применение нейросетей и искусственного интеллекта стали неотъемлемой частью нашей жизни. Обработка видео – одна из сфер, где возможности ИИ используют очень активно. В этом материале мы расскажем о приемах и программах, которые помогают пов…

28
Фев
2022

🐼 25 возможностей Pandas, о которых вы не знали

Новые и малоизвестные возможности Pandas, о которых полезно знать каждому специалисту по Data Science.

Сколько раз вы говорили: «было бы здорово, если бы я мог это сделать в Pandas»?

Возможно, вы это и можете! Pandas настолько огромна и глубока, что она позволяет выполнять практически любые операции с таблицами, которые вы можете себе представить. Однако подобная глубина имеет свою цену. Многие элегантные возможности, решающие редко возникающие задачи и уникальные сценарии, теряются в глубинах документации, затертые более часто используемыми функциями.

Эта статья попытается заново открыть для вас многие возможности Pandas и показать, что она может намного больше, чем вам казалось.

Автор <a href="https://www.pexels.com/@introspectivedsgn" target="_blank" rel="noopener noreferrer nofollow">Erik Mclean</a>. Источник <a href="https://www.pexels.com/photo/unrecognizable-man-in-panda-head-sitting-near-car-5199661" target="_blank" rel="noopener noreferrer nofollow">Pexels</a>
Автор Erik Mclean. Источник Pexels

1. ExcelWriter

ExcelWriter – это обобщенный класс для создания файлов Excel (с листами!) и записи в них DataFrame. Допустим, у нас есть два набора данных:

        # Загрузим два набора данных
diamonds = sns.load_dataset("diamonds")
tips = sns.load_dataset("tips")

# Пишем оба в один и тот же файл Excel
with pd.ExcelWriter("data/data.xlsx") as writer:
    diamonds.to_excel(writer, sheet_name="diamonds")
    tips.to_excel(writer, sheet_name="tips")
    

У класса есть дополнительные атрибуты для определения используемого формата DateTime: хотите ли вы создать новый файл Excel или изменить существующий, что делать, если лист существует и т. п. Детали см. в документации.

2. pipe

Автор <a href="https://www.pexels.com/@leah-kelley-50725" target="_blank" rel="noopener noreferrer nofollow">Leah Kelley</a>. Источник <a href="https://www.pexels.com/photo/grayscale-photo-of-man-holding-tobacco-pipe-192473/" target="_blank" rel="noopener noreferrer nofollow">Pexels</a>
Автор Leah Kelley. Источник Pexels

pipe – одна из лучших функций для проведения очистки данных в Pandas кратким и четким образом. Она позволяет объединять несколько пользовательских функций в одну операцию.

Для примера допустим, что у вас есть функции удаления дубликатов (remove_duplicates), удаления выбросов (remove_outliers) и кодирования категориальных признаков (encode_categoricals), каждая со своими аргументами. Вот как вы можете применить все эти функции одной операцией:

        df_preped = (diamonds.pipe(drop_duplicates).
                      pipe(remove_outliers, ['price', 'carat', 'depth']).
                      pipe(encode_categoricals, ['cut', 'color', 'clarity'])
            )
    

Мне нравится, что эта функция похожа на конвейеры Sklearn. Вы можете сделать с ее помощью намного больше – читайте документацию или эту полезную статью.

Больше полезной информации вы найдете на нашем телеграм-канале «Библиотека data scientist’а»

3. factorize

Эта функция – альтернатива LabelEncoder из Sklearn в Pandas:

        # Обратите внимание на [0] в конце
diamonds["cut_enc"] = pd.factorize(diamonds["cut"])[0]

>>> diamonds["cut_enc"].sample(5)

52103    2
39813    0
31843    0
10675    0
6634     0
Name: cut_enc, dtype: int64
    

В отличие от LabelEncoder‘а, factorize возвращает кортеж из двух значений: закодированный столбец и список уникальных категорий.

        codes, unique = pd.factorize(diamonds["cut"], sort=True)

>>> codes[:10]
array([0, 1, 3, 1, 3, 2, 2, 2, 4, 2], dtype=int64)

>>> unique
['Ideal', 'Premium', 'Very Good', 'Good', 'Fair']
    

4. explode – Бабах!

 Автор <a href="https://unsplash.com/@joshuas" target="_blank" rel="noopener noreferrer nofollow">Joshua Sukoff</a>. Источник <a href="https://unsplash.com/s/photos/explode" target="_blank" rel="noopener noreferrer nofollow">Unsplash</a>
Автор Joshua Sukoff. Источник Unsplash

explode – это функция с интересным именем (взрыв). Давайте сначала посмотрим пример, а потом объясним:

        data = pd.Series([1, 6, 7, [46, 56, 49], 45, [15, 10, 12]]).to_frame("dirty")

>>> data
    

В столбце dirty есть две строки, в которых хранятся не единственные значения, а списки. Такие данные часто встречаются в опросах, поскольку некоторые вопросы допускают несколько ответов.

        >>> data.explode("dirty", ignore_index=True)
    

explode распространяет данные из ячейки с массивоподобным значением на несколько строк. Установите ignore_index в True, чтобы сохранить числовой индекс по порядку.

5. squeeze

 Автор <a href="https://www.pexels.com/@cottonbro?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels" target="_blank" rel="noopener noreferrer nofollow">cottonbro</a>. Источник <a href="https://www.pexels.com/photo/close-up-photo-of-sausage-5875701/" target="_blank" rel="noopener noreferrer nofollow">Pexels</a>
Автор cottonbro. Источник Pexels

Еще одна функция с забавным именем – это squeeze (сжатие), используемая в очень редких, но надоедливых случаях. Один из таких случаев – когда запрос подмножества из DataFrame возвращает единственное значение. Рассмотрим следующий пример:

        subset = diamonds.loc[diamonds.index < 1, ["price"]]

>>> subset
    

Хотя результат – всего одна ячейка, он возвращается как DataFrame. Это неудобно, поскольку вам придется еще раз использовать .loc и передать как имя столбца, так и индекс, чтобы получить цену.

Но если вы знаете про squeeze, нам не придется этого делать. Эта функция позволяет убрать оси из DataFrame или Series, содержащих единственную ячейку. Например:

        >>> subset.squeeze()
326
    

Теперь мы получили скалярное значение. Можно также указать, какую ось нужно убрать:

        >>> subset.squeeze("columns")  # или "rows"

0    326
Name: price, dtype: int64
    

Обратите внимание, что squeeze работает только с DataFrame и Series, имеющими единственное значение.

6. between

 Автор <a href="https://unsplash.com/@jujudreaminx" target="_blank" rel="noopener noreferrer nofollow">Justin Dream</a>. Источник <a href="https://unsplash.com/photos/BxNyZdCbdz0" target="_blank" rel="noopener noreferrer nofollow">Pexels</a>
Автор Justin Dream. Источник Pexels

Это довольно изящная функция для бинарного индексирования числовых признаков по принадлежности диапазону:

        # Выбрать бриллианты с ценой от 3500 до 3700 долларов
diamonds[diamonds["price"]\
      .between(3500, 3700, inclusive="neither")].sample(5)
    

7. T

У всех DataFrame есть простой атрибут T, что значит «транспонирование». Возможно, вы не будете часто его использовать, но я считаю его довольно полезным при выводе DataFrame’ов после метода describe():

        >>> boston.describe().T.head(10)
    

Набор данных о недвижимости Бостона содержит 30 числовых столбцов. Если просто вызвать describe, результирующий DataFrame будет сжат по горизонтали, и сравнить статистику будет трудно. Транспонирование поменяет оси местами, и по горизонтали будут уже статистические параметры.

8. Стилизатор Pandas

А вы знали, что Pandas позволяет вам задавать стили DataFrame’ов?

У них есть атрибут style, открывающий дверь к настройкам и стилям, ограниченным только вашими знаниями HTML и CSS. Я не буду рассказывать обо всем, что вы можете сделать с помощью style, покажу лишь свои любимые функции:

        >>> diabetes.describe().T.drop("count", axis=1)\
                 .style.highlight_max(color="darkred")
    

Мы выделили ячейки, содержащие максимальные значения каждого столбца. Еще один полезный стилизатор – background_gradient, присваивающий ячейкам градиентный фоновый цвет на основе их значений:

        diabetes.describe().T.drop("count", axis=1).style.background_gradient(
    subset=["mean", "50%"], cmap="Reds"
)
    

Это особенно полезно, если вы вызываете describe для таблицы со множеством столбцов и хотите сравнить суммарную статистику. Подробности см. в документации по стилизатору.

9. Опции Pandas

Как и в Matplotlib, в Pandas есть глобальные настройки, которые можно изменять для настройки поведения по умолчанию:

        >>> dir(pd.options)
['compute', 'display', 'io', 'mode', 'plotting']
    

Эти настройки разделены на 5 модулей. Давайте посмотрим, какие настройки есть в модуле display:

        >>> dir(pd.options.display)

['chop_threshold',
 'max_columns',
 'max_colwidth',
 'max_info_columns',
 'max_info_rows',
 'max_rows',
 ...
 'precision',
 'show_dimensions',
 'unicode',
 'width']
    

В группе display много настроек, но я в основном использую max_columns и precision:

        # Убрать лимит на изображаемое количество столбцов
pd.options.display.max_columns = None

# Показывать только 5 цйфр после запятой
pd.options.display.precision = 5  # избавиться от научной нотации
    

Больше подробностей об этих замечательных настройках можно найти в документации.

10. convert_dtypes

Все мы знаем, что Pandas имеет раздражающую привычку присваивать столбцам тип данных object. Вместо того чтобы назначать типы данных вручную, вы можете использовать метод convert_dtypes, который пытается подобрать наиболее подходящий тип данных:

        sample = pd.read_csv(
    "data/station_day.csv",
    usecols=["StationId", "CO", "O3", "AQI_Bucket"],
)

>>> sample.dtypes

StationId      object
CO            float64
O3            float64
AQI_Bucket     object
dtype: object

>>> sample.convert_dtypes().dtypes

StationId      string
CO            float64
O3            float64
AQI_Bucket     string
dtype: object
    

К сожалению, метод не может разбирать даты из-за нюансов различных форматов их представления.

11. select_dtypes

Функция, которую я использую постоянно – это select_dtypes. Ее функционал очевиден из ее названия: выбор по типам данных. У нее есть параметры include и exclude, позволяющие выбрать столбцы, включая или исключая определенные типы данных. Например, можно выбрать только числовые столбцы, указав np.number:

        # Выбрать только числовые столбцы
diamonds.select_dtypes(include=np.number).head()
    

или, наоборот, исключить их:

        # Исключить числовые столбцы
diamonds.select_dtypes(exclude=np.number).head()
    

12. mask

 Автор <a href="https://www.pexels.com/@pixabay" target="_blank" rel="noopener noreferrer nofollow">Pixabay</a>. Источник <a href="https://www.pexels.com/photo/guy-fawkes-mask-and-red-flower-on-hand-38275/" target="_blank" rel="noopener noreferrer nofollow">Pexels.</a>
Автор Pixabay. Источник Pexels.

Функция mask позволяет быстро заменять значения в тех ячейках, для которых выполняется определенное условие. Предположим, что у нас есть данные опроса людей от 50 до 60:

        # Create sample data
ages = pd.Series([55, 52, 50, 66, 57, 59, 49, 60]).to_frame("ages")

ages
    

Мы будем считать возраст, выходящий за границы от 50 до 60 лет, ошибками ввода (таких ошибок две – 49 и 66 лет), которые заменим на NaN:

        ages.mask(cond=~ages["ages"].between(50, 60), other=np.nan)
    

Таким образом, mask заменяет значения ячеек, не удовлетворяющие cond, значениями other.

13. min и max по строкам и столбцам

Хотя функции min и max широко известны, они имеют еще одно применение, полезное для особых случаев. Давайте рассмотрим следующий набор данных:

        index = ["Diamonds", "Titanic", "Iris", "Heart Disease", "Loan Default"]
libraries = ["XGBoost", "CatBoost", "LightGBM", "Sklearn GB"]

df = pd.DataFrame(
    {lib: np.random.uniform(90, 100, 5) for lib in libraries}, index=index
)

>>> df
    

Этот DataFrame содержит воображаемую точность моделей, полученных в результате четырех видов градиентного бустинга на пяти различных наборах данных. Мы хотим найти лучшую точность на каждом наборе. Вот как элегантно это можно сделать с помощью max:

        >>> df.max(axis=1)

Diamonds         99.52684
Titanic          99.63650
Iris             99.10989
Heart Disease    99.31627
Loan Default     97.96728
dtype: float64
    

Если вы хотите найти максимум или минимум по каждому столбцу, достаточно изменить 1 на 0.

14. nlargest и nsmallest

Иногда вам недостаточно получить максимальное или минимальное значение столбца. Вы хотите получить N максимальных (или минимальных) значений. Для этого пригодятся функции nlargest и nsmallest. Давайте выведем 5 самых дорогих и самых дешевых бриллиантов:

        diamonds.nlargest(5, "price")
    

        diamonds.nsmallest(5, "price")
    

15. idxmax и idxmin

Когда вы вызываете max или min для столбца, pandas возвращает максимальное или минимальное значение. Однако иногда вам нужна позиция этого значения, а не оно само. Для этого используйте функции idxmax и idxmin:

        >>> diamonds.price.idxmax()
27749

>>> diamonds.carat.idxmin()
14
    

Можно также задать axis=’columns’, при этом функции будут возвращать номер индекса нужного столбца.

16. value_counts с параметром dropna=False

Для нахождения процента пропущенных значений чаще всего используется комбинация isnull и sum и деление на длину массива. Но вы можете сделать то же самое с помощью value_counts, если задать соответствующие аргументы:

        ames_housing = pd.read_csv("data/train.csv")

>>> ames_housing["FireplaceQu"].value_counts(dropna=False, normalize=True)

NaN    0.47260
Gd     0.26027
TA     0.21438
Fa     0.02260
Ex     0.01644
Po     0.01370
Name: FireplaceQu, dtype: float64
    

В этом столбце 47% пустых значений (NaN).

17. clip

 Автор <a href="https://www.pexels.com/@ann-h-45017" target="_blank" rel="noopener noreferrer nofollow">Ann H</a>. Источник <a href="https://www.pexels.com/photo/a-lot-of-paper-clips-2448452/" target="_blank" rel="noopener noreferrer nofollow">Pexels</a>
Автор Ann H. Источник Pexels

Обнаружение и удаление выбросов часто используется в анализе данных. Функция clip позволяет очень легко найти выбросы, выходящие за пределы диапазона и заменить их предельными значениями. Давайте вернемся к примеру с возрастами людей от 50 до 60:


На этот раз мы заменим значения, выходящие за диапазон от 50 до 60, крайними значениями диапазона.

        ages.clip(50, 60)
    

Быстро и эффективно!

18. at_time и between_time

Эти функции могут пригодиться при работе с данными, разделенными по времени с высокой степенью детализации. Давайте создадим таблицу, содержащую 100 часовых интервалов:

        index = pd.date_range("2021-08-01", periods=100, freq="H")
data = pd.DataFrame({"col": list(range(100))}, index=index)

>>> data.head()
    

Функция at_time позволяет выбирать значения по заданным дате или времени. Давайте выделим все строки, соответствующие 15.00:

        data.at_time("15:00")
    

Здорово, правда? А теперь давайте используем between_time, чтобы выделить строки в заданном интервале времени:

        from datetime import datetime

>>> data.between_time("09:45", "12:00")
    

Заметьте, что обе функции требуют DateTimeIndex, и они работают только с временем. Если вы хотите выделить строки в определенном интервале DateTime, используйте between.

19. bdate_range

bdate_range – это функция для быстрого создания индексов TimeSeries с частотой в один бизнес-день.

        series = pd.bdate_range("2021-01-01", "2021-01-31")  # A period of one month

>>> len(series)
21
    

Частота в бизнес-день часто встречается в финансовом мире. Значит, эта функция может оказаться полезной для переиндексирования существующих временных интервалов функцией reindex.

20. autocorr

Один из важнейших компонентов анализа временных последовательностей – это изучение автокорреляции переменной. Автокорреляция – это старый добрый коэффициент корреляции, но взятый по сравнению с лагом той же последовательности. Точнее, автокорреляция при lag=k вычисляется следующим образом:

1. Последовательность сдвигается k периодов времени:

        time_series = tips[["tip"]]
time_series["lag_1"] = time_series["tip"].shift(1)
time_series["lag_2"] = time_series["tip"].shift(2)
time_series["lag_3"] = time_series["tip"].shift(3)
time_series["lag_4"] = time_series["tip"].shift(4)
# time_series['lag_k'] = time_series['tip'].shift(k)

>>> time_series.head()
    

2. Рассчитывается корреляция между исходным значением и каждым лагом.

Вместо того чтобы делать все это вручную, вы можете использовать функцию Pandas autocorr:

        # Автокорреляция tip при lag_8
>>> time_series["tip"].autocorr(lag=8)
0.07475238789967077
    

О важности автокорреляции для анализа временных рядов можно прочитать в этой статье.

21. hasnans

Pandas предлагает метод для простой проверки, содержит ли Series какие-либо пустые значения – атрибут hasnans:

        series = pd.Series([2, 4, 6, "sadf", np.nan])

>>> series.hasnans
True
    

Согласно его документации, атрибут существенно ускоряет производительность. Заметьте, что он работает только для Series.

22. at и iat

Эти два метода доступа к значениям – гораздо более быстрые альтернативы loc и iloc, но с существенным недостатком: они позволяют получить или изменить только одно значение:

        # [index, label]
>>> diamonds.at[234, "cut"]
'Ideal'

# [index, index]
>>> diamonds.iat[1564, 4]
61.2

# Заменить 16541-ю строку столбца price
>>> diamonds.at[16541, "price"] = 10000
    

23. argsort

Эту функцию стоит использовать каждый раз, когда вы хотите выделить индексы, образующие отсортированный массив:

        tips.reset_index(inplace=True, drop=True)

sort_idx = tips["total_bill"].argsort(kind="mergesort")

# Теперь выведем значения `tips` в порядке сортировки по total_bill
tips.iloc[sort_idx].head()
    

24. Метод доступа cat

Общеизвестно, что Pandas позволяет использовать встроенные функции Python на датах и строках с помощью методов доступа вроде dt или str. Кроме того, в Pandas есть специальный тип данных category для категориальных переменных, как показано ниже:

        >>> diamonds.dtypes

carat       float64
cut        category
color      category
clarity    category
depth       float64
table       float64
price         int64
x           float64
y           float64
z           float64
cut_enc       int64
dtype: object
    

Если столбец имеет тип category, над ним можно выполнять несколько специальных функций с помощью метода доступа cat. Например, давайте рассмотрим различные виды огранки бриллиантов:

        >>> diamonds["cut"].cat.categories
['Ideal', 'Premium', 'Very Good', 'Good', 'Fair']
    

Есть и такие функции, как remove_categories, rename_categories и т. д.:

        diamonds["new_cuts"] = diamonds["cut"].cat.rename_categories(list("ABCDE"))

>>> diamonds["new_cuts"].cat.categories
Index(['A', 'B', 'C', 'D', 'E'], dtype='object')
    

Полный список функций, доступных через метод доступа cat, можно посмотреть здесь.

25. GroupBy.nth

Эта функция работает только для объектов GroupBy. После группировки она возвращает n-ю строку каждой группы:

        diamonds.groupby("cut").nth(5)
    

Заключение

Несмотря на то, что новые библиотеки вроде Dask и datatable потихоньку вытесняют Pandas благодаря их сверкающим новым возможностям для обработки огромных массивов данных, Pandas по-прежнему остается самым популярным средством манипуляции данными в экосистеме Data Science на Python.

Эта библиотека – образец для подражания, который другие пытаются имитировать и улучшить, поскольку она прекрасно интегрируется в современный стек SciPy.

Спасибо за внимание!

***

Материалы по теме

21
Фев
2022

🎲🐍 Моделируем игру в кости на Python с помощью метода Монте-Карло

В этой статье учимся использовать метод Монте-Карло для прогнозирования вероятностей.

Что такое моделирование методом Монте-Карло?

Моделирование Монте-Карло – это тип вычислительного алгоритма, оценивающий вероятность возникновения неопределенного события из-за участия случайных величин. Алгоритм основан на повторной случайной выборке в попытке определить вероятность. Это означает моделирование событий со случайными входными данными большое число раз для получения оценки. Также определяются и другие факторы, которые будут видны на примере. Моделирование по методу Монте-Карло используется в экономике, азартных играх, машиностроении, энергетической отрасли. Поэтому знание этого метода будет полезно для многих областей. Модель Монте-Карло легко понять на примере игры в кости.

Игра в кости

В этой игре будут задействованы 2 шестигранных кубика. Для выигрыша игроку требуется выбросить одинаковое число на обоих кубиках. Шестигранный кубик имеет 6 возможных исходов (1, 2, 3, 4, 5 и 6). С двумя кубиками 36 возможных исходов (1 и 1, 1 и 2, 1 и 3 и т. д., или 6 х 6 = 36 вариантов). В этой игре у заведения больше шансов на победу (30 исходов против 6 у игроков), следовательно, у заведения значительное преимущество.

Предположим, игрок начинает с баланса в 1000$ и готов проиграть все, поэтому ставит 1$ на каждый бросок (оба кубика) и решает сделать 1000 бросков. Предположим, что заведение щедрое и выплата будет в 4 раза больше ставки, когда игрок выигрывает. Например, если игрок выиграет первый бросок, баланс увеличится на 4$, и раунд закончится с 1004$. Если чудом получится выиграть серию из 1000 бросков, то итого получится 5000$. В случае каждого неудачного раунда получится 0$.

Импорт библиотек Python

Смоделируем игру, чтобы выяснить, сделал ли игрок правильный выбор. Начнем код с импорта необходимых библиотек Python: Pyplot из Matplotlib и random. Для визуализации результатов будет использоваться библиотека Pyplot, для моделирования броска шестигранной игральной кости – random.

        # Импорт библиотек
import matplotlib.pyplot as plt
import random

    

Функция броска кубиков

Далее определим функцию, которая будет выдавать случайное целое число от 1 до 6 для обеих костей (имитация броска). Функция будет сравнивать значение обеих костей и возвращать логическое значение – одинаковы броски или нет. Позже это значение будет использоваться для определения действий в коде.

        # Создаем функцию броска кубика
def roll_dice():
    die_1 = random.randint(1, 6)
    die_2 = random.randint(1, 6)

    # Определим является ли значение на костях одинаковым
    if die_1 == die_2:
        same_num = True
    else:
        same_num = False
    return same_num

    

Входные данные и отслеживаемые переменные

Каждое моделирование методом Монте-Карло требует знание входных данных и информации, которую требуется получить. Входные данные определены, когда описывалась игра. Количество бросков за игру 1000 раз, сумма за бросок 1$. В дополнение требуется определить – сколько раз игра будет моделироваться. В качестве счетчика Монте-Карло используем переменную num_simulations. Чем больше это число, тем точнее прогнозируемая вероятность соответствует истинному значению.

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

        # Входные данные
num_simulations = 10000
max_num_rolls = 1000
bet = 1

# Отслеживаемые переменные
win_probability = []
end_balance = []

    

Настройка фигуры

Следующий шаг – это настройка фигуры перед запуском симуляции: это позволит добавлять линии к рисунку после каждой игры. После запуска всех симуляций отобразим график, чтобы показать результаты.

        # Создание фигуры, для симуляции баланса
fig = plt.figure()
plt.title("Monte Carlo Dice Game [" + str(num_simulations) + "   
          simulations]")
plt.xlabel("Roll Number")
plt.ylabel("Balance [$]")
plt.xlim([0, max_num_rolls])

    

Моделирование Монте-Карло

В коде ниже 2 цикла: внешний, который перебирает заданное кол-во симуляций (10000) и вложенный, который запускает каждую игру (1000 бросков). Перед запуском каждого цикла while инициализируется:

  • баланс игрока как 1000$(в виде списка для построения графиков);
  • количество бросков и выигрышей.

Цикл while будет моделировать игру на 1000 бросков. Внутри этого цикла бросаются кости, используя логическую переменную, возвращаемую функцией roll_dice() для определения результата. Если кости одинаковые – в список баланса добавляется 4-кратная ставка и выигрыш к счету игрока. Если кости разные – вычитается ставка из списка баланса. В конце каждого броска добавляем счетчик в список num_rolls.

Как только количество бросков достигло 1000, рассчитываем вероятность выигрыша игрока, как количество выигрышей, деленное на общее количество бросков. Сохраняем конечный баланс завершенной игры в отслеживаемой переменной end_balance.

        # Цикл for запускает желаемое количество симуляций
for i in range(num_simulations):
    balance = [1000]
    num_rolls = [0]
    num_wins = 0
    # Выполняется до тех пор пока игрок не выкинет 1000 раз
    while num_rolls[-1] < max_num_rolls:
        same = roll_dice()
        # Результат если кости одинаковые
        if same:
            balance.append(balance[-1] + 4 * bet)
            num_wins += 1
        # Результат если кости разные
        else:
            balance.append(balance[-1] - bet)

        num_rolls.append(num_rolls[-1] + 1)
    # Сохраняем отслеживаемую переменную и добавляем строку к рисунку
    win_probability.append(num_wins/num_rolls[-1])
    end_balance.append(balance[-1])
    plt.plot(num_rolls, balance)

    

Получение результатов

Последний шаг – вывод осмысленных данных из отслеживаемых переменных. Отобразим фигуру (показанную ниже), созданную в цикле for. Также рассчитаем и отобразим общую вероятность выигрыша и конечный баланс, усредняя списки win_probability и end_balance.

        # Выведем график после завершения моделирования
plt.show()

# Усредненная вероятность выигрыша и конечного баланса
overall_win_probability = sum(win_probability)/len(win_probability)
overall_end_balance = sum(end_balance)/len(end_balance)
# Вывод средних значений
print("Average win probability after " + str(num_simulations) + "   
       runs: " + str(overall_win_probability))
print("Average ending balance after " + str(num_simulations) + " 
       runs: $" + str(overall_end_balance))

    
Моделирование игры в кости:
Моделирование игры в кости:

        Average win probability after 10000runs: 0.16666139999999954
Average ending balance after 10000runs: $833.307
    

Анализ результатов

Сделаем вывод из результатов. Из рисунка выше возможно определить, что игрок редко получает прибыль после 1000 бросков. Средний конечный баланс 10000 симуляций составляет 833,66$ (из-за рандомизации, возможны различия результатов). Казино остается в выигрыше даже, если выплачивает в четыре раза больше при победе игрока.

Также заметим, что вероятность выигрыша составляет 0.1667 или 1/6. Выше было отмечено, что у игрока 6 выигрышных исходов из 36 возможных. Используя эти 2 числа ожидаемо, что игрок выиграет 6 из 36 бросков, или 1/6 бросков, что соответствует прогнозу Монте-Карло.

***

Материалы по теме

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста»

17
Фев
2022

📈 Big O нотация: что это такое и почему ее обязательно нужно знать каждому программисту

Чем отличается структура данных от абстрактного типа данных? Что такое Big O нотация и как ее применять? Мы постарались ответить на эти вопросы в данной статье.

О структурах данных

Представьте, что вы создали очень популярное приложение, число пользователей которого быстро приближается к миллиону. Хотя пользователям нравится приложение, они жалуются, что оно работает медленно, из-за чего некоторые пользователи покидают ваш сервис.

Вы решили разобраться, в чем проблема и заметили, что основным узким местом является способ получения информации о пользователе при аутентификации. Ваше приложение ищет запрашиваемый идентификатор пользователя внутри несортированного списка словарей Python до тех пор, пока идентификатор не будет найден. Именно это создает проблему.

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

Более эффективный подход заключается в том, чтобы расположить данные о пользователях в виде двоичного дерева поиска, что позволит нам найти любой из миллиона идентификаторов значительно быстрее. Версия этой структуры данных является одним из способов индексирования записей внутри базы для быстрого поиска. Постепенный перенос информации пользователей в базу данных снижает задержку приложения.


Структуры данных, которые используют программы из примера выше, определяют, будет ли код масштабироваться по мере роста объема данных. Или придется переписывать все с нуля каждый раз, когда количество пользователей будет увеличиваться?

Выбор правильных структур данных имеет решающее значение для масштабируемого кода. От этого зависит все: быстрый поиск кратчайшего пути между локациями, постоянное обслуживание приоритетных элементов в регулярно меняющемся списке, мгновенное и безопасное подтверждение корректно введенного пароля.

***

Прежде чем приступить к изучению структур данных, необходимо понять, что это такое и как их сравнивать. Начнем с изучения различий внутри структур данных и их назначения – абстрактных типов данных. Далее расскажем про Big O нотацию – метрику для сравнения скорости операций над структурами данных и пройдемся по основным типам данных, которые хранятся внутри структуры данных.

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

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека программиста»

Структуры данных vs абстрактные типы данных

В программировании, как и в реальной жизни, существует множество способов выполнения задачи. Допустим, вы хотите выкопать яму. В вашем распоряжении есть вилы, молоток, пила и лопата. Каждый инструмент можно рассматривать как «структуру данных» в том смысле, что он является конкретным средством для решения проблемы.

Однако, если отделить задачу от способа ее выполнения, вы увидите, что данные инструменты выполняют роль «средства для копания» и являются абстрактным типом данных. То, как вы на самом деле копаете, можно назвать структурой данных. Абстрактный тип данных – это теоретическая сущность, а структура данных – это ее реализация.

Рассмотрим еще один пример. Предположим, вы хотите навестить своего друга, живущего на другом конце города. В вашем распоряжении велосипед, автомобиль и ноги. Здесь транспортное средство – это абстрактный тип данных. То, как вы передвигаетесь – это структура данных.


Это различие важно, так как существует несколько способов выполнения задачи. У каждого из них свои плюсы и минусы, которые зависят от конкретной программы. Так, для рытья ям лучше всего подходит лопата. Однако, для перемещения по городу «правильная» структура данных зависит от внешнего контекста. Например, автомобиль является самым быстрым способом, но для него нужны дороги, тогда как наши ноги медленнее, но могут использовать любые маршруты.

Структура данных – это конкретный инструмент, который мы используем для выполнения задачи. Но нашего пользователя волнует только абстрактный тип данных. Вашего друга не беспокоит, как вы доберетесь до его дома, главное, чтобы вы пришли вовремя.

Еще один пример. Представьте, что вам нужно убрать чистое белье. Структурой данных с низким временем записи и высоким временем чтения будет стопка одежды. Добавление в эту стопку происходит быстро, но извлечение конкретного предмета происходит медленнее, так как приходится искать его в несортированном белье.

Альтернативным методом может быть аккуратное размещение одежды в комоде или шкафу. Этот метод имеет высокое время записи и низкое время чтения, поскольку потребуется больше времени, чтобы разложить одежду, но вы сможете быстрее получить доступ к любому предмету, который вы искали.


Данные примеры не далеки от стратегий сброса данных в AWS S3 по сравнению с базой данных или хранения данных в высокоструктурированной базе данных SQL по сравнению с гибкой базой данных NoSQL.

Big O нотация

Логично, что лопатой легче выкопать яму, чем молотком, но как оценить разницу в производительности? Количество секунд, которые мы потратим на то, чтобы вырыть яму – это хорошая метрика. При этом для работы с ямами разного размера нам нужен расчет времени, который учитывает объем и глубину. Есть и другие факторы, которые придется учесть. Такие, как разный размер лопат и возможности людей, которые копают. Бодибилдер с молотком может выкопать яму быстрее, чем ребенок с лопатой, но это не значит, что молоток – лучший инструмент для копания.


В компьютерных терминах эти два аспекта можно представить как объем обрабатываемых данных и как используемую машину. При сравнении того, насколько хорошо структуры данных выполняют какую-либо операцию, нам нужна метрика, которая количественно определяет, как производительность зависит от объема данных. Например, хранение новых данных или получение запрошенного элемента. Это не зависит от того, какую машину мы используем.

Для этого мы можем обратиться к нотации Big O, обозначаемой как O(⋅). Big O – это мера эффективности «в худшем случае», верхняя граница того, сколько времени потребуется для выполнения задачи, или сколько памяти для этого необходимо. Например, поиск элемента в несортированном списке имеет значение O(n). Для получения результата, возможно, вам придется перебрать весь список.

Вот еще один пример операции с временной сложностью O(n). При увеличении количества элементов в списке, печать каждого элемента в Python списке занимает больше времени. Если вы удваиваете количество элементов, то удваивается и их время вывода, которое растет линейно.

        # сложность времени O(n)
def print_num(arr: list):
    for num in arr:
        print(num)
    

Если же мы выводим каждую пару элементов в массиве, то сложность становится O(n²). Массив из 4 элементов требует 16 шагов, массив из 10 элементов – 100 шагов и так далее.

        # сложность времени O(n^2)
def print_pairs(arr: list):
    for num1 in arr:
        for num2 in arr:
            print(num1, num2)
    

Алгоритм O(n²) не является идеальным. Нам нужен алгоритм, который работает в постоянном режиме. Или O(1), где время выполнения не зависит от объема данных. Например, печать случайного значения из массива всегда будет занимать одно и то же время, независимо от размера массива.

        # время O(1)
def print_idx(arr: list, i: int):
    print(arr[i])
    

Можно количественно оценить эффективность этих функций с помощью команды %%timeit в Jupyter Notebook. Ниже видно резкое увеличение времени выполнения O(n²) print_pairs. Также видно силу функции O(1) print_idx, время выполнения которой колеблется около 0.153 мс, независимо от размера массива и от того, какой элемент запрашивается, первый или последний.


Можно использовать график, подобный приведенному ниже, чтобы сравнить, как масштабируются алгоритмы с различной эффективностью. Зеленая область является идеальной – это наиболее масштабируемое время выполнения, которое растет значительно медленнее, чем объем данных. Данные в серой зоне выглядят удовлетворительно. Ситуация в оранжевой зоне нежелательна. Того, что вы видите в красной зоне, лучше избегать.


Однако, для решения каких задач может потребоваться алгоритм из красной зоны? Они необходимы для решения задач, где требуется знать все возможные ответы на вопрос. Одним из таких примеров алгоритма O(2ⁿ) является поиск всех подмножеств массива. Каждый элемент множества может быть либо включен, либо исключен из подмножества. Набор из четырех элементов [A,B,C,D] будет иметь 2⁴ или 16 подмножеств:

  1. [], [A], [B], [C], [D]
  2. [A,B], [A,C], [A,D], [B,C], [B,D], [C,D]
  3. [A,B,C], [A,B,D], [A,C,D], [B,C,D]
  4. [A,B,C,D]

Худшее время выполнения у алгоритма O(n!), который представляет из себя перестановки – классический пример n-факторной сложности. Чтобы найти все возможные варианты расположения [A, B, C, D] мы начинаем с одной из четырех букв в первой позиции, затем одну из оставшихся трех во второй позиции и так далее. Таким образом, будет 4 × 3 × 2 × 1, или 24 перестановки:

  1. [A,B,C,D], [A,B,D,C], [A,C,B,D], [A,C,D,B], [A,D,B,C], [A,D,C,B]
  2. [B,A,C,D], [B,A,D,C], [B,C,A,D], [B,C,D,A], [B,D,C,A], [B,D,A,C]
  3. [C,A,B,D], [C,A,D,B], [C,B,A,D], [C,B,D,A], [C,D,B,A], [C,D,A,B]
  4. [D,A,B,C], [D,A,C,B], [D,B,A,C], [D,B,C,A], [D,C,A,B], [D,C,B,A]

Время выполнения этих задач быстро увеличивается. Массив из 10 элементов имеет 1024 подмножества и 3 628 800 перестановок. Массив из 20 элементов имеет 1 048 576 подмножеств и 2 432 902 008 176 640 000 перестановок.

Если ваша задача состоит в том, чтобы найти все подмножества или перестановки введенного массива, сложно избежать времени выполнения O(2ⁿ) или O(n!). Однако, если вы выполняете эту операцию более одного раза, есть несколько архитектурных трюков, которые можно использовать для уменьшения нагрузки.

Типы данных

Перейдем к фундаментальным типам данных. Если структура данных – это набор данных, возникает вопрос: какие типы данных должны быть в наших структурах? Есть несколько типов данных, универсальных для всех языков программирования:

  • Целые числа (Integers), такие как 1, -5 и 256.

В других языках программирования (кроме Python) вы можете определить тип целого числа. Например, знаковое (+/-) или беззнаковое (только +), а также количество бит, которое может содержать целое число.

  • Числа с плавающей запятой (Float) – это числа с десятичными знаками. Например, 1.2, 0.14.

В Python к ним относятся числа, определенные с помощью научной нотации, такие как 1e5. В более низкоуровневых языках, например, C или Java, есть родственный тип double. Он обозначает дополнительную точность после запятой.

  • Заголовки (Chars) – это буквы a, b, c. Их набор – это строка, которая технически является массивом chars. Строковые представления чисел и символов, таких как 5 или ?, тоже являются символами.
  • Void – ноль, как None в Python. Указывает на отсутствие данных. Это помогает при инициализации массива, который будет заполняться. Например, функция, которая выполняет действие, но ничего не возвращает. Такая, как отправка электронного письма.

***

В следующей части материала мы приступим к изучению массивов и связанных списков.

Материалы по теме

21
Янв
2022

🍺📊 Какая связь между пивом и t-распределением? Рассказывает Кирилл Дубовиков из компании «Синимекс»

Что общего у пива Guinness и t-распределением вероятности? Об этом вы узнаете в нашей статье.

Автор: Кирилл Дубовиков, Директор по анализу данных и машинному обучению компании «Синимекс».

Нормальное распределение

Представим, что нам нужно исследовать рост людей в городе. Мы выходим на улицу и начинаем измерять рост случайных прохожих. (Некоторые из них могут вызвать полицию, но это же все ради науки!)

Нам нужно провести немного разведочного анализа данных как порядочным data scientist’ам. Но под рукой нет статистических инструментов, таких как язык R, поэтому мы просто берем и строим гистограмму из людей.

Когда под рукой нет статистических пакетов
Когда под рукой нет статистических пакетов

Мы видим самое важное распределение вероятности, с которым когда-либо нужно будет иметь дело — распределение Гаусса. Благодаря центральной предельной теореме, его можно обнаружить во множестве реальных процессов нашего мира. Распределение Гаусса встречается настолько часто, что его также называют нормальным распределением.

Центральная предельная теорема гласит, что среднее арифметическое достаточно большого числа случайных переменных величин имеет нормальное распределение. Сами эти величины могут изначально иметь любое распределение, но их сумма (по мере приближения количества этих величин к ) будет иметь вид нормального распределения.

Функция плотности распределения Гаусса представлена ниже:

f(x∣μ,σ)=1σ2πe−(x−μ)2/2σ2

Эта формула выглядит пугающе, но математически с ней удобно работать. Если вам интересно, как она выводится, можете почитать об этом здесь. Как видно, у этого распределения есть два параметра:

  • µ (математическое ожидание)
  • σ (стандартное отклонение).

Математическое ожидание µ определяет математическое ожидание случайной величины с нормальным распределением. Дисперсия σ² определяет меру разброса возможных значений.

Из-за вездесущего присутствия в реальных данных нормальное распределение часто используется в машинном обучении. Оно широко используется в различных алгоритмах, к примеру:

  • Подразумевается, что ошибки в линейных моделях имеют нормальное распределение.
  • Гауссовские процессы предполагают, что значения функции в рамках модели имеют нормальное распределение.
  • Смешанные гауссовские модели позволяют моделировать сложные распределения, используя несколько «простых» нормальных распределений.
  • Нормальное распределение является одним из основных компонентов в вариационных автокодировщиках.

По ссылке представлено интерактивное демо Гауссова распределения:

Рис. 1. Иллюстрация распределение Гаусса
Рис. 1. Иллюстрация распределение Гаусса

t-распределение Стьюдента

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

Уильям Госсет столкнулся с этой проблемой, оценивая качество пива Guinness. Он эмпирическим образом вывел формулу для случайной переменной, имеющей t-распределение.

Для начала, допустим у нас есть ряд значений x, …, xn, которые были получены путем выборки из нормального распределения N(µ, σ²).

Мы не знаем величину истинной дисперсии, но мы можем примерно оценить ее, рассчитав выборочное среднее и дисперсию:

x¯=1n∑i=1nxi
s2=1n−1∑i=1n(xi−x¯)2

Тогда случайная переменная

t=x¯−μS/n

будет иметь t-распределение с числом степеней свободы n-1 , где n это число элементов в выборке.

Эта формула похожа на трансформацию нормального распределения в стандартное нормальное (это условное название нормального распределения, где математическое ожидание равно 0, а дисперсия – 1):

x¯−μσ/n

Мы не знаем, чему равна истинная дисперсия для всей генеральной совокупности, поэтому мы вынуждены заменить ее на выборочное стандартное отклонение.

Это распределение лежит в основе научного метода, который называется t-тест. Он был впервые использован в компании Guinness для оценки качества их пива.

Уильям Госсет опубликовал результаты своего исследования под псевдонимом Стьюдент, так как в Guinness волновались о том, что конкуренты узнают о методике использования t-теста для контроля качества своей продукции.

Метод, обнаруженный Госсетом, впоследствии был доработан знаменитым статистиком Рональдом Фишером. Фишер считается родоначальником частотного подхода к статистике.

Пощупать t-распределение в интерактивном режиме можно по ссылке.

Рис. 2. Иллюстрация t-распределения
Рис. 2. Иллюстрация t-распределения

Как вы можете видеть, t-распределение приближается к нормальному на больших числах степеней свободы. Это происходит, потому что выборочное среднее приближается к истинному среднему по мере того, как размер выборки приближается к бесконечности. А «толстые» хвосты t-распределения компенсируют состояние неопределенности при работе с выборкой малого размера.

Логично задать вопрос: «Чему равна плотность распределения вероятностей t-распределения? Как мы можем вывести её?» Это непростая задача с точки зрения математики, но в основе её лежит достаточно понятная мысль.

Предположим, что мы хотим узнать плотность распределения вероятностей нормальной переменной X ~ N(0, σ). Но без прямой зависимости от стандартного отклонения σ.

Для того, чтобы избавиться от σ, нам нужно будет сделать ряд предположений. Давайте считать саму σ случайной переменной, и предположим, что она следует Гамма-распределению. Гамма-распределение позволяет описать одной формулой целое семейство различных распределений, из-за чего оказывается удобным инструментом в таких случаях.

Таким образом, X представляет собой смесь двух непрерывных вероятностных распределений – нормального и Гамма. После этого мы исключаем путем интегрирования σ и получаем формулу плотности распределения вероятности для t-распределения.

Если объяснение выше оказалось недостаточно подробным и показалось похожим на инструкцию по «рисованию совы», то больше доказательств вы найдете <a href="https://probabilityandstats.wordpress.com/tag/students-t-distribution/" target="_blank" rel="noopener noreferrer nofollow">здесь</a> и <a href="https://www.statlect.com/probability-distributions/student-t-distribution" target="_blank" rel="noopener noreferrer nofollow">здесь</a> ☺.
Если объяснение выше оказалось недостаточно подробным и показалось похожим на инструкцию по «рисованию совы», то больше доказательств вы найдете здесь и здесь ☺.

Заключение

Распределения Гаусса и Стьюдента относятся к важнейшим непрерывным вероятностным распределениям в статистике и машинном обучении.

T-распределение может использоваться взамен Гауссова в случае, когда дисперсия генеральной совокупности не известна, или для выборок малых размеров. Оба эти распределения тесно связаны между собой.

Спасибо, что прочитали эту статью. Надеюсь, вы открыли для себя что-то новое или освежили свои знания.

18
Янв
2022

👨‍🎨 NFT и криптопанки: пишем нейросеть для их генерации

В этой статье разберемся, что такое NFT и напишем простую нейросеть для генерации криптопанков.

Что такое NFT и криптопанки?

NFT (Non Fungible Token) – это невзаимозаменяемый, уникальный токен, которым торгуют и обмениваются на блокчейне Ethereum.

Криптопанки (CryptoPunks) – набор из 10 000 уникальных коллекционных персонажей, каждый из которых представляет собой уникальный аватар размером 24×24 пикселя в 8-битном стиле. Доказательство прав собственности хранится на блокчейне Ethereum.

Их создание началось как эксперимент, проведенный разработчиками программного обеспечения Мэттом Холлом и Джоном Аткинсоном в 2017 году. Криптопанки послужили вдохновением для стандарта ERC-721, на котором сегодня основано большинство цифровых произведений искусства и коллекционных предметов.

Это самая первая серия NFT, которая вызвала интерес у публики, и одна из наиболее активно торгуемых и «хайповых» сегодня.

Рыночная капитализация всех 10 000 CryptoPunks на текущий момент оценивается в более чем несколько миллиардов долларов США.

В этом материале мы будем использовать DCGAN (Deep Convolutional Generative Adversarial Network – Глубокая Сверточная Генеративно-Состязательная Сеть) и обучать ее на наборе данных CryptoPunks для того, чтобы попытаться сгенерировать новых «панков» на основе существующих. Вы можете скачать данные для проекта отсюда. Если вы ещё не знакомы с платформой Kaggle и тем, как ей пользоваться, рекомендуем вам ознакомиться со следующим материалом: 📊 Kaggle за 30 минут: практическое руководство для начинающих.

Почему нейросеть с таким сложным названием?

Группа GAN-нейросетей принадлежит к методам обучения без учителя, называемым генеративными моделями. Это тип моделей в машинном обучении, которые используются для более подробного описания явлений в данных, что позволяет обучить нашу модель с лучшим результатом.

Генеративные модели и GAN были одними из самых успешных разработок последних лет в области компьютерного зрения. Их можно использовать для автоматизированного изучения признаков, параметров и многих других составляющих того набора данных, над которым мы хотим провести наше исследование.

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека data scientist’а»

Загрузка данных и препроцессинг

Весь код находится в github репозитории. Ниже приведены основные моменты, необходимые для понимания нашей нейросети:

        # загрузим данные
base_dir = '/kaggle/input/cryptopunks/'
os.listdir(base_dir)
data_dir = '../input/cryptopunks/txn_history-2021-10-07.jsonl'
image_dir = "../input/cryptopunks/imgs/imgs"
image_root = "../input/cryptopunks/imgs"
df = pd.read_json(base_dir + 'txn_history-2021-10-07.jsonl', lines=True)
    

Посмотрим на первые 100 изображений, перед этим определив количество строк и столбцов:


Очистим наш датасет и оставим те столбцы, которые нам действительно нужны.

        df = df[["txn_type", "date", "eth", "punk_id", "type", "accessories"]]
    

Здесь:

eth – цена в криптовалюте Ethereum.

punk_idid криптопанка.

type – его вид (пришелец, зомби, мужчина/женщина).

accessories – особенности изображения.

Сравним цену NFT-токенов исходя из их типа («Пришелец», «Зомби» и.т.д.):


Как мы видим, наибольшую цену имеют «панки» категории Alien.

Для того чтобы наша GAN-нейросеть работала корректно, необходимо чтобы наш код имел следующую структуру:

  1. Функция для отображения картинок и загрузки данных
  2. Генератор
  3. Дискриминатор
  4. Параметры модели и функция потерь
  5. Код для старта тренировки и генерации изображений

Функции

def tensor_imshow() – функция для отображения изображений. Сюда мы прописываем общую переменную для картинок и их размерность.

def get_dataloader() – функция для загрузки данных, куда мы прописываем трансформер (созданный для изменения картинок в подходящий формат), переменную самого датасета и его загрузчика.

Структура генератора

Класс генератора создает фейковые данные с помощью обратной связи от дискриминатора (о нём ниже). Таким образом, он обучает дискриминатор обнаружению настоящих данных. Это необходимо для более точной работы модели и является неотъемлемой частью GAN. Обучение генератора требует более тесной интеграции между генератором и дискриминатором, чем обучение самого дискриминатора.

        class Generator(nn.Module):     
    def __init__() – функция инициализации размерности класса Генератор  
    def make_gen_block() – «начинка» генератора, которая преобразует случайный input в экземпляр данных
return nn.Sequential(*layers)  – возвращаем слои нейросети
    

Структура дискриминатора

Дискриминатор в GAN-нейросети является простым классификатором. Его цель – отличить реальные данные от тех данных, которые созданы генератором. Он может использовать любую архитектуру, если она соответствует типу данных, которые классифицирует дискриминатор.

        class Discriminator(nn.Module):     
    def __init__() – функция инициализации размерности класса Генератор  
    def make_disc_block() – «начинка» генератора
return nn.Sequential(*layers) – возвращаем слои нейросети
    

Дискриминатор классифицирует наши входные данные и определяет их категорию. То есть, дискриминационный класс сопоставляет образы с категорией. Его основная задача – исключительно осуществление данной корреляции.

Параметры для модели

В первую очередь нам необходимо инициализировать размерность. По мнению Ian Goodfellow, который является одним из отцов-основателей современного Deep Learning, оптимальное значение для коэффициентов mean=0, stdev=0.2.

        def weights_init_normal(m):
    
    if isinstance(m, nn.Conv2d) or isinstance(m, nn.ConvTranspose2d):
        torch.nn.init.normal_(m.weights, 0.0, 0.02)
    
    if isinstance(m, nn.BatchNorm2d):
      torch.nn.init.normal_(m.weights, 0.0, 0.02)
              torch.nn.init.constant_(m.bias, 0)
    

Функция потерь

Она используется для расчета ошибки между реальными и полученными ответами. Наша главная цель – сделать эту ошибку меньше, насколько это возможно. Таким образом, функция потерь эффективно приближает обучение нейронной сети к этой цели.

Теперь мы инициализируем критерий и параметры функции потерь, размер batch-а и лейблы:

def real_loss() – реальная потеря.

def fake_loss() – фейковая потеря. Необходима для работы генератора.

В каждой из них мы инициализируем критерий (criterion) и параметры функции потерь, размер batch-а (batch_size) и лейблы (labels).

Тренировка модели

def print_tensor_images() – функция для отображения изображений: даем тензор, получаем картинку.

def train() – функция будущей тренировки с необходимыми гиперпараметрами для генератора и дискриминатора.

И наконец, тренируем саму модель!

Вводим общепринятые числа для всех гиперпараметров.

        z_dim = 100
beta_1 = 0.5 
beta_2 = 0.999 
lr = 0.0002
n_epochs = 100
batch_size = 128
image_size = 64
    

Нам нужно максимально сбалансировать генератор и дискриминатор. Для лучшего результата добавим Adam-оптимизацию отдельно для каждого из элементов.

Инициализируем как generator, так и discriminator, после чего настроим Adam-оптимизацию с помощью g_optimizer и d_optimizer соответственно.

Начинаем тренировку! Вводим те параметры, которые указаны выше.

        n_epochs = 100
train(необходимые параметры)
    

Мы видим, что дискриминатор несколько превосходит генератор, особенно на начальном этапе, потому что его работа проще. Сбалансировать эти две модели в стандартном GAN очень сложно, но то, что мы сделали ранее, имеет значение: иначе разрыв между двумя элементами внутри модели мог быть гораздо больше.

Сохраняем предобученную модель для того, чтобы использовать её для генерации новых изображений.

        def save_model(generator,file_name):
    generator = generator.to('cuda')
    torch.save(generator.state_dict(),"cryptopunks_generator.pth")

save_model(generator, "kaggle")
    

Генерируем новых криптопанков

        generator.to(device)
generator.eval() 
sample_size=8

for i in range(8):    

    fixed_z = Generator.get_noise(n_samples=sample_size, 
                                  z_dim=z_dim, 
                                  device=device)    
    sample_image = generator(fixed_z)
    print_tensor_images(sample_image)
    

Готово! Написанная нами нейросеть теперь генерирует изображения криптопанков. Мы проделали большую работу.

***

Основная цель этой статьи – предоставить вам базовое понимание пайплайна, с помощью которого мы строим нейросеть, генерирующую различные изображения. В данном случае в качестве примера мы взяли популярную тему NFT-токенов CryptoPunks.

Пайплайн включает в себя:

  1. Обзор данных для понимания того, какая нейросеть лучше всего подойдет (в нашем случае – GAN, генеративно-состязательная)
  2. Понимание интуиции, которая стоит за выбранной нейросетью. У нас это «соревнование» генератора и дискриминатора, которые необходимо написать.
  3. Определение правильных параметров для модели, ее тренировка и сохранение.
  4. Генерация новых изображений на основе натренированной модели.

Исходя из этого, вы можете усовершенствовать описанное выше базовое решение. Например, поэкспериментировать с другими параметрами перед тренировкой, или использовать другой способ оптимизации. Может быть, даже попробовать взять другую нейросеть для достижения лучшего результата.

Бескрайнее поле Глубокого Обучения (Deep Learning) – это целое искусство, освоить которое вы сможете, комбинируя самые смелые подходы с разнообразными техниками.

Материалы по теме

25
Дек
2021

🐼 Как правильно сортировать данные в Pandas

Из этой заметки вы узнаете, как сортировать датафреймы Pandas по нескольким столбцам с помощью метода sort_values, а также по индексам методом sort_index.

Датафрейм – это двумерная структура данных, очень похожая на таблицу, которая состоит из рядов и столбцов. В Pandas мы можем сортировать фрейм данных по одному столбцу, либо по нескольким столбцам.

Мы будем работать с набором данных Kaggle, а именно со статистикой трендовых видеороликов YouTube. Скачаем и откроем файлUSvideos.csv:

        df = pd.read_csv('USvideos.csv')
df.columns
    

Датафрейм включает следующие столбцы:


Метод sort_values применяется для сортировки датафрейма и выглядит следующим образом:

        DataFrame.sort_values(by, axis=0, ascending=True, inplace=False, kind='quicksort', na_position='last', ignore_index=False, key=None)
    

Далее мы подробно разберем, за что отвечает каждый из вышеперечисленных параметров.

Сортировка по одному столбцу

Чтобы отсортировать датафрейм по одному столбцу, укажем имя столбца с помощью параметра by. В качестве примера возьмем столбец likes, который выводит количество набранных лайков.

        df.sort_values(by='likes', ascending=False)
    

Здесь:

by – определяет список столбцов для сортировки.

ascending – задает порядок сортировки.

sort_values по умолчанию сортирует по возрастанию.

Чтобы задать порядок «по убыванию», следует указать ascending=False.


Сортировка по нескольким столбцам

Чтобы отсортировать датафрейм по нескольким столбцам, методу sort_values нужно через запятую указать имена столбцов, которые мы собираемся использовать.

Давайте отсортируем датафрейм по показателям likes и dislikes, то есть найдем видео с наибольшим числом лайков и дизлайков.

В параметре ascending порядок сортировки для столбцов также указывается через запятую, что позволяет задавать разный порядок сортировки для разных столбцов в датафрейме.

        df.sort_values(['likes','dislikes'], ascending=[False, False])
    

Подробнее про параметры

Параметр kind позволяет выбрать алгоритм сортировки: quicksort (Быстрая сортировка), mergesort (Сортировка слиянием) или heapsort (Пирамидальная сортировка). По умолчанию используется алгоритм quicksort.

        df.sort_values('likes', ascending=False, kind="mergesort")
    

Inplace-сортировка (на месте) по умолчанию отключена. Для включения inplace-сортировки используем параметр inplace:

        df.sort_values('likes', ascending=False, kind="mergesort", inplace=True)
    

С помощью параметра key мы можем применить любую функцию к данным еще до операции сортировки. Вместо функции также может быть lambda-функция.

        df.sort_values(by='title', key=lambda x: x.str.lower())
    

Метод sort_index сортирует датафрейм по индексам строк. Давайте еще раз взглянем на наш датафрейм:

        sdf = df.sort_values(by='likes', ascending=False)
    

Когда мы сортируем датафрейм, используя метод sort_values, Pandas учитывает столбец, ответственный за сортировку. Чтобы отсортировать датафрейм sdf по индексу строк, воспользуемся методом sort_index:

        sdf.sort_index()
    

Чтобы отсортировать датафрейм по меткам столбцов, присвоим параметру axis значение 1:

        sdf.sort_index(axis=1)
    

***

В этой заметке мы:

  • научились сортировать датафрейм по одному и нескольким значениям;
  • узнали, как работают методы sort_values() и sort_index().

Материалы по теме

18
Дек
2021

📚 ТОП-10 вышедших в 2021 году книг по Data Science для новичков и профессионалов

Чтобы стать специалистом в области анализа данных, необходимо следить за последними новинками в отрасли. В этом материале мы собрали для вас самые интересные книги по Data Science, вышедшие в 2021 году.

09
Дек
2021

Факультет Искусственного интеллекта

Получите одну из самых востребованных IT-профессий. Машинное обучение от профессиональных преподавателей.
— Читать дальше «Факультет Искусственного интеллекта»

25
Ноя
2021

🤖 Решаем задачи машинного обучения с помощью алгоритма градиентного бустинга

Градиентный бустинг (Gradient Boosting) – один из самых эффективных инструментов для решения задач машинного обучения, в особенности на соревнованиях Kaggle. Чтобы научиться правильно его применять, разберем подробнее лежащие в основе алгоритма процессы.

Градиентный бустинг – это продвинутый алгоритм машинного обучения для решения задач классификации и регрессии. Он строит предсказание в виде ансамбля слабых предсказывающих моделей, которыми в основном являются деревья решений. Из нескольких слабых моделей в итоге мы собираем одну, но уже эффективную. Общая идея алгоритма – последовательное применение предиктора (предсказателя) таким образом, что каждая последующая модель сводит ошибку предыдущей к минимуму.

Предположим, что вы играете в гольф. Чтобы загнать мяч в лунĸу, вам необходимо замахиваться клюшкой, каждый раз исходя из предыдущего удара. То есть перед новым ударом гольфист в первую очередь смотрит на расстояние между мячом и лунĸой после предыдущего удара, так как наша основная задача – при следующем ударе уменьшить это расстояние.

Бустинг строится таким же способом. Для начала, нам нужно ввести определение “лунĸи”, а именно цели, которая является конечным результатом наших усилий. Далее необходимо понимать, куда нужно “бить ĸлюшĸой”, для попадания ближе ĸ цели. С учётом всех этих правил нам необходимо составить правильную последовательность действий, чтобы ĸаждый последующий удар соĸращал расстояние между мячом и лунĸой.

Стоит отметить, что для задач классификации и регрессии реализация алгоритма в программировании будет различаться.

Больше полезной информации вы найдете на нашем телеграм-канале «Библиотека data scientist’а».

Параметры алгоритма

  • criterion – критерий выбора расщепления, Mean Absolute Error (MAE) или Mean Squared Error (MSE). Используется только при построении деревьев.
  • init – какой алгоритм мы будем использовать в качестве главного (именно его и улучшает техника бустинга).
  • learning_rate – скорость обучения.
  • n_estimators – число итераций в бустинге. Чем больше, тем лучше качество, однако слишком большой увеличение данного параметра может привести к ухудшению производительности и переобучению.
  • min_samples_split – минимальное число объектов, при котором происходит расщепление. С данным параметром мы можем избежать переобучение.
  • min_samples_leaf – минимальное число объектов в листе (узле). При увеличении данного параметра качество модели на обучении падает, в то время как время построения модели сокращается. Меньшие значения стоит выбирать для менее сбалансированных выборок.
  • max_depth – максимальная глубина дерева. Используется для того, чтобы исключить возможность переобучения.
  • max_features – количество признаков, учитываемых алгоритмом для построения расщепления в дереве.
  • max_leaf_nodes : Максимальное число верхних точек в дереве. При наличии данного параметра max_depth будет игнорироваться.

Реализация на языке python (библиотека sklearn)

        ### Загружаем библиотеки и данные
import pandas as pd
import numpy as np
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler,LabelEncoder
from sklearn.datasets import load_breast_cancer
from sklearn.metrics import mean_squared_error,r2_score 

import warnings
warnings.filterwarnings('ignore')
breast_cancer = load_breast_cancer()


### Обозначаем целевую переменную для нашей будущей модели
X = pd.DataFrame(breast_cancer['data'], columns=breast_cancer['feature_names'])
y = pd.Categorical.from_codes(breast_cancer['target'], breast_cancer['target_names'])

lbl = LabelEncoder() 
lbl.fit(y)

y_enc = lbl.transform(y)


### Разбираемся с признаками
scl = StandardScaler()
scl.fit(X)
X_scaled = scl.transform(X)

X_train, X_test, y_train, y_test = train_test_split(X, y_enc, test_size=0.20, random_state=42)


### Прописываем параметры для нашей модели 
params = {'n_estimators':200,
          'max_depth':12,
          'criterion':'mse',
          'learning_rate':0.03,
          'min_samples_leaf':16,
          'min_samples_split':16
          }


### Тренируем
gbr = GradientBoostingRegressor(**params)
gbr.fit(X_train,y_train)


### Вычисляем точность
train_accuracy_score=gbr.score(X_train,y_train)
print(train_accuracy_score)

test_accuracy_score=gbr.score(X_test,y_test)
print(test_accuracy_score)

### Предсказание
y_pred = gbr.predict(X_test)

### И среднеквадратичную ошибку
mse = mean_squared_error(y_test,y_pred)
print("MSE: %.2f" % mse)
print(r2_score(y_test,y_pred))
    

Результат работы кода:

        0.9854271477118486
0.8728770740774442
MSE: 0.03
0.8728770740774442
    

Базовая модель градиентного бустинга с несложной простой настройкой дает нам точность более чем в 95% на задаче регрессии.

Какие библиотеки использовать?

Помимо классической для машинного обучения sklearn, для алгоритма градиентного бустинга существуют три наиболее используемые библиотеки:

XGBoost – более регуляризованная форма градиентного бустинга. Основным преимуществом данной библиотеки является производительность и эффективная оптимизация вычислений (лучший результат с меньшей затратой ресурсов).

Вы можете установить XGBoost следующим образом:

        pip install xgboost
    

Библиотека XGBoost предоставляем нам разные классы для разных задач: XGBClassifier для классификации и XGBregressor для регрессии.

Примечание
Все приведенные ниже библиотеки имеют отдельные классы для задач как классификации, так и регрессии.

  • Пример использования XGBoost для классификации:
        # xgboost для классификации
from numpy import asarray
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from xgboost import XGBClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
# определяем датасет
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# и нашу модель вместе с кросс-валидацией
model = XGBClassifier()
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Точность: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = XGBClassifier()
model.fit(X, y)
# предсказываем
row = [2.56999479, -0.13019997, 3.16075093, -4.35936352, -1.61271951, -1.39352057, -2.48924933, -1.93094078, 3.26130366, 2.05692145]
row = asarray(row).reshape((1, len(row)))
yhat = model.predict(row)
print('Предсказание (Предикт): %d' % yhat[0])
    
  • Пример использования XGBoost для регрессии:
        # xgboost для регрессии
from numpy import asarray
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from xgboost import XGBRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
# определяем датасет
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# и нашу модель (в данном примере мы меняем метрику на MAE)
model = XGBRegressor(objective='reg:squarederror')
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
print('MAE (Средняя Абсолютная Ошибка): %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = XGBRegressor(objective='reg:squarederror')
model.fit(X, y)
# предсказываем
row = [2.02220122, 0.31563495, 0.82797464, -0.30620401, 0.16003707, -1.44411381, 0.87616892, -0.50446586, 0.23009474, 0.76201118]
row = asarray(row).reshape((1, len(row)))
yhat = model.predict(row)
print('Предсказание (Предикт): %.3f' % yhat[0])

    
LightGBM – библиотека от Microsoft. В ней идет добавление авто выбора объектов и фокуса на тех частях бустинга, в которых мы имеем больший градиент. Это способствует значительному ускорению в обучении модели и улучшению показателей предсказания. Основная сфера применения – соревнования с использованием табличных данных на Kaggle.

Вы можете установить LightGBM также при помощи pip:

        pip install lightgbm
    
  • LightGBM для классификации:
        # lightgbm для классификации
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from lightgbm import LGBMClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
# определяем датасет
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# и нашу модель
model = LGBMClassifier()
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Точность: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = LGBMClassifier()
model.fit(X, y)
# предсказываем
row = [[2.56999479, -0.13019997, 3.16075093, -4.35936352, -1.61271951, -1.39352057, -2.48924933, -1.93094078, 3.26130366, 2.05692145]]
yhat = model.predict(row)
print('Предсказание (Предикт): %d' % yhat[0])
    
  • LightGBM для регрессии:
        # lightgbm для регрессии
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from lightgbm import LGBMRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
# определяем датасет
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# и нашу модель (в данном примере мы меняем метрику на MAE)
model = LGBMRegressor()
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
print('MAE (Средняя Абсолютная Ошибка): %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = LGBMRegressor()
model.fit(X, y)
# предсказываем
row = [[2.02220122, 0.31563495, 0.82797464, -0.30620401, 0.16003707, -1.44411381, 0.87616892, -0.50446586, 0.23009474, 0.76201118]]
yhat = model.predict(row)
print('Предсказание (Предикт): %.3f' % yhat[0])
    
CatBoost – это библиотека градиентного бустинга, которую создали разработчики Яндекса. Здесь используются “забывчивые” (oblivious) деревья решений, при помощи которых мы растим сбалансированное дерево. Одни и те же функции используются для создания разделений (split) на каждом уровне дерева.

Более того, главным преимуществом CatBoost (помимо улучшения скорости вычислений) является поддержка категориальных входных переменных. Из-за этого библиотека получила свое название CatBoost, от “Category Gradient Boosting” (Категориальный Градиентный Бустинг).

Вы можете установить CatBoost проверенным ранее путем:

        pip install catboost
    
  • CatBoost в задаче классификации:
        # catboost для классификации
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from catboost import CatBoostClassifier
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from matplotlib import pyplot
# определяем датасет
X, y = make_classification(n_samples=1000, n_features=10, n_informative=5, n_redundant=5, random_state=1)
# evaluate the model
model = CatBoostClassifier(verbose=0, n_estimators=100)
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
print('Точность: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = CatBoostClassifier(verbose=0, n_estimators=100)
model.fit(X, y)
# предсказываем
row = [[2.56999479, -0.13019997, 3.16075093, -4.35936352, -1.61271951, -1.39352057, -2.48924933, -1.93094078, 3.26130366, 2.05692145]]
yhat = model.predict(row)
print('Предсказание (Предикт): %d' % yhat[0])
    
  • CatBoost в задаче регрессии:
        # catboost для регрессии
from numpy import mean
from numpy import std
from sklearn.datasets import make_regression
from catboost import CatBoostRegressor
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedKFold
from matplotlib import pyplot
# определяем датасет
X, y = make_regression(n_samples=1000, n_features=10, n_informative=5, random_state=1)
# и нашу модель (в данном примере мы меняем метрику на MAE)
model = CatBoostRegressor(verbose=0, n_estimators=100)
cv = RepeatedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='neg_mean_absolute_error', cv=cv, n_jobs=-1, error_score='raise')
print('MAE (Средняя Абсолютная Ошибка): %.3f (%.3f)' % (mean(n_scores), std(n_scores)))
# тренируем модель на всём наборе данных
model = CatBoostRegressor(verbose=0, n_estimators=100)
model.fit(X, y)
# предсказываем
row = [[2.02220122, 0.31563495, 0.82797464, -0.30620401, 0.16003707, -1.44411381, 0.87616892, -0.50446586, 0.23009474, 0.76201118]]
yhat = model.predict(row)
print('Предсказание (Предикт): %.3f' % yhat[0])
    

Когда использовать?

Вы можете использовать алгоритм градиентного бустинга при следующих условиях:

  • Наличие большого количества наблюдений (ближайшее сходство) в тренировочной выборке данных.
  • Количество признаков меньше количества наблюдений в обучающих данных. Бустинг хорошо работает, когда данные содержат смесь числовых и категориальных признаков или только числовые признаки.
  • Когда необходимо рассмотреть метрики производительности модели.

Когда НЕ следует использовать XGBoost:

  • В задачах распознавания изображений и компьютерного зрения (CV – Computer Vision).
  • В обработке и понимании естественного языка (NLP – Natural Language Processing).
  • Когда число обучающих выборок значительно меньше чем число признаков (фич).

Плюсы и минусы

Плюсы

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

Минусы

  • Алгоритм крайне чувствителен к выбросам и при их наличии будет тратить огромное количество ресурсов на эти моменты. Однако, стоит отметить, что использование Mean Absolute Error (MAE) вместо Mean Squared Error (MSE) значительно снижает влияние выбросов на вашу модель (выбор функции в параметре criterion).
  • Ваша модель будет склонна к переобучению при слишком большом количестве деревьев. Данная проблема присутствует в любом алгоритме, связанном с деревьями и справляется правильной настройкой параметра n_estimators.
  • Вычисления могут занять много времени. Поэтому, если у вас большой набор данных, всегда составляйте правильный размер выборки и не забывайте правильно настроить параметр min_samples_leaf.
***

Хотя градиентный бустинг широко используется во всех областях науки о данных, от соревнований Kaggle до практических задач, многие специалисты все еще используют его как черный ящик. В этой статье мы разбили метод на более простые шаги, чтобы помочь читателям понять лежащие в основе работы алгоритма процессы. Удачи!

19
Ноя
2021

«Чёрная пятница» в GeekBrains

На выбор есть факультеты, профессии, программы и курсы по 7 направлениям: программирование, IT-инфраструктура, аналитика, дизайн, маркетинг, менеджмент и школьникам.
— Читать дальше ««Чёрная пятница» в GeekBrains»

12
Ноя
2021

🤖 Наивный байесовский алгоритм классификации: преимущества и недостатки

Наивный байесовский классификатор (Naive Bayes classifier) – это очень популярный в машинном обучении алгоритм, который в основном используется для получения базовой точности набора данных. Изучим его преимущества и недостатки, а также реализацию на языке Python.

Что это такое?

Наивный Байес – это самый простой алгоритм, который вы можете применить к своим данным. Как следует из названия, этот алгоритм делает предположение, что все переменные в наборе данных “наивные”, т.е. не коррелируют друг с другом.

Предположим, что вы видите перед собой что-то зеленое. Этот зеленый объект может быть ежиком, собакой или мячом. Естественно, вы предположите, что это будет мяч. Но почему?

Вы создаете алгоритм и вашей целью является проблема выше: классифицировать объект между мячом, ежиком и собакой. Сначала вы подумаете об определении символов объекта, а затем об их сопоставлении с объектами классификации, например, если объект – круг, то это будет мяч, если объект – колючее живое существо, то это будет ежик, а если наш объект лает, то, вероятно, это будет собака.

Причина проста: мы с детства видим зеленый шар, но собака или ежик такого цвета крайне маловероятны для нас. Таким образом, в нашем случае мы можем классифицировать объект, сопоставив его признаки с нашим классификатором по отдельности. Зеленый цвет был сопоставлен с ежом, собакой и мячом, и в итоге мы получили наибольшую вероятность принадлежности зеленого объекта к мячу. Это и есть причина, почему мы классифицировали его как мяч.

Больше полезной информации вы можете найти на нашем телеграм-канале «Библиотека data scientist’а».

Теоретическая составляющая алгоритма

Теорема Байеса позволяет рассчитать апостериорную вероятность P(A | B) на основе P(A), P(B) и P(B | A).


Где:

  • P(A | B) – апостериорная вероятность (что A из B истинно)
  • P(A) – априорная вероятность (независимая вероятность A)
  • P(B | A) – вероятность данного значения признака при данном классе. (что B из A истинно)
  • P(B) – априорная вероятность при значении нашего признака. (независимая вероятность B)

Реализация на языке python

        ### Загружаем библиотеки и данные
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from scipy.stats import norm
 
data = load_iris()
X, y, column_names = data['data'], data['target'], data['feature_names']
X = pd.DataFrame(X, columns = column_names)
 
### Разбиваем данные
from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(X, y, random_state=44)
 
means = X_train.groupby(y_train).apply(np.mean)
stds = X_train.groupby(y_train).apply(np.std)
 
### Вычисляем априорную вероятность класса
probs = X_train.groupby(y_train).apply(lambda x: len(x)) / X_train.shape[0]
 
### Вычисляем вероятность для Теоремы Байеса для каждого элемента
y_pred = []
# каждый элемент в валидационной части данных
for elem in range(X_val.shape[0]):
   p = {}
 
   # для каждого возможного класса
   for cl in np.unique(y_train):
 
       # априорная вероятность взятого ранее класса
       p[cl] = probs.iloc[cl]
 
       # для каждого столбца в датасете
       for index, param in enumerate(X_val.iloc[elem]):
 
           # умножаем вероятность того, что данное значение столбца
           # будет принадлежать распределению для выбранного класса
           p[cl] *= norm.pdf(param, means.iloc[cl, index], stds.iloc[cl, index])
  
   y_pred.append(pd.Series(p).values.argmax())
 
### Посмотрим точность нашего предсказания несколькими методами
# ручной классификатор
from sklearn.metrics import accuracy_score
accuracy1 = accuracy_score(y_val, y_pred)
 
# классификатор из библиотеки sklearn
from sklearn.naive_bayes import GaussianNB
model = GaussianNB()
model.fit(X_train, y_train)
accuracy2 = accuracy_score(y_val, model.predict(X_val))
 
print(accuracy1)
print(accuracy2)
    

Результат работы кода:

        0.9210526315789473
0.9210526315789473
    

Базовая модель с самой простой настройкой дает нам точность более чем в 90% на задаче классификации цветков ириса.

Плюсы и минусы

Плюсы

  • Алгоритм легко и быстро предсказывает класс тестового набора данных. Он также хорошо справляется с многоклассовым прогнозированием.
  • Производительность наивного байесовского классификатора лучше, чем у других простых алгоритмов, таких как логистическая регрессия. Более того, вам требуется меньше обучающих данных.
  • Он хорошо работает с категориальными признаками(по сравнению с числовыми). Для числовых признаков предполагается нормальное распределение, что может быть серьезным допущением в точности нашего алгоритма.

Минусы

  • Если переменная имеет категорию (в тестовом наборе данных), которая не наблюдалась в обучающем наборе данных, то модель присвоит 0 (нулевую) вероятность и не сможет сделать предсказание. Это часто называют нулевой частотой. Чтобы решить эту проблему, мы можем использовать технику сглаживания. Один из самых простых методов сглаживания называется оценкой Лапласа.
  • Значения спрогнозированных вероятностей, возвращенные методом predict_proba, не всегда являются достаточно точными.
  • Ограничением данного алгоритма является предположение о независимости признаков. Однако в реальных задачах полностью независимые признаки встречаются крайне редко.

В каких областях использовать?

Алгоритм наивного Байеса – это классификатор, обучение которого идет очень быстро. Следовательно, данный инструмент идеально подходит для составления прогнозов в реальном времени.

Также этот алгоритм также хорошо известен благодаря функции многоклассового прогнозирования. Мы можем предсказать вероятность нескольких классов целевой переменной.

Таким образом, идеальные области для применения наивного байесовского классификатора это:

  • Система рекомендаций. В сочетании алгоритма с методами коллаборативной фильтрации (Collaborative Filtering) мы можем создать рекомендательную систему, которая использует машинное обучение и методы добычи данных для учета невидимой информации (такой, как поиск фильмов пользователем и длительность просмотра). Цель – предсказание того, понравится ли пользователю данный ресурс/продукт или нет.
  • Фильтрация спама и классификация текста. Наивный байесовский классификатор в основном используются для классификации текстов (благодаря лучшему результату в многоклассовых проблемах и правилу независимости) и имеет более высокую точность по сравнению с другими алгоритмами. В результате он широко используется в фильтрации спама (в электронной почте) и анализе настроений (к примеру, социальных сетей, для выявления положительных и отрицательных настроений клиентов).
***

Из этого руководства вы узнали о наивном байесовском алгоритме классификации, его работе, проблемах, реализации, преимуществах и недостатках.

Параллельно вы также научились реализовывать его на языке Python. Наивный Байесовский классификатор – одих из самых простых и эффективных алгоритмов машинного обучения.

Несмотря на значительные успехи других методов за последние несколько лет, Байес все так же доказывает свою ценность. Он успешно применяется во многих приложениях, от текстовой аналитики и спам-фильтров до систем рекомендаций.

09
Ноя
2021

Хакатон WildHack

Хакатон от Wildberries с призовым фондом 500 000 рублей. Приглашают разработчиков, DataScience и ML-специалистов, аналитиков, маркетологов и дизайнеров
— Читать дальше «Хакатон WildHack»

25
Окт
2021

Хакатон AgroCode Weekend

Хакатон для веб-разработчиков, Data Science, Machine Learning и Computer Vision специалистов с призовым фондом в 2 220 000 рублей.
— Читать дальше «Хакатон AgroCode Weekend»

21
Окт
2021

🤖 Состояние дел в области синтеза речи на конец мая 2021 года

Представляем вашему вниманию большой обзор научных публикаций о синтезе речи, вышедших до конца мая 2021 года. Если вы хотите иметь представление о состоянии дел в этой области, постарайтесь его не пропустить.

28
Сен
2021

📊 Kaggle за 30 минут: разбираемся с соревнованием House Prices

Из предыдущей статьи мы узнали, что такое Kaggle и какие разделы предлагает этот ресурс. Теперь разберемся с одним из самых базовых соревнований Kaggle – House Prices.

Для начала необходимо ознакомиться с целью соревнования, правилами и данными. Также стоит вспомнить основы работы с Kaggle из первой статьи.

Перед нами стоит задача предсказания стоимости дома на основе множества признаков (фич), вроде расположения, площади, количества комнат, наличия гаража и т.д.

Это состязание по решению задачи регрессии, исходя из чего мы и будем действовать.

Данные состоят из четырех файлов:

  • train.csv – обучающая (тренировочная) выборка.
  • test.csv – тестовые данные, на основе которых мы будем делать предсказания.
  • data_description.txt – полное описание каждого столбца.
  • sample_submission.csv – пример того, как должен выглядеть наш ответ (сабмит).

Весь код воспроизводится в ячейках jupyter notebook.

Для начала, загружаем тестовую и тренировочную выборки.

        import numpy as np
import pandas as pd

df_train = pd.read_csv('../input/train.csv')
df_test  = pd.read_csv('../input/test.csv')

# Просматриваем данные
train_df.head()
    

Определим размеры датасета. Для анализа будем использовать тренировочную часть.

        train_df.shape
    
Получаем (1460, 81), а именно 81 столбец и 1460 строк.
Получаем (1460, 81), а именно 81 столбец и 1460 строк.

Обзор данных – целевая переменная

Первое, что мы должны сделать – посмотреть на нашу целевую переменную SalePrice.

        train_df['SalePrice'].describe()
    

Создается впечатление, что цена дома существенно отклоняется от нормального распределения:

  • Стандартное отклонение слишком велико.
  • Минимум больше 0 (что логично для цен на недвижимость).
  • Существует большая разница между минимальным значением и 25-м процентилем.
  • Разница между 75-м процентилем и максимумом больше, чем 25-й процентиль и максимум.

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

        # Импортируем необходимые библиотеки для визуализации
import matplotlib.pyplot as plt
import seaborn as sns

# гистограмма
f, ax = plt.subplots(figsize=(8, 6))
sns.distplot(train_df['SalePrice'])
    

Как мы и полагали, распределение далеко от идеального. Проведем больше наблюдений:

        # Рассчитываем асимметрию и эксцесс
print("Ассиметрия: %f" % train_df['SalePrice'].skew())
print("Эксцесс: %f" % train_df['SalePrice'].kurt())
    
  • Ассиметрия: 1.882876.
  • Эксцесс: 6.536282.

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

        from scipy import stats 

fig = plt.figure(figsize = (14,8))

# Распределение на необработанных данных
fig.add_subplot(1,2,1)
res = stats.probplot(train_df['SalePrice'], plot=plt)

# Распределение при условии, что мы прологарифмировали 'SalePrice'
fig.add_subplot(1,2,2)
res = stats.probplot(np.log1p(train_df['SalePrice']), plot=plt)
    

Этот метод построения признаков исправил ситуацию. Теперь наша задача – совершить логарифмирование не просто испытательным путем на графике, а применить данный метод ко всей тренировочной выборке:

        train_df['SalePrice'] = np.log1p(train_df['SalePrice'])
    

Обзор данных – корреляция

Теперь посмотрим, с какими признаками коррелирует целевая переменная SalePrice:

        # Матрица корреляции
corrmat = train_df.corr()
f, ax = plt.subplots(figsize=(12, 9))
sns.heatmap(corrmat, vmax=.8, square=True);
    
На таком графике непросто отобрать нужные нам “фичи”.
На таком графике непросто отобрать нужные нам “фичи”.

Попробуем усеченный вариант и сократим количество коррелирующих признаков до 10:

        k = 10 # количество коррелирующих признаков, которое мы хотим увидеть
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
cm = np.corrcoef(train_df[cols].values.T)
sns.set(font_scale=1.25)
hm = sns.heatmap(cm, cbar=True, annot=True, square=True, 
                 fmt='.2f', annot_kws={'size': 10}, 
                 yticklabels=cols.values, xticklabels=cols.values)
plt.show()
    

Теперь мы видим, что лучше всего SalePrice коррелирует с GrLivArea и OverallQual. Проверим эти два признака на наличие выбросов:

        fig, ax = plt.subplots()
ax.scatter(x = train_df['GrLivArea'], y = train_df['SalePrice'])
plt.ylabel('SalePrice', fontsize=13)
plt.xlabel('GrLivArea', fontsize=13)
plt.show()
    

        fig, ax = plt.subplots()
ax.scatter(x = train_df['OverallQual'], y = train_df['SalePrice'])
plt.ylabel('SalePrice', fontsize=13)
plt.xlabel('OverallQual', fontsize=13)
plt.show()
    

Выбросы незначительны. Однако если мы удалим несколько самых выделяющихся значений, то результат модели улучшится.

        # Ликвидируем 
# Только эти 2 удаления помогут нам улучшить наш показатель на таблице лидеров
train_df = train_df.drop(train[(train['OverallQual'] > 9) & (train['SalePrice'] < 220000)].index)
train_df = train_df.drop(train[(train['GrLivArea'] > 4000) & (train['SalePrice'] < 300000)].index)
    

Очистка данных и отбор признаков

Далее стоит провести исследование данных на наличие пропущенных данных и других моментов, которые могут испортить score (а значит и нашу позицию в таблице лидеров соревнования).

Эта строчка кода выведет топ-20 пропущенных значений:

        # Пропущенные значения
train_df.isnull().sum().sort_values(ascending=False).head(20)
    

На диаграмме масштаб пропущенных значений будет виден лучше:

        # Визуализируем
total = train_df.isnull().sum().sort_values(ascending=False)
percent = (train_df.isnull().sum() / train_df.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])

# Гистограмма
percent_data = percent.head(20)
percent_data.plot(kind="bar", figsize = (8,6), fontsize = 10)
plt.xlabel("Столбцы", fontsize = 20)
plt.ylabel("Count", fontsize = 20)
plt.title("Общее количество недостающих значений  (%)", fontsize = 20)
    

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

Исправим проблему на объединенных данных.

        # Удаляем строки, где целевое значение (target) пропущено
Target = 'SalePrice'
train_df.dropna(axis=0, subset=[Target], inplace=True)

# Соединяем тренировочный и тестовый датасеты, чтобы провести наши преобразования на всех данных
all_data = pd.concat([train_df.iloc[:,:-1], test_df],axis=0)

print('У тренировочного датасета {} рядов и {} признаков'.format(train_df.shape[0], train_df.shape[1]))
print('У тестового датасета {} рядов и {} признаков'.format(test_df.shape[0], test_df.shape[1]))
print('Объединённый датасет содержит в себе {} рядов и {} признаков'.format(all_data.shape[0], all_data.shape[1]))
    
        # Удаляем бесполезный столбец
all_data = all_data.drop(columns=['Id'], axis=1)
    

Теперь мы можем полноценно разобраться с пропущенными данными.

        # Функция для просмотра пропущенных данных
# При желании вместо 'train_df' вы можете забить 'all_data'

def missingValuesInfo(df):
    total = df.isnull().sum().sort_values(ascending = False)
    percent = round(df.isnull().sum().sort_values(ascending = False) / len(df)*100, 2)
    temp = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
    return temp.loc[(temp['Total'] > 0)]

missingValuesInfo(train_df)
    
        # Разбираемся с пропущенными данными
# Числовые значения отбираем через принадлежность к формату ['int64', 'float64']
# Категориальные значения отбираем через принадлежность к формату ["object"]

def HandleMissingValues(df):
    num_cols = [cname for cname in df.columns if df[cname].dtype in ['int64', 'float64']]
    cat_cols = [cname for cname in df.columns if df[cname].dtype == "object"]
    values = {}
    for a in cat_cols:
        values[a] = 'UNKNOWN'

    for a in num_cols:
        values[a] = df[a].median()
        
    df.fillna(value=values, inplace=True)
    
    
HandleMissingValues(all_data)
all_data.head()
    
        # Проверим
all_data.isnull().sum().sum()
    

Результат – 0.

Отлично, мы справились с основной проблемой. Не стоит также забывать о категориальных признаках.

        # Разбираемся с категориальными признаками

def getObjectColumnsList(df):
    return [cname for cname in df.columns if df[cname].dtype == "object"]

def PerformOneHotEncoding(df, columnsToEncode):
    return pd.get_dummies(df, columns=columnsToEncode)

cat_cols = getObjectColumnsList(all_data)
all_data = PerformOneHotEncoding(all_data, cat_cols)
all_data.head()
    

Наша задача по базовой очистке данных и отбору признаков решена. Теперь мы можем снова разбить данные на тренировочный и тестовый датасеты. Это необходимо, так как предсказывать поведение будущей модели мы будем на тестовой выборке.

        train_data = all_data.iloc[:1460, :]
test_data = all_data.iloc[1460:, :]
print(train_df.shape)
print(test_df.shape)
    

Моделирование

Так как в соревновании House Prices перед участниками стоит задача регрессии, использовать мы будем соответствующие модели.

Ridge regression

        from sklearn.linear_model import RidgeCV

ridge_cv = RidgeCV(alphas = (0.01, 0.05, 0.1, 0.3, 1, 3, 5, 10))
ridge_cv.fit(X, y)
ridge_cv_preds = ridge_cv.predict(test_data)
    

И также XGBRegressor

        import xgboost as xgb

model_xgb = xgb.XGBRegressor(n_estimators=340, max_depth=2, learning_rate=0.2)
model_xgb.fit(X, y)
xgb_preds = model_xgb.predict(test_data)
    

Возьмем усредненное значение от обеих моделей:

        predictions = (ridge_cv_preds + xgb_preds) / 2

    

Создадим датафрейм, чтобы выложить наше решение.

        submission = {
    'Id': test_df.Id.values,
    'SalePrice': predictions
}
solution = pd.DataFrame(submission)
solution.to_csv('submission.csv',index=False)
    

Заключение

Цель этой статьи – предоставить вам базовое понимание “пайплайна”, который необходим для успешного покорения Kaggle. Сюда входят:

  • Загрузка данных, их тщательное изучение и последующая очистка.
  • Отбор признаков, при необходимости – создание новых.
  • Выбор правильной модели (в продвинутых случаях – ансамбль нескольких моделей), подбор приемлемых параметров.
  • Предсказание и успешный сабмит.
Исходя из этого, вы можете усовершенствовать описанное выше базовое решение. Например, разобраться с пропущенными данными по отдельности для каждого признака, а не циклом, создать новые “фичи” на основе имеющихся, или же найти параметры, которые увеличат score модели в таблице лидеров.

Поиск лучшего решения на соревновании Kaggle – это целое искусство, освоить которое вы сможете, комбинируя самые разнообразные техники с нестандартными методами.

***

Если вы только начинаете путь в профессию и еще не определились со специализацией, подумайте о применении методов науки о данных в медицинской отрасли: сейчас это одно из самых перспективных направлений. Образовательная онлайн-платформа GeekBrains проводит набор на факультет Data Science в медицине, на котором студенты научатся с нуля решать задачи в области медицины. Обучение длится 18 месяцев, плюс 6 месяцев занимает практика по медицинской специализации. По итогам получите 15 проектов в портфолио и гарантию трудоустройства.

28
Сен
2021

📊 Kaggle за 30 минут: разбираемся с соревнованием House Prices

Из предыдущей статьи мы узнали, что такое Kaggle и какие разделы предлагает этот ресурс. Теперь разберемся с одним из самых базовых соревнований Kaggle – House Prices.

Для начала необходимо ознакомиться с целью соревнования, правилами и данными. Также стоит вспомнить основы работы с Kaggle из первой статьи.

Перед нами стоит задача предсказания стоимости дома на основе множества признаков (фич), вроде расположения, площади, количества комнат, наличия гаража и т.д.

Это состязание по решению задачи регрессии, исходя из чего мы и будем действовать.

Данные состоят из четырех файлов:

  • train.csv – обучающая (тренировочная) выборка.
  • test.csv – тестовые данные, на основе которых мы будем делать предсказания.
  • data_description.txt – полное описание каждого столбца.
  • sample_submission.csv – пример того, как должен выглядеть наш ответ (сабмит).

Весь код воспроизводится в ячейках jupyter notebook.

Для начала, загружаем тестовую и тренировочную выборки.

        import numpy as np
import pandas as pd

df_train = pd.read_csv('../input/train.csv')
df_test  = pd.read_csv('../input/test.csv')

# Просматриваем данные
train_df.head()
    

Определим размеры датасета. Для анализа будем использовать тренировочную часть.

        train_df.shape
    
Получаем (1460, 81), а именно 81 столбец и 1460 строк.
Получаем (1460, 81), а именно 81 столбец и 1460 строк.

Обзор данных – целевая переменная

Первое, что мы должны сделать – посмотреть на нашу целевую переменную SalePrice.

        train_df['SalePrice'].describe()
    

Создается впечатление, что цена дома существенно отклоняется от нормального распределения:

  • Стандартное отклонение слишком велико.
  • Минимум больше 0 (что логично для цен на недвижимость).
  • Существует большая разница между минимальным значением и 25-м процентилем.
  • Разница между 75-м процентилем и максимумом больше, чем 25-й процентиль и максимум.

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

        # Импортируем необходимые библиотеки для визуализации
import matplotlib.pyplot as plt
import seaborn as sns

# гистограмма
f, ax = plt.subplots(figsize=(8, 6))
sns.distplot(train_df['SalePrice'])
    

Как мы и полагали, распределение далеко от идеального. Проведем больше наблюдений:

        # Рассчитываем асимметрию и эксцесс
print("Ассиметрия: %f" % train_df['SalePrice'].skew())
print("Эксцесс: %f" % train_df['SalePrice'].kurt())
    
  • Ассиметрия: 1.882876.
  • Эксцесс: 6.536282.

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

        from scipy import stats 

fig = plt.figure(figsize = (14,8))

# Распределение на необработанных данных
fig.add_subplot(1,2,1)
res = stats.probplot(train_df['SalePrice'], plot=plt)

# Распределение при условии, что мы прологарифмировали 'SalePrice'
fig.add_subplot(1,2,2)
res = stats.probplot(np.log1p(train_df['SalePrice']), plot=plt)
    

Этот метод построения признаков исправил ситуацию. Теперь наша задача – совершить логарифмирование не просто испытательным путем на графике, а применить данный метод ко всей тренировочной выборке:

        train_df['SalePrice'] = np.log1p(train_df['SalePrice'])
    

Обзор данных – корреляция

Теперь посмотрим, с какими признаками коррелирует целевая переменная SalePrice:

        # Матрица корреляции
corrmat = train_df.corr()
f, ax = plt.subplots(figsize=(12, 9))
sns.heatmap(corrmat, vmax=.8, square=True);
    
На таком графике непросто отобрать нужные нам “фичи”.
На таком графике непросто отобрать нужные нам “фичи”.

Попробуем усеченный вариант и сократим количество коррелирующих признаков до 10:

        k = 10 # количество коррелирующих признаков, которое мы хотим увидеть
cols = corrmat.nlargest(k, 'SalePrice')['SalePrice'].index
cm = np.corrcoef(train_df[cols].values.T)
sns.set(font_scale=1.25)
hm = sns.heatmap(cm, cbar=True, annot=True, square=True, 
                 fmt='.2f', annot_kws={'size': 10}, 
                 yticklabels=cols.values, xticklabels=cols.values)
plt.show()
    

Теперь мы видим, что лучше всего SalePrice коррелирует с GrLivArea и OverallQual. Проверим эти два признака на наличие выбросов:

        fig, ax = plt.subplots()
ax.scatter(x = train_df['GrLivArea'], y = train_df['SalePrice'])
plt.ylabel('SalePrice', fontsize=13)
plt.xlabel('GrLivArea', fontsize=13)
plt.show()
    

        fig, ax = plt.subplots()
ax.scatter(x = train_df['OverallQual'], y = train_df['SalePrice'])
plt.ylabel('SalePrice', fontsize=13)
plt.xlabel('OverallQual', fontsize=13)
plt.show()
    

Выбросы незначительны. Однако если мы удалим несколько самых выделяющихся значений, то результат модели улучшится.

        # Ликвидируем 
# Только эти 2 удаления помогут нам улучшить наш показатель на таблице лидеров
train_df = train_df.drop(train[(train['OverallQual'] > 9) & (train['SalePrice'] < 220000)].index)
train_df = train_df.drop(train[(train['GrLivArea'] > 4000) & (train['SalePrice'] < 300000)].index)
    

Очистка данных и отбор признаков

Далее стоит провести исследование данных на наличие пропущенных данных и других моментов, которые могут испортить score (а значит и нашу позицию в таблице лидеров соревнования).

Эта строчка кода выведет топ-20 пропущенных значений:

        # Пропущенные значения
train_df.isnull().sum().sort_values(ascending=False).head(20)
    

На диаграмме масштаб пропущенных значений будет виден лучше:

        # Визуализируем
total = train_df.isnull().sum().sort_values(ascending=False)
percent = (train_df.isnull().sum() / train_df.isnull().count()).sort_values(ascending=False)
missing_data = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])

# Гистограмма
percent_data = percent.head(20)
percent_data.plot(kind="bar", figsize = (8,6), fontsize = 10)
plt.xlabel("Столбцы", fontsize = 20)
plt.ylabel("Count", fontsize = 20)
plt.title("Общее количество недостающих значений  (%)", fontsize = 20)
    

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

Исправим проблему на объединенных данных.

        # Удаляем строки, где целевое значение (target) пропущено
Target = 'SalePrice'
train_df.dropna(axis=0, subset=[Target], inplace=True)

# Соединяем тренировочный и тестовый датасеты, чтобы провести наши преобразования на всех данных
all_data = pd.concat([train_df.iloc[:,:-1], test_df],axis=0)

print('У тренировочного датасета {} рядов и {} признаков'.format(train_df.shape[0], train_df.shape[1]))
print('У тестового датасета {} рядов и {} признаков'.format(test_df.shape[0], test_df.shape[1]))
print('Объединённый датасет содержит в себе {} рядов и {} признаков'.format(all_data.shape[0], all_data.shape[1]))
    
        # Удаляем бесполезный столбец
all_data = all_data.drop(columns=['Id'], axis=1)
    

Теперь мы можем полноценно разобраться с пропущенными данными.

        # Функция для просмотра пропущенных данных
# При желании вместо 'train_df' вы можете забить 'all_data'

def missingValuesInfo(df):
    total = df.isnull().sum().sort_values(ascending = False)
    percent = round(df.isnull().sum().sort_values(ascending = False) / len(df)*100, 2)
    temp = pd.concat([total, percent], axis=1, keys=['Total', 'Percent'])
    return temp.loc[(temp['Total'] > 0)]

missingValuesInfo(train_df)
    
        # Разбираемся с пропущенными данными
# Числовые значения отбираем через принадлежность к формату ['int64', 'float64']
# Категориальные значения отбираем через принадлежность к формату ["object"]

def HandleMissingValues(df):
    num_cols = [cname for cname in df.columns if df[cname].dtype in ['int64', 'float64']]
    cat_cols = [cname for cname in df.columns if df[cname].dtype == "object"]
    values = {}
    for a in cat_cols:
        values[a] = 'UNKNOWN'

    for a in num_cols:
        values[a] = df[a].median()
        
    df.fillna(value=values, inplace=True)
    
    
HandleMissingValues(all_data)
all_data.head()
    
        # Проверим
all_data.isnull().sum().sum()
    

Результат – 0.

Отлично, мы справились с основной проблемой. Не стоит также забывать о категориальных признаках.

        # Разбираемся с категориальными признаками

def getObjectColumnsList(df):
    return [cname for cname in df.columns if df[cname].dtype == "object"]

def PerformOneHotEncoding(df, columnsToEncode):
    return pd.get_dummies(df, columns=columnsToEncode)

cat_cols = getObjectColumnsList(all_data)
all_data = PerformOneHotEncoding(all_data, cat_cols)
all_data.head()
    

Наша задача по базовой очистке данных и отбору признаков решена. Теперь мы можем снова разбить данные на тренировочный и тестовый датасеты. Это необходимо, так как предсказывать поведение будущей модели мы будем на тестовой выборке.

        train_data = all_data.iloc[:1460, :]
test_data = all_data.iloc[1460:, :]
print(train_df.shape)
print(test_df.shape)
    

Моделирование

Так как в соревновании House Prices перед участниками стоит задача регрессии, использовать мы будем соответствующие модели.

Ridge regression

        from sklearn.linear_model import RidgeCV

ridge_cv = RidgeCV(alphas = (0.01, 0.05, 0.1, 0.3, 1, 3, 5, 10))
ridge_cv.fit(X, y)
ridge_cv_preds = ridge_cv.predict(test_data)
    

И также XGBRegressor

        import xgboost as xgb

model_xgb = xgb.XGBRegressor(n_estimators=340, max_depth=2, learning_rate=0.2)
model_xgb.fit(X, y)
xgb_preds = model_xgb.predict(test_data)
    

Возьмем усредненное значение от обеих моделей:

        predictions = (ridge_cv_preds + xgb_preds) / 2

    

Создадим датафрейм, чтобы выложить наше решение.

        submission = {
    'Id': test_df.Id.values,
    'SalePrice': predictions
}
solution = pd.DataFrame(submission)
solution.to_csv('submission.csv',index=False)
    

Заключение

Цель этой статьи – предоставить вам базовое понимание “пайплайна”, который необходим для успешного покорения Kaggle. Сюда входят:

  • Загрузка данных, их тщательное изучение и последующая очистка.
  • Отбор признаков, при необходимости – создание новых.
  • Выбор правильной модели (в продвинутых случаях – ансамбль нескольких моделей), подбор приемлемых параметров.
  • Предсказание и успешный сабмит.
Исходя из этого, вы можете усовершенствовать описанное выше базовое решение. Например, разобраться с пропущенными данными по отдельности для каждого признака, а не циклом, создать новые “фичи” на основе имеющихся, или же найти параметры, которые увеличат score модели в таблице лидеров.

Поиск лучшего решения на соревновании Kaggle – это целое искусство, освоить которое вы сможете, комбинируя самые разнообразные техники с нестандартными методами.

***

Если вы только начинаете путь в профессию и еще не определились со специализацией, подумайте о применении методов науки о данных в медицинской отрасли: сейчас это одно из самых перспективных направлений. Образовательная онлайн-платформа GeekBrains проводит набор на факультет Data Science в медицине, на котором студенты научатся с нуля решать задачи в области медицины. Обучение длится 18 месяцев, плюс 6 месяцев занимает практика по медицинской специализации. По итогам получите 15 проектов в портфолио и гарантию трудоустройства.

25
Сен
2021

📊 Построение и отбор признаков. Часть 2: feature selection

Мы уже знаем, что такое признаки и почему они важны в моделях машинного обучения. Попробуем разобраться со следующей после построения “фич” техникой – их отбором.

Что такое отбор признаков?

В первой статье мы разобрались с построением признаков. В нашей таблице есть свежие сгенерированные “фичи”, а также некоторые исходные данные. Теперь важным моментом является то, какие из них использовать, так как существует бесконечное число возможных преобразований.

«Прогонка» всех признаков в модели, чтобы посмотреть, какие из них работают – плохая идея. На самом деле алгоритмы работают плохо, когда в них попадает слишком много “фич”. Как решить эту проблему? При помощи отбора признаков.

Отбор признаков (feature selection) – это оценка важности того или иного признака с помощью алгоритмов машинного обучения и отсечение ненужных.

Существует масса алгоритмов, которые преобразуют набор со слишком большим количеством признаков в управляемое подмножество. Как и в случае с построением признаков, для разных типов данных оптимальны разные способы. Более того, при выборе алгоритма необходимо учитывать наши цели, что мы хотим сделать с обрабатываемым датасетом.

Выбор наиболее оптимальных признаков из множества существующих – непростая задача. Большое их количество значительно увеличивает время вычислений, к тому же, появляется угроза переобучения.

Для решения проблемы существует несколько общих методов, которые относятся к одной из следующих категорий.

1. Методы фильтрации (filter methods)

Выбирают внутренние свойства признаков – они быстрее и менее затратны с точки зрения вычислений, чем методы-оболочки. При работе с данными большой размерности в вычислительном отношении дешевле использовать методы фильтрации.

Сбор информации (Information Gain, IG)

Вычисляет уменьшение энтропии в результате преобразования набора данных. Его можно использовать для отбора признаков путем оценки информационного прироста каждой переменной в контексте целевой переменной.

        import pandas as pd
import numpy as np
from sklearn.feature_selection import mutual_info_classif
import matplotlib.pyplot as plt

importances = mutual_info_classif(X, y)
# Где data - ваш датасет; X, y – входные и выходные данные соответственно
feature_importances = pd.Series(importances, data.columns[0:len(data.columns)-1])
feature_importances.plot(kind='barh', color='teal')
plt.show()
    

Критерий хи-квадрат (Chi-square Test)

Используется для категориальных признаков в датасете. Мы вычисляем хи-квадрат между каждым признаком и целью, после выбираем желаемое количество “фич” с лучшими показателями. Чтобы правильно применить критерий для проверки связи между различными функциями в наборе данных и целевой переменной, должны быть выполнены следующие условия: категориальные переменные, которые выбираются независимо, и частота значений > 5.

        import pandas as pd
import numpy as np
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import chi2

# Преобразование в категориальные данные путем преобразования в целые числа.
# Где X, y - входные и выходные данные соответственно.
X_categorical = X.astype(int)

# Выбираем 3 признака с наивысшим "хи-квадрат".
chi2_features = SelectKBest(chi2, k = 3)
X_kbest_features = chi2_features.fit_transform(X_categorical, y)

# Вывод "до и после"
print("Количество признаков до преобразования:", X_categorical.shape[1])
print("Количество признаков после преобразования:", X_kbest_features.shape[1])
    

Критерий Фишера (F-тест)

Критерий Фишера – один из наиболее широко используемых методов контролируемого выбора признаков. Алгоритм, который мы будем использовать, возвращает ранги переменных на основе оценки критерия в порядке убывания, после чего уже следует их отбор.

        import pandas as pd
import numpy as np
from skfeature.function.similarity_based import fisher_score
import matplotlib.pyplot as plt

# Вычисляем критерий
# Где X, y - входные и выходные данные соответственно.
ranks = fisher_score.fisher_score(X, y)

# Делаем график наших "фич"
# Где data - ваш датасет
feature_importances = pd.Series(ranks, data.columns[0:len(data.columns)-1])
feature_importances.plot(kind='barh', color='teal')
plt.show()
    

Коэффициент корреляции

Корреляция – это мера линейной связи двух или более переменных. При её помощи мы можем предсказать одну переменную через другую. Логика использования этого метода для выбора характеристик заключается в том, что “хорошие” переменные сильно коррелируют с нашей целью.

Стоит отметить, что переменные должны коррелировать с целевым показателем, но не должны между собой. В примере ниже мы будем использовать корреляцию Пирсона.

        import seaborn as sns
import matplotlib.pyplot as plt

# Матрица корреляции
# Где data - ваш датасет
correlation_matrix = data.corr()

# Выводим признаки на тепловую карту
plt.figure(figsize= (10, 6))
sns.heatmap(correlation_matrix, annot = True)
    

Абсолютное отклонение (Mean Absolute Difference, MAD)

Эта техника позволяет нам вычислить абсолютное отклонение от среднего.

        import pandas as pd
import numpy as np
import matplotlib as plt
# Вычисляем MAD
# Где X - входные данные
mean_absolute_difference = np.sum(np.abs(X - np.mean(X, axis = 0)), axis = 0) / X.shape[0]

# Наш график признаков
plt.bar(np.arange(X.shape[1]), mean_absolute_difference, color = 'teal')
    

2. Методы обертки (wrapper methods)

Особенность этих методов – поиск всех возможных подмножеств признаков и оценка их качества путем “прогонки” через модель.

Процесс выбора функции основан на конкретном алгоритме машинного обучения, который мы используем. Он следует подходу жадного поиска, оценивая все возможные комбинации функций по определенному критерию. Методы оболочки обычно обеспечивают лучшую точность прогнозирования чем методы фильтрации.

Прямой отбор признаков

Это крайне прямолинейный метод, в котором мы начинаем с наиболее эффективной переменной по отношению к цели. Затем мы выбираем другую переменную, которая дает лучшую производительность в сочетании с первой. Этот процесс продолжается до тех пор, пока не будет достигнут заданный критерий.

        from sklearn.linear_model import LogisticRegression
from mlxtend.feature_selection import SequentialFeatureSelector
 
lr = LogisticRegression(class_weight = 'balanced', solver = 'lbfgs', random_state=42, n_jobs=-1, max_iter=50e)
ffs = SequentialFeatureSelector(lr, k_features='best', forward = True, n_jobs=-1)
 
ffs.fit(X, Y)
# X, y – входные и выходные данные соответственно.
# X_train – входные данные с обучающейся выборки,
# y_pred – выходные данные предиктора
features = list(ffs.k_feature_names_)
features = list(map(int, features))
y_pred = lr.predict(X_train[features])
    

Последовательный отбор признаков

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

        from sklearn.linear_model import LogisticRegression
from mlxtend.feature_selection import SequentialFeatureSelector

lr = LogisticRegression(class_weight = 'balanced', solver = 'lbfgs', random_state=42, n_jobs=-1, max_iter=50e)
lr.fit(X, y)

bfs = SequentialFeatureSelector(lr, k_features='best', forward = False, n_jobs=-1)
bfs.fit(X, y)
features = list(bfs.k_feature_names_)
features = list(map(int, features))
lr.fit(X_train[features], y_train)
y_pred = lr.predict(x_train[features])
    

Исчерпывающий выбор признаков

Это самый надежный метод выбора функций из всех существующих. Его суть – оценка каждого подмножества функций методом перебора. Это означает, что метод пропускает все возможные комбинации переменных через алгоритм и возвращает наиболее эффективное подмножество.

        from mlxtend.feature_selection import ExhaustiveFeatureSelector
from sklearn.ensemble import RandomForestClassifier

# создаем ExhaustiveFeatureSeLlector объект.
efs = ExhaustiveFeatureSelector(RandomForestClassifier(),
        min_features=4,
        max_features=8,
        scoring='roc_auc',
        cv=2)

efs = efs.fit(X, Y)

# выводим выбранные признаки
selected_features = X_train.columns[list(efs.best_idx_)]
print(selected_features)

# выводим финальную оценку прогнозирования.
print(efs.best_score_)
    

Рекурсивное исключение признаков

Сначала модель обучается на начальной выборке признаков, и важность каждой функции определяется либо с помощью атрибута coef_ или feature_importances_. Затем наименее важные “фичи” удаляются из текущего набора. Процедура рекурсивно повторяется для сокращенного набора до тех пор, пока в конечном итоге не будет достигнуто желаемое количество признаков для выбора.

        from sklearn.linear_model import LogisticRegression
from sklearn.feature_selection import RFE

lr = LogisticRegression(class_weight = 'balanced', solver = 'lbfgs', random_state=42, n_jobs=-1, max_iter=50e)

rfe = RFE(lr, n_features_to_select=7)
rfe.fit(X_train, y_train)
# X_train, y_train - входные и выходные данные с обучающей выборки соответственно.
y_pred = rfe.predict(X_train)
    

3. Встроенные методы (embedded methods)

Эти методы включают в себя преимущества первых двух, а также уменьшают вычислительные затраты. Отличительной особенностью встроенных методов является извлечение “фич” на этапе конкретной итерации.

Регуляризация LASSO (L1)

Регуляризация состоит в добавлении штрафа (penalty) к различным параметрам модели во избежание чрезмерной подгонки. При регуляризации линейной модели штраф применяется к коэффициентам, умножающим каждый из предикторов. Lasso-регуляризация обладает свойством, позволяющим уменьшить некоторые коэффициенты до нуля. Следовательно, такие “фичи” можно будет просто удалить из модели.

        from sklearn.linear_model import LogisticRegression
from sklearn.feature_selection import SelectFromModel

# Устанавливаем наш параметр регуляризации C=1
logistic = LogisticRegression(C=1, penalty="l1", solver='liblinear', random_state=7).fit(X, y)
# Где X, y - входные и выходные данные соответственно.
model = SelectFromModel(logistic, prefit=True)

X_new = model.transform(X)

# Выбираем нужные нам столбцы из датасета без нулевых данных
# Где “selected_features” - предварительно выбранные нами признаки (см. по предыдущим методам)
selected_columns = selected_features.columns[selected_features.var() != 0]
print(selected_columns)

    

Метод с использованием Случайного Леса (Random Forest Importance)

Стратегии на основе дерева, используемые случайными лесами, естественным образом ранжируются по тому, насколько хорошо они улучшают чистоту модели в плане данных. Таким образом, “обрезая” деревья ниже определенного коэффициента, мы можем подобрать наиболее важные признаки.

        import numpy as np
import pandas as pd
from sklearn.ensemble import RandomForestClassifier

# создаем случайное дерево с вашими гипер параметрами
model = RandomForestClassifier(n_estimators=340)

# Обучаем модель на вашей выборке; Где X, y - входные и выходные данные соответственно.
model.fit(X, y)

# Подбираем самые важные признаки
importances = model.feature_importances_

# Создаем отдельный датасет для визуализации
final_df = pd.DataFrame({"Features" : pd.DataFrame(X).columns, "Importances" : importances})
final_df.set_index('Importances')

# Сортируем их по возрастанию для лучшей визуализации
final_df = final_df.sort_values('Importances')

# Выводим на график
final_df.plot.bar(color = 'teal')
    

Заключение

Эффективный отбор необходимых “фич” для модели приводит к наибольшему увеличению производительности. Это та проблема, за решением которой дата-сайентисты проводят большую часть времени. Разумеется, без построения признаков (feature engineering) у нас не будет материала для дальнейшего отбора.

Правильные преобразования зависят от многих факторов: типа и структуры данных, их объема. Не стоит также забывать о доступных ресурсах нашего компьютера или облака. Взяв на вооружение обе техники из этого цикла статей, вы будете чувствовать себя гораздо увереннее в мире науки о данных.

17
Сен
2021

📊 Kaggle за 30 минут: практическое руководство для начинающих

Начинающему дата сайентисту необходима практика, а Kaggle решает эту проблему. Из статьи вы узнаете, как лучше всего начать работу с популярным сервисом.

Что такое Kaggle?
Kaggle – это сообщество специалистов по Data Science. Изначально оно было соревновательной платформой, однако со временем обзавелось многими другими разделами (о них ниже). В результате мы имеем своеобразную соцсеть для дата-сайентистов, с полным циклом становления нового специалиста: от образовательных мини-курсов по основам машинного обучения до соревнований по исследованию данных.

Как начать?

Прежде чем начать покорение Kaggle, необходимо зарегистрироваться на сайте. Переходим по ссылке и нажимаем кнопку Register. У вас будет два варианта: зарегистрироваться через аккаунт Google или по адресу электронной почты. Получаем подтверждение на почту, логинимся – готово, теперь вы в Kaggle сообществе.

Важно:
На ресурсе есть система продвижения. Как только вы зарегистрируетесь, ваш аккаунт будет на самом низком уровне: Новичок (Novice).


Следующий уровень – Участник (Contributor). Достичь его можно несколькими простыми действиями:

  • Запустите 1 скрипт или notebook.
  • Сделайте 1 сабмит в любое соревнование.
  • Напишите 1 комментарий.
  • Сделайте 1 upvote (аналог лайка – стрелочка вверх).

Ниже вы найдете подробное руководство о том, как совершить эти действия и получить значок Contributor.


Что есть на Kaggle?

После регистрации мы оказываемся на главной странице ресурса и видим там несколько разделов.
После регистрации мы оказываемся на главной странице ресурса и видим там несколько разделов.
Competitions – те самые соревнования Kaggle
Они разделяются на несколько типов. Так, Getting Started и Playground представляют из себя соревнования с заранее обработанными данными и простыми задачами. Featured и Research – более сложные и полномасштабные состязания. Они охватывают весь цикл работ специалиста по Data Science (например, приведение данных в приемлемое состояние). Задача в подобных соревнованиях – решение нетривиальной проблемы, часто от таких крупных корпораций, как Google или Amazon, с солидным денежным вознаграждением для победителей.


Datasets – наборы данных на любой вкус и цвет
Здесь присутствует как дата для соревнований, так и пользовательская. Можно выкладывать собственные датасеты.

Code – пользовательский код
Онлайн-редактор, который позволяет создать Jupyter Notebook или простой скрипт на языках Python и R. Вы просто подключаете данные и работаете в браузере без необходимости устанавливать библиотеки и зависимости. Код выкладывается самый разнообразный: от EDA (Exploratory Data Analysis, он же подробный разбор) задач с соревнований, до простых методов, которые помогут оптимизировать ваши программы.


Ниже панели поиска находятся теги, по которым вы можете отобрать «нотбуки», которые вас интересуют.

Стрелочка под названием – это тот самый Upvote, по количеству которых определяется релевантность. Рекомендую выбрать интересующий вас notebook, лайкнуть его, прокомментировать и нажать кнопку Copy and Edit. Таким образом вы сохраните его у себя в профиле (аналог форка на GitHub), сможете запустить ячейки внутри него и получить описанную выше плашку Kaggle Contributor.

Discussions – обсуждение
Разделенный на несколько частей форум.


  • General – всё, что связано с самим Kaggle (анонсы, дискуссии по поводу прошедших соревнований) и жизненными циклами моделей машинного обучения.
  • Getting Started – аналог предыдущего раздела, но для новичков. Рекомендуется для посещения в первую очередь.
  • Product Feedback – отзывы о сайте. Если в процессе работы на Kaggle вы столкнулись с техническими проблемами, вам сюда.
  • Question & Answers – советы по технической составляющей от других дата-сайентистов.
  • Learn – вопросы и дискуссии, которые касаются раздела Courses на сайте.

Как принять участие в соревновании Kaggle?

Найдите приемлемое для вас соревнование. Потом нажмите Join Competition и согласитесь с условиями.


  • Overview – обзор соревнования. Здесь изложена суть проблемы, которую нужно решить. Также в этом разделе указана метрика, которая используется в состязании и другие требования (например, формат «сабмита»).
  • Data – данные, по которым нужно добиться наилучшего показателя метрики.
  • Code – тут участники соревнования выкладывают свои идеи и решения. Этот раздел рекомендуется для посещений в первую очередь, так как вы можете подсмотреть идеи для своих решений.
  • Discussion – обсуждение проблем соревнования, методов решения, нюансов.
  • Leaderboard – доска лидеров. В продвинутых соревнованиях на ней присутствуют золотая секция для денежных призов, серебряная для поощрительных и бронзовая для медалей Kaggle.
  • Rules – правила соревнования.
  • Team – есть не во всех состязаниях. Лучше всего создавать команды на более сложных этапах покорения Kaggle, для начала – пробуйте сами, чтобы обзавестись необходимыми навыками.

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

Чаще всего данные разбиваются на сеты train и test. При помощи первого вы обучаете модель, а уже на основе второго делаете предсказание (predict) перед сохранением решения (Submission).

Чтобы составить решение прямо на сайте, вам нужно:

  • Создать новый notebook в разделе Code.

  • Добавить туда данные соревнования, нажав кнопку Add data.

  • Сохранить notebook.

  • После этого у вас высветится меню, где нужно нажать Submit to Competition.

Теперь ваше решение появилось в турнирной таблице.

Самые простые соревнования для начинающих.

Примечание:
Данные соревнования входят в категории Getting Started и Playground. Вы не получите за них денежные призы и медали, однако, это отличный способ улучшить свои навыки и влиться в соревновательную среду Kaggle.

  • Titanic. Пожалуй, самое известное соревнование для новичков. Датасет «Титаника» содержит данные пассажиров одноименного корабля. Ваша цель – построение такой модели, которая наилучшим образом сможет предсказать, остался произвольный пассажир в живых или нет. Это типичная задача классификации.
  • House prices. Перед нами стоит задача предсказания стоимости дома на основе множества признаков (фич), вроде местоположения, площади, количества комнат, наличия гаража и т.д. Существует и более продвинутая версия этого соревнования – Advanced Regression Techniques. Здесь нужно решить задачу регрессии, поэтому вы можете наполнить модель линейными методами.
  • Tabular Playground Series. Запускается каждый месяц с января 2021 года. Ваша цель – предсказать столбец target на основе простых, табличных данных. В отличии от описанных выше бесконечных соревнований, Tabular Playground длится ровно месяц, что делает его более динамичным. Здесь будет меньше открытых нотбуков с готовыми ответами, но больше пространства для создания собственного, уникального решения.

Почему стоит участвовать в соревнованиях Kaggle?

Если вы еще не пробовали Kaggle, самое время начать. Соревнования помогут вам научиться решать реальные задачи из области Data Science и выбрать одно из ее многочисленных направлений. В режиме непрерывной практики за неделю вы узнаете больше, чем за 3 месяца изучения теории. Более того, медали с соревнований будут плюсом при трудоустройстве: работодатели обязательно обратят внимание на ваш практический опыт.

***

Если вы только начинаете путь в профессию и еще не определились со специализацией, подумайте о применении методов науки о данных в медицинской отрасли: сейчас это одно из самых перспективных направлений. Образовательная онлайн-платформа GeekBrains проводит набор на факультет Data Science в медицине, на котором студенты научатся с нуля решать задачи в области медицины. Обучение длится 18 месяцев, плюс 6 месяцев занимает практика по медицинской специализации. По итогам получите 15 проектов в портфолио и гарантию трудоустройства.

15
Сен
2021

📊 Построение и отбор признаков. Часть 1: feature engineering

Машинное обучение – это не просто подбор правильных параметров для модели. Рабочие процессы ML зависят от построения и отбора признаков. В сообществах специалистов по Data Science эти понятия ошибочно отождествляют. Разберемся, для чего нам нужны признаки, а также изучим особенности реализации техники feature engineering.

Что такое признаки (features) и для чего они нужны?

Признак, он же «фича» (от англ feature) – это переменная (столбец в таблице), которая описывает отдельную характеристику объекта. Признаки являются краеугольным камнем задач машинного обучения в целом: именно на их основании мы строим предсказания в моделях.

Признаки могут быть следующих видов:

  • Бинарные, которые принимают только два значения. Например, [true, false], [0,1], [“да”, “нет”].
  • Категориальные (или же номинальные). Они имеют конечное количество уровней, например, признак «день недели» имеет 7 уровней: понедельник, вторник и т. д. до воскресенья.
  • Упорядоченные. В некоторой степени похожи на категориальные признаки. Разница между ними в том, что данном случае существует четкое упорядочивание категорий. Например, «классы в школе» от 1 до 11. Сюда же можно отнести «время суток», которое имеет 24 уровня и является упорядоченным.
  • Числовые (количественные). Это значения в диапазоне от минус бесконечности до плюс бесконечности, которые нельзя отнести к предыдущим трем типам признаков.

Стоит отметить, что для задач машинного обучения нужны только те «фичи», которые на самом деле влияют на итоговый результат. Определить и сгенерировать такие признаки вам поможет эта статья.

Что такое построение признаков?

Построение признаков (Feature Engineering) – это процесс, во время которого мы извлекаем новые переменные для таблицы из необработанных данных. В жизни редко данные приходят в виде готовых матриц, потому любая задача начинается с извлечения признаков.

Например, в базе данных интернет-магазина есть таблица «Покупатели», содержащая одну строку для каждого посетившего сайт клиента.

В ней также может быть таблица «Взаимодействия», содержащая строку для каждого взаимодействия (клика или посещения страницы), которое клиент совершил на сайте. Эта таблица также содержит информацию о времени взаимодействия и типе события, которое представляло собой взаимодействие (событие «Покупка», событие «Поиск» или событие «Добавить в корзину»). Эти две таблицы связаны между собой столбцом Customer ID.



Чтобы предсказать, когда покупатель приобретет товар в следующий раз, мы хотели бы получить единую числовую матрицу признаков со строкой для каждого покупателя. Затем мы можем использовать ее в алгоритме машинного обучения. Однако таблица, которая больше всего похожа на эту («Покупатели»), не содержит практически никакой релевантной информации. Мы можем построить из нее несколько характеристик, например, количества дней, прошедших с момента регистрации клиента, но наши возможности на этом этапе ограничены.

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

  • Среднее время между прошлыми покупками.
  • Средняя сумма прошлых покупок.
  • Максимальная сумма прошлых покупок.
  • Время, прошедшее с момента последней покупки.
  • Общее количество покупок в прошлом.

Чтобы построить эти признаки, мы должны найти все связанные с конкретным клиентом взаимодействия. Затем мы проведем фильтрацию тех, чей Тип (Type) не является "Покупкой", и вычислим функцию, которая возвращает одно значение, используя имеющиеся данные.

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

Этот тип инжиниринга признаков необходим для эффективного использования алгоритмов машинного обучения и построения прогностических моделей.

Ниже будут перечислены основные и самые известные методы feature engineering с кратким описанием и кодом реализации.

Построение признаков на табличных данных

Удаление пропущенных значений

Отсутствующие значения – одна из наиболее распространенных проблем, с которыми вы можете столкнуться при попытке подготовить данные. Этот фактор очень сильно влияет на производительность моделей машинного обучения.

Самое простое решение для пропущенных значений – отбросить строки или весь столбец. Оптимального порога для отбрасывания не существует, но вы можете использовать 70% в качестве значения и отбросить строки со столбцами, в которых отсутствуют значения, превышающие этот порог.

        import pandas as pd
import numpy as np

threshold = 0.7
# Удаление столбцов с коэффициентом пропущенных значений выше порога
data = data[data.columns[data.isnull().mean() < threshold]]

# Удаление строк с коэффициентом отсутствия значений выше порога
data = data.loc[data.isnull().mean(axis=1) < threshold]
    

Заполнение пропущенных значений

Более предпочтительный вариант, чем отбрасывание, потому что он сохраняет размер данных. Очень важно, что именно вы относите к недостающим значениям. Например, если у вас есть столбец, с числами 1 и N/A , то вполне вероятно, что строки N/A соответствуют 0 .

В качестве другого примера: у вас есть столбец, который показывает количество посещений клиентов за последний месяц. Тут отсутствующие значения могут быть заменены на 0.

За исключением вышеперечисленного, лучший способ заполнения пропущенных значений – использовать медианы столбцов. Поскольку средние значения столбцов чувствительны к значениям выбросов, медианы в этом отношении будут более устойчивыми.

        import pandas as pd
import numpy as np

# Заполнение всех пропущенных значений 0
 data = data.fillna (0)
# Заполнение пропущенных значений медианами столбцов
 data = data.fillna (data.median ())
    

Замена пропущенных значений максимальными

Замена отсутствующих значений на максимальное значение в столбце будет хорошим вариантом для работы только в случае, когда мы разбираемся с категориальными признаками. В других ситуациях настоятельно рекомендуется использовать предыдущий метод.

        import pandas as pd
import numpy as np

data['column_name'].fillna(data['column_name'].value_counts() .idxmax(), inplace=True) 
    

Обнаружение выбросов

Прежде чем упомянуть, как можно обрабатывать выбросы, я хочу заявить, что лучший способ обнаружить выбросы – провести визуализацию вашего датасета. В этом вам помогут библиотеки seaborn и matplotlib.

Что касается обнаружения выбросов: один из лучших способов это сделать – рассчитать стандартное отклонение. Если значение отклоняется больше, чем на x * стандартное отклонение, его можно принять, как выброс. Наиболее используемое значение для x – в пределах [2, 4].

        import pandas as pd
import numpy as np

# Удаление неподходящих строк
x = 3
upper_lim = data['column'].mean () + data['column'].std () * x 
lower_lim = data['column'].mean () - data['column'].std () * x
data = data[(data['column'] < upper_lim) & (data['column'] > lower_lim)]
    

Другой математический метод обнаружения выбросов – использование процентилей. Вы принимаете определенный процент значения сверху или снизу за выброс.

Ключевым моментом здесь является повторная установка процентного значения, и это зависит от распределения ваших данных, как упоминалось ранее.

Кроме того, распространенной ошибкой является использование процентилей в соответствии с диапазоном данных. Другими словами, если ваши данные находятся в диапазоне от 0 до 100 , ваши лучшие 5% – это не значения между 96 и 100 . Верхние 5% означают здесь значения, выходящие за пределы 95-го процентиля данных.

        import pandas as pd
import numpy as np

# Избавляемся от лишних строк при помощи процентилей
upper_lim = data['column'].quantile(.95)
lower_lim = data['column'].quantile(.05)
data = data[(data['column'] < upper_lim) & (data['column'] > lower_lim)]
    

Ограничение выбросов

Другой вариант обработки выбросов – ограничить их, а не отбрасывать. Вы сможете сохранить свой размер данных, и это может быть лучше для окончательной производительности модели.

С другой стороны, ограничение может повлиять на распределение данных и качество модели, поэтому лучше придерживаться золотой середины.

        import pandas as pd
import numpy as np

upper_lim = data['column'].quantile(.95)
lower_lim = data['column'].quantile(.05)
data.loc[(df[column] > upper_lim),column] = upper_lim
data.loc[(df[column] < lower_lim),column] = lower_lim
    

Логарифмическое преобразование

Логарифмическое преобразование – одно из наиболее часто используемых во время построения признаков математических преобразований.

  • Оно помогает обрабатывать искаженные данные, и после преобразования распределение становится более приближенным к нормальному.
  • В большинстве случаев порядок величины данных изменяется в пределах диапазона данных. Например, разница между возрастом от 15 до 20 лет не равна возрасту от 65 до 70 лет, так как по всем остальным аспектам разница в 5 лет в молодом возрасте означает большую разницу в величине. Этот тип данных поступает в результате мультипликативного процесса, и логарифмическое преобразование нормализует подобные различия величин.
  • Это также снижает влияние выбросов за счет нормализации разницы величин, и модель становится более надежной.

Важное примечание: данные, которые вы применяете, должны иметь только положительные значения, иначе вы получите ошибку.

        import pandas as pd
import numpy as np

# Пример логарифмической трансформации
data = pd.DataFrame({'value':[2,45, -23, 85, 28, 2, 35, -12]})
data['log+1'] = (data['value']+1).transform(np.log)

# Обработка отрицательных значений
# (Обратите внимание, что значения разные)
data['log'] = (data['value']-data['value'].min()+1) .transform(np.log)
    

Быстрое кодирование (One-Hot encoding)

Этот метод распределяет значения в столбце по нескольким столбцам флагов и присваивает им 0 или 1. Бинарные значения выражают связь между сгруппированным и закодированным столбцом. Этот метод изменяет ваши категориальные данные, которые сложно понять алгоритмам, в числовой формат. Группировка происходит без потери какой-либо информации, например:


Приведенная ниже функция отражает использование метода быстрого кодирования с вашими данными.

        encoded_columns = pd.get_dummies(data['column'])
data = data.join(encoded_columns).drop('column', axis=1)
    

Масштабирование признаков

В большинстве случаев числовые характеристики набора данных не имеют определенного диапазона и отличаются друг от друга.

Например, столбцы возраста и месячной зарплаты будут иметь совершенно разный диапазон.

Как сравнить эти два столбца, если это необходимо в нашей задаче? Масштабирование решает эту проблему, так как после данной операции элементы становятся идентичными по диапазону.

Существует два распространенных способа масштабирования:

  • Нормализация.

В данном случае все значения будут находиться в диапазоне от 0 до 1. Дискретные бинарные значения определяются как 0 и 1.


        import pandas as pd
import numpy as np

data = pd.DataFrame({'value':[2,45, -23, 85, 28, 2, 35, -12]})

data['normalized'] = (data['value'] - data['value'].min()) / (data['value'].max() - data['value'].min())
    
  • Стандартизация.

Масштабирует значения с учетом стандартного отклонения. Если стандартное отклонение функций другое, их диапазон также будет отличаться друг от друга. Это снижает влияние выбросов в элементах. В следующей формуле стандартизации среднее значение показано как μ, а стандартное отклонение показано как σ.


        import pandas as pd
import numpy as np

data = pd.DataFrame({'value':[2,45, -23, 85, 28, 2, 35, -12]})

data['standardized'] = (data['value'] - data['value'].mean()) / data['value'].std()
    

Работа с текстом

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

Перед тем как работать с текстом, его необходимо разбить на токены – отдельные слова. Однако делая это слишком просто, мы можем потерять часть смысла. Например, «Великие Луки» это не два токена, а один.

После превращения документа в последовательность слов, можно начинать превращать их в векторы. Самый простой метод – Bag of Words. Мы создаем вектор длиной в словарь, для каждого слова считаем количество его вхождений в текст и подставляем это число на соответствующую позицию в векторе.

В коде алгоритм выглядит гораздо проще, чем на словах:

        from functools import reduce
import numpy as np

texts = [['i', 'have', 'a', 'cat'],
         ['he', 'have', 'a', 'dog'],
         ['he', 'and', 'i', 'have', 'a', 'cat', 'and', 'a', 'dog']]

dictionary = list(enumerate(set(reduce(lambda x, y: x + y, texts))))

def vectorize(text):
    vector = np.zeros(len(dictionary))
    for i, word in dictionary:
        num = 0
        for w in text:
            if w == word:
                num += 1
        if num:
            vector[i] = num
    return vector
for t in texts:
    print(vectorize(t))
    

Работа с изображениями

Что касается изображений, то методы построения и извлечения признаков для этого типа данных – одни из самых простых.

Часто для задач с изображениями используется определенная сверточная сеть. Необязательно продумывать архитектуру сети и обучать ее с нуля. Можно взять уже обученную нейросеть из открытых источников.

Чтобы адаптировать ее под свою задачу, работающие в области науки о данных инженеры практикуют fine tuning (тонкую настройку). Ликвидируются последние слои нейросети, вместо них добавляются новые, подобранные под нашу конкретную задачу, и сеть дообучается на новых данных.

Пример подобного шаблона:

        from keras.applications.resnet50 import ResNet50
from keras.preprocessing import image
from scipy.misc import face
import numpy as np

resnet_settings = {'include_top': False, 'weights': 'imagenet'}
resnet = ResNet50(**resnet_settings)

img = image.array_to_img(face())
img = img.resize((224, 224))
# в реальной жизни может понадобиться внимательнее относиться к ресайзу
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
# нужно дополнительное измерение, т.к. модель рассчитана на работу с массивом изображений

features = resnet.predict(x)
    

Заключение

Правильное построение признаков крайне важно в улучшении наших моделей машинного обучения. К тому же без этого этапа мы не сможем осуществить последующую технику отбора признаков.

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

Следующая статья будет посвящена отбору признаков.

14
Сен
2021

📊 Обучение на Data Scientist: как составить резюме, пройти собеседование и найти работу?

Читайте обзор ресурсов для составления резюме, поиска вакансий и прохождения собеседования на позицию Data Scientist.

Независимо от того, являетесь ли вы опытным специалистом по Data Science или новичком, вы можете столкнуться с трудностями при поиске работы. В небольшом обзоре мы разберемся, какие стратегии, ресурсы и инструменты помогут продать себя на рынке труда, и как получить лучшие офферы.

Составляем резюме

Контент

Наряду с навыками и знаниями, которыми должны обладать Data Scientist, узнайте о последних тенденциях отрасли: как работает корпорация, каковы востребованные рабочие роли, каковы новейшие языки программирования и т.д. Работа в Data Science – это прежде всего умение учиться самостоятельно и постоянно обновлять набор навыков.


Не забудьте включить в резюме ссылки на GitHub, Twitter, Linkedin и другие ресурсы, позволяющие продемонстрировать ваш опыт. Опубликуйте проекты, над которыми вы работали во время учебы и стажировок. Таким образом работодатель сможет заметить вас и оценить ваши навыки, отточенные на реальных задачах. Если вы являетесь новичком в науке данных и хотите найти первую работу, но у вас еще нет опыта, создайте собственные проекты! Для поиска первого оффера достаточно двух-трех примеров:

  • Опубликуйте результаты соревнований Kaggle и код;
  • Создайте проект, который покажет ваши личные интересы или примите участие в хакатоне;
  • Включите проекты и код, созданные во время прохождения курсов Data Science.

Организуйте свои проекты так, чтобы сделать ваш вклад и достижения очевидными. Для этого попробуйте ответить на следующие вопросы:

  • Почему вы это сделали? Какую проблему вы хотели решить? Покажите, какова была конечная цель проекта.
  • Что вы сделали? Объясните, как вы подошли к проблеме. Если вы можете показать код, статью, сообщение в блоге или презентацию на конференции – сделайте это!
  • Как вы это сделали? Представьте инструменты и ресурсы, которые вы использовали.
  • Чего вы добились? Отразите количественные результаты вашей работы в технических и бизнес-показателях.
Если вы начинаете карьеру специалиста по Data Science, будьте предельно настойчивы в поиске контрактов. Создайте личный веб-сайт с демонстрацией примеров вашей работы и убедитесь, что он прост в навигации, лаконичен и постоянно обновляется. Потенциальные работодатели обязательно захотят заглянуть в ваше портфолио, поэтому приступите к его оформлению в первую очередь.

Сбалансируйте ваше резюме: наряду с техническими навыками важно показать применение навыков визуализации и презентации данных, story telling, soft skills и умение работать в команде.

Стиль

Выберите подходящий шаблон резюме, рекомендуется использовать шаблоны с двумя столбцами – это сделает резюме лаконичным и легко читаемым. Дизайн и визуальная репрезентация опыта кандидата играет важную роль для первого впечатления, поэтому уделите внимание деталям:

  • Постарайтесь разместить всю информацию на одной странице. Если у вас большой опыт, много проектов или публикаций – упомяните несколько из них в резюме и предоставьте ссылку на Github или личный веб-сайт.
  • Выделите ссылки, используя Bold или Underline. Это позволит сотрудникам HR быстрее их обнаружить.
  • Соблюдайте единый стиль ссылок, дат, названий компаний и университетов, знаков пунктуации и т.д. Эти маленькие детали играют большую роль в общей визуальной картине вашего резюме.
  • Сделать хорошую профессиональную фотографию для резюме – сложная задача. Это необязательно, и никто на самом деле не ожидает, что у вас будет фотография. Многие компании предпочитают лаконичные резюме без фото, таким образом отбор кандидатов проходит более объективно.
  • Проверьте орфографию и пунктуацию. Ошибки и опечатки в резюме раздражают и указывают на недостаточное внимание к деталям. Перечитайте свои тексты с Text.ru, Advego (на русском) или Grammarly, ReversoSpeller (на английском) прежде чем отправлять их. Попросите друзей проверить ваше резюме: они могут заметить ошибки, которые вы упустили.

Обзор ресурсов


Canva – платформа для графического дизайна и создания резюме, постеров и разнообразного визуального контента.

Примеры:

Overleaf – редактор LaTeX, используемый для написания, редактирования и публикации научных документов, резюме и т.д. Платформа сотрудничает с широким кругом издателей, предоставляя официальные шаблоны журнала LaTeX и прямые ссылки для отправки.

Примеры:

CVmaker – платформа для создания профессионального резюме за 10 минут. Интегрированные в CVmaker шаблоны позволяют легко изменять контент или цвета вашего резюме.

Поиск вакансий

Стратегии поиска

Выберите свою нишу или специальность в области науки о данных. Например, если ли у вас есть опыт в обработке естественного языка, в области фармацевтики, финансов, компьютерного зрения, розничной торговли или облачных технологий, обозначьте это в начале резюме или профайла.

Ваши посты в блоге, примеры проектов и поиск офферов должны быть сосредоточены вокруг выбранной специализации. Это поможет найти подходящий вариант намного быстрее и начать строить портфолио, даже не имея опыта за плечами.


Не бойтесь вести переговоры! Если вы готовы освоить дополнительные навыки в ходе работы, не спешите отказываться от офферов, которые их требуют. Работа в Data Science – это постоянное самообучение. Если же вы не уверены, что сможете выполнить заказ качественно и в срок, стоит задуматься, стоит ли вознаграждение риска потерять репутацию.

Лучше всего проанализировать свои возможности и не цепляться за каждый оффер.

Попробуйте найти кого-нибудь, кто работает в компании, и кто может направить вас и предоставить рекомендацию. Это увеличит ваши шансы на прохождение первого этапа отбора. Обычно, если кандидата нанимают на работу, порекомендовавший его человек получает денежный бонус. Это беспроигрышная ситуация.

Всегда лучше попросить рекомендации у своих друзей или слабых связей, но также можно сначала написать в Linkedin. Найдите профиль сотрудника компании в Linkedin, свяжитесь с ним или с ней и напишите сообщение. Не бойтесь попросить рекомендации у незнакомца. Если вы покажете свою мотивацию и приложенные усилия, вам обязательно помогут. Будьте уважительны: не отправляйте разным людям одно и то же сообщение с измененным названием компании. Уважайте время других, будучи кратким и конкретным. Убедите других помочь вам, будучи честным.

Обзор ресурсов

При поиске офферов и проектов обратите внимание на самые крупные и авторитетные российские и международные онлайн-платформы: HH, Jooble, Работа.ру, Linkedin, Яндекс Работа, Upwork, AngelList, Freelancer, Kaggle, Indeed, Peopleperhour, Freelance.ru, Freelancehunt, Weblancer, Workzilla.

Они предлагают массу возможностей, а также предоставляют необходимые для успешной реализации проекта средства: публичный профиль, чат в режиме реального времени с клиентами, функции безопасности, расписание, аналитику и, самое главное, инструменты для управления заработной платой и налогами. Регистрация на сайтах может занять много времени, а в ряде случаев вам придется пройти собеседование. Также вас могут попросить заплатить небольшой взнос, чтобы зарегистрироваться или подать заявку на получение офферов.

Это один из наиболее энергозатратных этапов, поэтому уделите достаточное количество времени созданию хорошего профиля с подробным описанием вашего образования и опыта, а также с информацией о предыдущих проектах. Включите в него ссылки на примеры работы: личный веб-сайт, GitHub, интерактивное портфолио, студенческие проекты или соревнования Kaggle.

Собеседование


Подготовка к собеседованиям на вакансии в Data Science – трудоемкое занятие. Время подготовки может быть значительно сокращено, если у вас есть предыдущий опыт работы в этой области и/или есть список подходящих ресурсов для каждой темы, которые потенциально возникнут во время интервью.

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

Самые распространенные типы интервью:

  • Интервью по кодированию (Python, R и т.д.);
  • Статистическое/Математическое интервью (проверка знаний концепций и навыков решения задач);
  • A/B проверка знаний.

Помимо подготовки к задачам для разных типов интервью есть и другие важные позиции, которые стоит подтянуть:

  • Коммуникативные навыки: всем специалистам Data Science необходимо умения общаться, строить коммуникации и презентовать проекты;
  • Знакомство с облачными платформам и хранилищами данных является плюсом, поскольку большинство компаний их использует;
  • Владение инструментами визуализации данных, например, Looker, Tableau и Microsoft Power BI.
Подробнее о том, чего ожидать и к чему готовиться, можно прочесть в материале «Собеседование на вашу первую работу Data Scientist’ом».

Заключение

Освоить профессию Data Scientist можно даже в самые краткие сроки. Разработанная в США методика Bootcamp предполагает интенсивное очное обучение с полным погружением в процесс. В России этот формат практикует образовательный проект Elbrus Bootcamp: студенты обучаются в московском кампусе, посвящая науке о данных все будние дни с 9 до 18 часов. Заниматься в онлайне без отрыва от производства не получится, формат буткампа обеспечивает высочайшую вовлеченность всех участников в учебный процесс. В течение 12 недель под руководством практикующего Data Scientist студенты осваивают сбор и анализ данных, нейронные сети, машинное обучение и другие hard и soft skills: количество практических занятий при этом сравнимо со стажировкой в крупной ИТ-компании. Успешно завершив курс, вы получите не только ценные знания, но и возможность их применить, а также добавите несколько проектов портфолио. Удачи!