Фильтруйте пандас-фрейм данных со словарем с различными функциями - PullRequest
0 голосов
/ 24 октября 2018

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

   a    b    c
0  5    foo  2
1  5    bar  3
2  4    foo  2
3  5    test 1
4  4    bar  7

Предположим, я хочу фильтр типа

df[(df['a'] == 5) & (~df['b'].isin(['foo','bar'])) & (df['c'].isin(range(5)))]

или, может быть, что-то вроде df[(df['a'] == 5) & (~df['b'].isin(['test','bar'])) | (df['c'].isin(range(5)))]

но я хочу что-то, что может быть легко подключено в качестве входа, что-то вроде:

def filter_df(filter_kwargs, df):
    # do the filtering here

У меня есть идея, что делать с оператором ==, но я недоумеваю, как сделать более сложныйтакие, как .isin и |.Какой лучший способ сделать это?

Ответы [ 3 ]

0 голосов
/ 24 октября 2018

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

import pandas as pd
df = pd.DataFrame({'a': [5,5,4,5,4], 'b': ['foo','bar','foo','test','bar'],'c': [2,3,2,1,7]})

Пример 1 - то же самое, что вы указали, но разделено и, таким образом, более читабельно:

mask_1 = (df['a'] == 5) & \
        (~df['b'].isin(['foo','bar'])) & \
        (df['c'].isin(range(5)))

print(df.loc[mask_1])

Пример 2 - использование лямбда-функций, поэтому их использование является стандартным, поскольку условия выглядят как-то иначе (==, не in, in,>, <и т. Д.): </h1> mask_2 = (df['a'].apply(lambda x: x == 5)) & \ (df['b'].apply(lambda x: x not in ['foo', 'bar'])) & \ (df['c'].apply(lambda x: x in range(5))) print(df.loc[mask_2]) Пример 3 - вдохновленный ответом Б. Хеля и более общим

def filter_df(filter_kwargs, df):
    l = len(filter_kwargs)

    for i, cond in enumerate(filter_kwargs):
        eval_cond = df[cond[0]].apply(lambda x: eval("x " + cond[1]))

        if i == 0:
            mask = eval_cond

        elif i+1 == l:
            break

        else:
            mask = eval('mask' + filter_kwargs[i-1][2] + 'eval_cond')

    return df.loc[mask]

# Format for each condition [[column_name, condition, AND_OR],...]
filter_kwargs = [['a', '==5', '&'],['b', 'not in ["foo", "bar"]','&'], ['c', 'in range(5)','|']]    
print(filter_df(filter_kwargs,df))
0 голосов
/ 24 октября 2018

Предположим, что у вас есть эта преамбула

import pandas as pd
df = pd.DataFrame({'a': [5,5,4,5,4], 'b': ['foo','bar','foo','test','bar'],'c': [2,3,2,1,7]})

и эта функция

def helper_function(df,d):
    x = True
    for (i,k) in enumerate(d):
        y = getattr(df[k['key']],k['function'])(k['values'])
        if k['isnot']:
            y = getattr(getattr(y,'__ne__'),'__self__')
        if i == 0:
            x = y
        else:
            x = getattr(x,k['left_connector'])(y)
    return x

Теперь вы можете создать список словарей

di = [
    {
        'key': 'a',
        'function': 'isin',
        'isnot': False,
        'values': [5],
        'left_connector': "__and__"
    },
    {
        'key': 'b',
        'function': 'isin',
        'isnot': True,
        'values': ['test','bar'],
        'left_connector': "__and__"
    },
    {
        'key': 'c',
        'function': 'isin',
        'isnot': False,
        'values': [0,1,2,3],
        'left_connector': "__or__"
    },
]

и использовать этукод для фильтрации

df[helper_function(df,di)]

Поскольку вы используете только функции панд, вы сохраняете производительность панд.

0 голосов
/ 24 октября 2018

Это идея решения

import pandas as pd

df = pd.DataFrame({'a': [5,5,4,5,4], 'b': ['foo','bar','foo','test','bar'],'c': [2,3,2,1,7]})


def helper_function(df, *argv):
    x = True
    y = "and"
    for (i,arg) in enumerate(argv):
        if (i % 2 == 1):
            y = arg
        else:
            if (y == "and"):
                x = x & df[arg[0]].isin(arg[1])
            else:
                x = x | df[arg[0]].isin(arg[1])
    return df[x]

print(helper_function(df, ['a',[5]],"and",['b',['test','bar']],"and",['c',[0,1,2]]))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...