Выполнение запроса SQL над набором данных pandas

У меня есть набор данных pandas, который называется 'df'.

Как я могу сделать что-то вроде ниже;

df.query("select * from df")

Спасибо.

Для тех, кто знает R, есть библиотека sqldf, где вы можете выполнять SQL-код в R, мой вопрос в основном, есть ли какая-нибудь библиотека, такая как sqldf в python

9 ответов

Решение

Это не pandas.query должен сделать, вы можете посмотреть на пакет pandasql (такой же как sqldf в R)

import pandas as pd
import pandasql as ps

df = pd.DataFrame([[1234, 'Customer A', '123 Street', np.nan],
               [1234, 'Customer A', np.nan, '333 Street'],
               [1233, 'Customer B', '444 Street', '333 Street'],
              [1233, 'Customer B', '444 Street', '666 Street']], columns=
['ID', 'Customer', 'Billing Address', 'Shipping Address'])

q1 = """SELECT ID FROM df """

print(ps.sqldf(q1, locals()))

     ID
0  1234
1  1234
2  1233
3  1233

Гораздо лучшим решением является использование duckdb

      pip install duckdb
      import pandas as pd
import duckdb
test_df = pd.DataFrame.from_dict({"i":[1, 2, 3, 4], "j":["one", "two", "three", "four"]})

duckdb.query("SELECT * FROM test_df where i>2").df() # returns a result dataframe

Улучшение производительности по сравнению с pandasql: тестовые данные желтых такси Нью-Йорка ~ 120 МБ данных csv

      nyc = pd.read_csv('https://s3.amazonaws.com/nyc-tlc/trip+data/yellow_tripdata_2021-01.csv',low_memory=False)
      from pandasql import sqldf
pysqldf = lambda q: sqldf(q, globals())
      pysqldf("SELECT * FROM nyc where trip_distance>10")
# wall time 16.1s
      duckdb.query("SELECT * FROM nyc where trip_distance>10").df()
# wall time 183ms

Улучшение скорости примерно в 100 раз

В этой статье приводятся подробные сведения и утверждается, что 1000-кратное улучшение по сравнению с pandasql: https://duckdb.org/2021/05/14/sql-on-pandas.html.

Через некоторое время я понял, что самый простой способ - просто сделать

from pandasql import sqldf

output = sqldf("select * from df")

Работает как шарм, где dfэто фреймворк pandas. Вы можете установить pandasql: https://pypi.org/project/pandasql/

Ты можешь использовать DataFrame.query(condition) вернуть подмножество соответствия фрейма данных condition как это:

df = pd.DataFrame(np.arange(9).reshape(3,3), columns=list('ABC'))
df
   A  B  C
0  0  1  2
1  3  4  5
2  6  7  8

df.query('C < 6')
   A  B  C
0  0  1  2
1  3  4  5


df.query('2*B <= C')
   A  B  C
0  0  1  2


df.query('A % 2 == 0')
   A  B  C
0  0  1  2
2  6  7  8

Это в основном тот же эффект, что и оператор SQL, за исключением SELECT * FROM df WHERE подразумевается.

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

Или вы можете использовать инструменты, которые делают то, что у них лучше всего:

  1. Установить postgresql

  2. Подключитесь к базе данных:

из sqlalchemy import create_engine
import urllib.parse
engconnect = "{0}: // {1}:{2}@{3}:{4} / {5}".format (dialect, user_uenc, pw_uenc, host, port, dbname)
dbengine = create_engine(engconnect)
database = dbengine.connect()

  1. Выгрузить фрейм данных в postgres

df.to_sql('mytablename', база данных, if_exists='replace')

  1. Напишите свой запрос со всеми вложениями SQL, с которыми может справиться ваш мозг.

myquery = "выбрать отдельный * из mytablename"

  1. Создайте фрейм данных, выполнив запрос:

newdf = pd.read_sql(myquery, база данных)

Я думаю лучшее решение чем pandassqlбудет duckdb. Способ, которым он обрабатывает сопоставление имени таблицы с объектом фрейма данных, немного чище, imo. Однако я не оценивал производительность.

Также есть FugueSQL.

      pip install fugue[sql]
      import pandas as pd
from fugue_sql import fsql

comics_df = pd.DataFrame({'book': ['Secret Wars 8',
                                   'Tomb of Dracula 10',
                                   'Amazing Spider-Man 252',
                                   'New Mutants 98',
                                   'Eternals 1',
                                   'Amazing Spider-Man 300',
                                   'Department of Truth 1'],
                          'publisher': ['Marvel', 'Marvel', 'Marvel', 'Marvel', 'Marvel', 'Marvel', 'Image'],
                          'grade': [9.6, 5.0, 7.5, 8.0, 9.2, 6.5, 9.8],
                          'value': [400, 2500, 300, 600, 400, 750, 175]})

# which of my books are graded above 8.0?
query = """
SELECT book, publisher, grade, value FROM comics_df
WHERE grade > 8.0
PRINT
"""

fsql(query).run()

Выход

      PandasDataFrame
book:str                                                      |publisher:str|grade:double|value:long
--------------------------------------------------------------+-------------+------------+----------
Secret Wars 8                                                 |Marvel       |9.6         |400       
Eternals 1                                                    |Marvel       |9.2         |400       
Department of Truth 1                                         |Image        |9.8         |175       
Total count: 3

использованная литература

https://fugue-tutorials.readthedocs.io/tutorials/beginner/beginner_sql.html

https://www.kdnuggets.com/2021/10/query-pandas-dataframes-sql.html

Другим решением является RBQL , который предоставляет SQL-подобный язык запросов, который позволяет использовать выражение Python внутри операторов SELECT и WHERE. Он также обеспечивает удобный %rbqlволшебная команда для использования в Jupyter/IPyhon:

      # Get some test data:
!pip install vega_datasets
from vega_datasets import data
my_cars_df = data.cars()
# Install and use RBQL:
!pip install rbql
%load_ext rbql
%rbql SELECT * FROM my_cars_df WHERE a.Horsepower > 100 ORDER BY a.Weight_in_lbs DESC

В этом примере my_cars_dfпредставляет собой кадр данных Pandas.

Вы можете попробовать это в этом демонстрационном блокноте Google Colab.

Другие вопросы по тегам