як ви фільтруєте кадри даних панд за кількома стовпцями


100

Щоб відфільтрувати кадр даних (df) за одним стовпцем, якщо врахувати дані з чоловіками та жінками, ми можемо:

males = df[df[Gender]=='Male']

Питання 1 - Але що, якщо дані охоплювали кілька років, і я хотів бачити чоловіків лише за 2014 рік?

Іншими мовами я можу зробити щось на зразок:

if A = "Male" and if B = "2014" then 

(за винятком того, що я хочу зробити це і отримати підмножину вихідного кадру даних у новому об'єкті кадру даних)

Питання 2. Як це зробити у циклі та створити об’єкт кадру даних для кожного унікального набору року та статі (тобто df для: 2013-Male, 2013-Female, 2014-Male та 2014-Female

for y in year:

for g in gender:

df = .....

Ви хочете робити фільтрувати його або група його? Якщо ви хочете створити окремий DataFrame для кожного унікального набору року та статі, подивіться на groupby.
BrenBarn

1
Ця відповідь дає вичерпний огляд булевого індексування та логічних операторів у пандах.
cs95

Відповіді:


172

Використовуючи &оператор, не забудьте обернути підзаявки ():

males = df[(df[Gender]=='Male') & (df[Year]==2014)]

Щоб зберегти свої кадри даних у dictциклі for:

from collections import defaultdict
dic={}
for g in ['male', 'female']:
  dic[g]=defaultdict(dict)
  for y in [2013, 2014]:
    dic[g][y]=df[(df[Gender]==g) & (df[Year]==y)] #store the DataFrames to a dict of dict

РЕДАГУВАТИ:

Демо для вашого getDF:

def getDF(dic, gender, year):
  return dic[gender][year]

print genDF(dic, 'male', 2014)

чудова відповідь zhangxaochen - чи можете ви відредагувати свою відповідь, щоб показати внизу, як ви можете зробити цикл for, який створює фрейми даних (з даними року та статі), але додає їх до словника, щоб вони могли отримати доступ пізніше за допомогою мого методу getDF? def GetDF (dict, key): return dict [key]
yoshiserry

@yoshiserry що таке keyу вас getDF? один параметр або набір ключів? будьте конкретними plz;)
zhangxaochen

привіт, це єдиний ключ, лише слово, яке відповідало б статі (чоловікові чи жінці) або року (13, 14). Не знав, що ти можеш мати кортеж ключів. Не могли б ви поділитися прикладом того, коли і як ви б це зробили?
yoshiserry

Ви могли б поглянути на це питання теж. Мені здається, ти міг би на це відповісти. Знову стосується кадрів даних панд. stackoverflow.com/questions/22086619 / ...
yoshiserry

1
Зверніть увагу, що Genderі Yearобоє повинні бути рядками, тобто 'Gender'і 'Year'.
Steven C. Howell

22

Для більш загальних булевих функцій, які ви хотіли б використовувати як фільтр і які залежать від кількох стовпців, ви можете використовувати:

df = df[df[['col_1','col_2']].apply(lambda x: f(*x), axis=1)]

де f - це функція, яка застосовується до кожної пари елементів (x1, x2) з col_1 та col_2 і повертає True або False залежно від будь-якої умови, яку ви хочете (x1, x2).


11

Почніть з pandas 0,13 , це найефективніший спосіб.

df.query('Gender=="Male" & Year=="2014" ')

1
Чому це повинно бути ефективнішим за прийняту відповідь?
Bouncner

@Bouncner просто перевірити це проти високої відповіді.
redreamality

4
Цю відповідь можна покращити, показавши орієнтир
nardeas

8

Якщо хтось задається питанням, який швидший спосіб фільтрування (прийнята відповідь або відповідь від @redreamality):

import pandas as pd
import numpy as np

length = 100_000
df = pd.DataFrame()
df['Year'] = np.random.randint(1950, 2019, size=length)
df['Gender'] = np.random.choice(['Male', 'Female'], length)

%timeit df.query('Gender=="Male" & Year=="2014" ')
%timeit df[(df['Gender']=='Male') & (df['Year']==2014)]

Результати для 100 000 рядків:

6.67 ms ± 557 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
5.54 ms ± 536 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

Результати для 10000 000 рядків:

326 ms ± 6.52 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
472 ms ± 25.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Тож результати залежать від розміру та даних. На моєму ноутбуці query()швидше стає після 500 тис. Рядків. Крім того, пошук рядка в Year=="2014"має непотрібні накладні витрати ( Year==2014швидший).


1
Однак я думаю, що queryсинтаксис є акуратнішим і близьким до SQL, що робить його приємним для даних з тих пір. Вишневе на торті полягає в тому, що це швидше з багатьма рядами :)
csgroen

1

Ви можете створити свою власну функцію фільтру , використовуючи queryв pandas. Тут у вас є фільтрація dfрезультатів за всіма kwargsпараметрами. Не забудьте додати кілька валідаторів ( kwargsфільтрація), щоб отримати власну функцію фільтра df.

def filter(df, **kwargs):
    query_list = []
    for key in kwargs.keys():
        query_list.append(f'{key}=="{kwargs[key]}"')
    query = ' & '.join(query_list)
    return df.query(query)

Дякуємо за елегантне рішення! Я думаю, що це найкраще з усіх інших. Він поєднує ефективність використання запиту з універсальністю використання його як функції.
A Merii,

0

Ви можете фільтрувати за кількома стовпцями (більше двох), використовуючи np.logical_andоператор для заміни &(або np.logical_orдля заміни |)

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

def filter_df(df, filter_values):
    """Filter df by matching targets for multiple columns.

    Args:
        df (pd.DataFrame): dataframe
        filter_values (None or dict): Dictionary of the form:
                `{<field>: <target_values_list>}`
            used to filter columns data.
    """
    import numpy as np
    if filter_values is None or not filter_values:
        return df
    return df[
        np.logical_and.reduce([
            df[column].isin(target_values) 
            for column, target_values in filter_values.items()
        ])
    ]

Використання:

df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [1, 2, 3, 4]})

filter_df(df, {
    'a': [1, 2, 3],
    'b': [1, 2, 4]
})
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.