February 10, 2022

Сложные запросы к таблице в Pandas

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

Создадим датафрейм следующего вида:

df = pd.DataFrame([['Калашников', 'Павел', 'Москва', 15],
                  ['Авдеева', 'Серафима', 'Новгород', 22], 
                  ['Магомедов', 'Ислам', 'Махачкала', 34],
                  ['Павленко', 'Сергей', 'Киев', 45],
                  ['Ибрагимов', 'Ислам', 'Махачкала', 77],
                  ['Купеев', 'Павел', 'Москва', 21]],columns=['surname' ,'name', 'city', 'age'])
df

Продемонстрируем распространенный способ задания сложного запроса:

df[(df['age']>25)&(df['surname'].isin(['Павленко', 'Ибрагимов']))&(df['name'].str.startswith('И'))]

В данном примере мы ищем лицо старше 25 лет с фамилией из списка и именем, начинающимся с "И". Если бы таблица весила несколько гигабайт на персональном компьютере могло не хватить памяти для обработки запроса, так как при такой индексации Pandas неявно создает несколько временных датафреймов: df['age']>25, df['surname'].isin(['Павленко', 'Ибрагимов']), df['name'].str.startswith('И'), а потом применяет к ним заданную логическую связку (в нашем случае "И"). Это имеет свои плюсы, в частности, ускоряет обработку на малых данных.

Альтернативным способом индексации является использование метода query. Так наш запрос бы выглядел с его применением:

df.query('age>25 & surname.isin(["Павленко", "Ибрагимов"]) & name.str.startswith("И")')

Как можно заметить, внутри метода на столбцы можно ссылаться по их имени. Также предусмотрен способ обращения к переменным пространства имен Python через символ @:

l = ['Павленко', 'Ибрагимов']
name_start = "И"
df.query('age>25 & surname.isin(@l) & name.str.startswith(@name_start)')