{"id":14293,"url":"\/distributions\/14293\/click?bit=1&hash=05c87a3ce0b7c4063dd46190317b7d4a16bc23b8ced3bfac605d44f253650a0f","hash":"05c87a3ce0b7c4063dd46190317b7d4a16bc23b8ced3bfac605d44f253650a0f","title":"\u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0441\u0435\u0440\u0432\u0438\u0441 \u043d\u0435 \u043f\u043e\u0442\u0440\u0430\u0442\u0438\u0432 \u043d\u0438 \u043a\u043e\u043f\u0435\u0439\u043a\u0438","buttonText":"","imageUuid":""}

30 SQL-запросов, объяснённых через их эквиваленты Pandas

В мире, где с 1974 года доминирует SQL, в 2008 году появился Pandas, предлагающий привлекательные функции, такие как встроенная визуализация и гибкая обработка данных. Он быстро стал популярным инструментом для исследования данных, затмив собой SQL.

Но не обманывайте себя, SQL по-прежнему держит свои позиции. Это второй по востребованности и третий по скорости роста язык для Data science (см. здесь ). Таким образом, в то время как Pandas привлекает всеобщее внимание, SQL остаётся жизненно важным навыком для любого специалиста по данным.

Давайте узнаем, как легко выучить SQL, если вы уже знаете Pandas.

Подключение к базе данных

Настройка рабочей области SQL и подключение к образцу базы данных может быть настоящей головной болью. Во-первых, вам нужно установить предпочитаемый вариант SQL (PostgreSQL, MySQL и т. д.) и загрузить SQL IDE. Выполнение их здесь увело бы нас от цели статьи, поэтому мы воспользуемся сокращением.

В частности, мы будем напрямую запускать SQL-запросы в Jupyter Notebook без дополнительных шагов. Всё, что нам нужно сделать, это установить пакет ipython-sql с помощью pip:

pip install ipython-sql

После установки запустите новый сеанс Jupyter и выполните эту команду в блокноте:

%load_ext sql

и всё готово!

Чтобы проиллюстрировать, как работают основные операторы SQL, мы будем использовать базу данных Chinook SQLite, которая имеет 11 таблиц.

Чтобы загрузить набор данных и его 11 таблиц как отдельные переменные в нашу среду, мы можем запустить:

%sql sqlite:///data/chinook.db

Оператор начинается со встроенной волшебной команды %sql, которая сообщает интерпретатору блокнота, что мы будем запускать команды SQL. За ней следует путь, по которому находится загруженная база данных Chinook.

Допустимые пути всегда должны начинаться с префикса sqlite:/// для баз данных SQLite. Выше мы подключаемся к базе данных, хранящейся в папке «data» текущего каталога. Если вы хотите передать абсолютный путь, префикс должен начинаться с четырех косых черт:sqlite:////

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

Первый взгляд на таблицы

Первое, что мы всегда делаем в Pandas, — это используем функцию .head() для первого взгляда на данные. Давайте узнаем, как это сделать в SQL:

%%sql SELECT * FROM customers LIMIT 5

Первое ключевое слово в приведённом выше запросе — SELECT. Оно эквивалентно оператору скобок в Pandas, где мы выбираем определённые столбцы. Но за ключевым словом SELECT следует * (звездочка). * — оператор SQL, который выбирает всё (все строки и столбцы) из таблицы, указанной после ключевого слова FROM. LIMIT используется для минимизации возвращаемого результата. Таким образом, приведённый выше запрос эквивалентен функции df.head().

Если вы не хотите выбирать все столбцы, вы можете указать одно или несколько имён столбцов после ключевого слова SELECT:

%%sql SELECT Name, Composer, UnitPrice FROM tracks LIMIT 10

Эквивалентная операция Pandas:

tracks[['Name', 'Composer', 'UnitPrice']].head(10)

Другое полезное ключевое слово в SQL — DISTINCT. Добавление этого ключевого слова перед именем любого столбца возвращает его уникальные значения:

%%sql SELECT DISTINCT FirstName FROM employees -- equivalent to `.unique()`

Комментарии в SQL пишутся с двойным дефисом.

Подсчёт количества строк

Точно так же, как у Pandas есть атрибут .shape для своих DataFrames, у SQL есть функция COUNT для отображения количества строк в таблице:

%%sql SELECT COUNT(*) FROM tracks

Более полезной информацией будет подсчёт количества уникальных значений в определённом столбце. Мы можем сделать это, добавив ключевое слово DISTINCT в COUNT:

%%sql SELECT COUNT(DISTINCT FirstName) FROM employees -- equivalent to `employees['FirstName'].nunique()`

Фильтрация результатов с помощью предложений WHERE

Просто смотреть и считать строки может любой. Давайте посмотрим, как мы можем фильтровать строки на основе условий.

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

%%sql SELECT * FROM tracks WHERE UnitPrice > 1.0 LIMIT 10 --tracks[tracks['UnitPrice' > 1.0]]

Условные операторы записываются в предложении WHERE, которое всегда следует после FROM и перед ключевыми словами LIMIT. Использование условий очень похоже на то, как мы это делаем в Pandas, но я осмелюсь сказать, что версия SQL более читабельна.

Вы также можете использовать функцию COUNT при использовании условных выражений. Например, давайте посмотрим количество песен с ценой от 1 до 10 долларов:

%%sql SELECT COUNT(*) FROM tracks WHERE UnitPrice > 1.0 AND UnitPrice < 10 -- tracks[(tracks['UnitPrice'] > 1) & (tracks['UnitPrice'] < 10)]

Выше мы связали два условия логическим оператором AND. Аналогично используются и другие логические операторы (OR, NOT).

Теперь давайте посмотрим все счета-фактуры, в которых в качестве города выставления счётов указан Париж или Берлин:

%%sql SELECT BillingAddress, BillingCity, Total FROM invoices WHERE BillingCity = 'Paris' OR BillingCity = 'Berlin' LIMIT 5 --invoices[(invoices['BillingCity'] == 'Paris') | -- (invoices['BillingCity'] == 'Berlin')]

Оператор равенства в SQL требует только одного знака «=» (равно). Оператор неравенства представлен операторами '!=' или '<>':

%%sql SELECT BillingAddress, BillingCity, Total FROM invoices WHERE BillingCity != 'Paris' AND BillingCity <> 'Berlin' LIMIT 5

Упрощённая фильтрация с помощью BETWEEN и IN

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

Если бы мы хотели выбрать счета для пяти городов, нам пришлось бы написать пять связанных условий. К счастью, SQL поддерживает аналогичный оператор IN, поэтому .isin() нам не нужно:

%%sql SELECT * FROM invoices WHERE BillingCity IN ('Berlin', 'Paris', 'New York', 'Boston', 'London') LIMIT 5 --invoices[invoices['BillingCity'].isin( -- ('Berlin', 'Paris', 'New York', 'Boston', 'London') --)]

Список значений после IN следует указывать в виде кортежа, а не списка. Вы также можете отменить условие с помощью ключевого слова NOT:

%%sql SELECT * FROM invoices WHERE BillingCity NOT IN ('Berlin', 'Paris', 'New York', 'Boston', 'London') LIMIT 5 --invoices[~invoices['BillingCity'].isin( -- ('Berlin', 'Paris', 'New York', 'Boston', 'London') --)]

Другой распространённой операцией фильтрации числовых столбцов является выбор значений в пределах диапазона. Для этого можно использовать ключевое слово BETWEEN, которое эквивалентно pd.Series.between():

%%sql SELECT BillingCity, Total FROM invoices WHERE Total BETWEEN 5 AND 15 LIMIT 5 --invoices[invoices['Total'].between(5, 15)]

Проверка на нули

В каждом источнике данных есть пропущенные значения, и базы данных не являются исключением. Точно так же, как есть несколько способов исследовать отсутствующие значения в Pandas, существуют определённые ключевые слова, которые проверяют наличие нулевых значений в SQL. Следующий запрос подсчитывает количество строк с пропущенными значениями в BillingState:

%%sql SELECT COUNT(*) FROM invoices WHERE BillingState IS NULL --invoices['BillingState'].isnull().sum()

Вы можете добавить ключевое слово NOT между IS и NULL, чтобы отбросить пропущенные значения определённого столбца:

%%sql SELECT InvoiceDate, BillingCountry FROM invoices WHERE Total IS NOT NULL LIMIT 10

Лучшее сопоставление строк с LIKE

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

В качестве альтернативы SQL предлагает подстановочный знак '%' в качестве заполнителя для соответствия любому символу 0 или более раз. Например, строка «gr%» соответствует «greet», «groom», «greed» и «%ex%» соответствует любому тексту с «ex» в середине и т. д. Давайте посмотрим, как использовать её с SQL:

%%sql SELECT Name, Composer, UnitPrice FROM tracks WHERE Name LIKE 'B%' LIMIT 5 --tracks[tracks['Name'].str.startswith('B')]

Приведённый выше запрос находит все песни, начинающиеся с «B». Строка, содержащая подстановочный знак, должна идти после ключевого слова LIKE.

Теперь давайте найдём все песни, в названии которых есть слово «beautiful»:

%%sql SELECT Name, Composer, UnitPrice FROM tracks WHERE Name LIKE '%beautiful%' --tracks[tracks['Name'].str.contains('beautiful')]

Вы также можете использовать другие логические операторы рядом с LIKE:

%%sql SELECT Name, Composer, UnitPrice FROM tracks WHERE (Name LIKE 'F%') AND (UnitPrice > 1.0) --tracks[(tracks['Name'].str.startswith('F')) & (tracks['UnitPrice'] > 1.0)]

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

Агрегатные функции в SQL

Также возможно выполнять основные арифметические операции над столбцами. Эти операции называются агрегатными функциями в SQL, и наиболее распространёнными из них являются AVG, SUM, MIN, MAX. Их функциональность должна быть ясна из их названий:

%%sql SELECT SUM(Total), MAX(Total), MIN(Total), AVG(Total) FROM invoices

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

%%sql SELECT AVG(Total), BillingCity, BillingAddress FROM invoices; -- the result will be a single row because -- of the presence of aggregate functions

Вы можете так же легко комбинировать агрегатные функции с условными операторами, используя предложения WHERE:

%%sql SELECT AVG(Total), BillingCity FROM invoices WHERE BillingCity = 'Paris' -- invoices[invoices['BillingCity']]['Total'].mean()

Также можно использовать арифметические операторы, такие как +, -, *, / в столбцах и простые числа. При использовании со столбцами операция выполняется поэлементно:

%%sql SELECT SUM(Total) / COUNT(Total) FROM invoices -- finding the mean manually

Одно замечание об арифметических операциях: если вы выполняете операции только с целыми числами, SQL считает, что вы ожидаете целое число в качестве ответа:

%%sql
SELECT 10 / 3

Вместо того, чтобы возвращать 3,33…, результат равен 3. Чтобы получить результат с плавающей запятой, вы должны использовать в запросе хотя бы одно число с плавающей запятой или использовать все числа с плавающей запятой, чтобы быть в безопасности:

%%sql
SELECT 10.0 / 3.0

Используя эти знания, рассчитаем среднюю продолжительность песни в минутах:

%%sql SELECT Milliseconds / 1000.0 / 60.0 FROM tracks LIMIT 10

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

Чтобы избежать этого, SQL допускает использование псевдонимов, подобно тому, как операторы импорта имеют псевдонимы в Python. Например:

%%sql SELECT SUM(Total) as sum_total FROM invoices

Использование ключевого слова as после одного элемента в операторе SELECT сообщает SQL, что мы используем псевдоним. Вот ещё примеры:

%%sql SELECT SUM(Total) as sum_total, MAX(Total) as max_total, MIN(Total) as min_total, SUM(Total) / COUNT(Total) as mean_total FROM invoices

Вы можете так же легко использовать псевдонимы для столбцов с длинными именами.

Упорядочивание результатов в SQL

Так же, как у Pandas есть метод sort_values, SQL поддерживает упорядочение столбцов через предложение ORDER BY. Передача имени столбца после предложения сортирует результаты в порядке возрастания:

%%sql SELECT Name, Composer, UnitPrice FROM tracks WHERE Composer <> 'None' ORDER BY Composer LIMIT 10 -- tracks.sort_values('Compose')[['Name', 'Compose', 'UnitPrice']]

Упорядочим таблицу треков по возрастанию имени композитора. Обратите внимание, что оператор ORDER BY всегда должен стоять после предложения WHERE. Также можно передать два или более столбца в ORDER BY:

%%sql SELECT Name, Composer, UnitPrice FROM tracks WHERE Composer <> 'None' ORDER BY UnitPrice, Composer, Name LIMIT 10 -- tracks.sort_values(['UnitPrice', 'Composer', 'Name'])\ -- [['Name', 'Compose', 'UnitPrice']]

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

%%sql SELECT Name, Composer, UnitPrice FROM tracks WHERE Composer != 'None' ORDER BY UnitPrice DESC, Composer DESC, Name ASC LIMIT 10 -- tracks.sort_values(['UnitPrice', 'Composer', 'Name'])\ -- [['Name', 'Compose', 'UnitPrice']]

Приведённый выше запрос возвращает три столбца после упорядочения UnitPrice и Compose в порядке убывания и имени в порядке возрастания ( ключевое слово ASC по умолчанию).

Группировка в SQL

Одной из самых мощных функций Pandas является расширение groupby. Вы можете использовать его, чтобы преобразовать таблицу практически в любую форму, которую вы хотите. Его очень близкий родственник в SQL - GROUP BY, который можно использовать для достижения той же функциональности. Например, следующий запрос подсчитывает количество песен в каждом жанре:

%%sql SELECT GenreID, COUNT(*) as genre_count FROM tracks GROUP BY GenreId LIMIT 10 -- tracks.groupby('GenreId')['GenreID'].count()

Разница между GROUP BY в SQL и groupby в Pandas заключается в том, что SQL не позволяет выбирать столбцы, которые не были указаны в предложении GROUP BY. Например, добавление дополнительного свободного столбца в приведённый выше запрос приводит к ошибке:

%%sql SELECT Name, GenreID, COUNT(*) as genre_count FROM tracks GROUP BY GenreId syntax error at or near "GROUP" LINE 1: GROUP BY GenreId;

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

%%sql SELECT GenreId, AlbumId, COUNT(*) as genre_count, AVG(Milliseconds) / 1000.0 / 60.0 as avg_duration, AVG(UnitPrice) as avg_price FROM tracks GROUP BY GenreId, AlbumId LIMIT 10

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

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

%%sql SELECT GenreId, AlbumId, COUNT(*) as genre_count, AVG(Milliseconds) / 1000.0 / 60.0 as avg_duration, AVG(UnitPrice) as avg_price FROM tracks GROUP BY GenreId, AlbumId ORDER BY avg_duration DESC, genre_count DESC LIMIT 10

Обратите внимание на то, как мы используем псевдонимы агрегатных функций в предложении ORDER BY. После того как вы назовёте столбец или результат агрегатной функции псевдонимом, вы сможете ссылаться на них только по псевдониму для остальной части запроса.

Использование условных выражений с HAVING

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

%%sql SELECT GenreId FROM tracks GROUP BY GenreId WHERE COUNT(GenreId) > 10 syntax error at or near "WHERE" LINE 1: where COUNT(GenreId) > 10

Правильный способ фильтрации строк на основе результатов агрегатных функций — использование предложения HAVING:

%%sql SELECT GenreId FROM tracks GROUP BY GenreId HAVING COUNT(GenreId) > 100

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

Краткое содержание

К настоящему времени вы должны были понять, насколько мощным может быть SQL и насколько более читабельным он становится по сравнению с Pandas. Несмотря на то, что мы узнали тонну, мы едва лишь поцарапали поверхность.

Для практических задач я рекомендую Data Lemur или LeetCode, если вы любите приключения.

0
Комментарии
-3 комментариев
Раскрывать всегда