Подтвердить что ты не робот

Выбор между несколькими столбцами с помощью python pandas?

У меня есть dataframe df в pandas, который был создан с использованием pandas.read_table из файла csv. Блок данных имеет несколько столбцов и индексируется одним из столбцов (что уникально, поскольку каждая строка имеет уникальное значение для этого столбца, используемого для индексирования.)

Как я могу выбрать строки моего фрейма данных на основе "сложного" фильтра, применяемого к нескольким столбцам? Я могу легко выбрать срез блока данных, где столбец colA больше 10, например:

df_greater_than10 = df[df["colA"] > 10]

Но что, если мне нужен фильтр вроде: выберите срез df, где любой из столбцов больше 10?

Или где значение для colA больше 10, но значение для colB меньше 5?

Как они реализованы в pandas? Спасибо.

4b9b3361

Ответ 1

Я рекомендую вам задать эти вопросы в списке рассылки, но в любом случае это все еще очень плохое дело, работающее с базовые массивы NumPy. Например, чтобы выбрать строки, где значение в любом столбце превышает, например, 1,5 в этом примере:

In [11]: df
Out[11]: 
            A        B        C        D      
2000-01-03 -0.59885 -0.18141 -0.68828 -0.77572
2000-01-04  0.83935  0.15993  0.95911 -1.12959
2000-01-05  2.80215 -0.10858 -1.62114 -0.20170
2000-01-06  0.71670 -0.26707  1.36029  1.74254
2000-01-07 -0.45749  0.22750  0.46291 -0.58431
2000-01-10 -0.78702  0.44006 -0.36881 -0.13884
2000-01-11  0.79577 -0.09198  0.14119  0.02668
2000-01-12 -0.32297  0.62332  1.93595  0.78024
2000-01-13  1.74683 -1.57738 -0.02134  0.11596
2000-01-14 -0.55613  0.92145 -0.22832  1.56631
2000-01-17 -0.55233 -0.28859 -1.18190 -0.80723
2000-01-18  0.73274  0.24387  0.88146 -0.94490
2000-01-19  0.56644 -0.49321  1.17584 -0.17585
2000-01-20  1.56441  0.62331 -0.26904  0.11952
2000-01-21  0.61834  0.17463 -1.62439  0.99103
2000-01-24  0.86378 -0.68111 -0.15788 -0.16670
2000-01-25 -1.12230 -0.16128  1.20401  1.08945
2000-01-26 -0.63115  0.76077 -0.92795 -2.17118
2000-01-27  1.37620 -1.10618 -0.37411  0.73780
2000-01-28 -1.40276  1.98372  1.47096 -1.38043
2000-01-31  0.54769  0.44100 -0.52775  0.84497
2000-02-01  0.12443  0.32880 -0.71361  1.31778
2000-02-02 -0.28986 -0.63931  0.88333 -2.58943
2000-02-03  0.54408  1.17928 -0.26795 -0.51681
2000-02-04 -0.07068 -1.29168 -0.59877 -1.45639
2000-02-07 -0.65483 -0.29584 -0.02722  0.31270
2000-02-08 -0.18529 -0.18701 -0.59132 -1.15239
2000-02-09 -2.28496  0.36352  1.11596  0.02293
2000-02-10  0.51054  0.97249  1.74501  0.20525
2000-02-11  0.10100  0.27722  0.65843  1.73591

In [12]: df[(df.values > 1.5).any(1)]
Out[12]: 
            A       B       C        D     
2000-01-05  2.8021 -0.1086 -1.62114 -0.2017
2000-01-06  0.7167 -0.2671  1.36029  1.7425
2000-01-12 -0.3230  0.6233  1.93595  0.7802
2000-01-13  1.7468 -1.5774 -0.02134  0.1160
2000-01-14 -0.5561  0.9215 -0.22832  1.5663
2000-01-20  1.5644  0.6233 -0.26904  0.1195
2000-01-28 -1.4028  1.9837  1.47096 -1.3804
2000-02-10  0.5105  0.9725  1.74501  0.2052
2000-02-11  0.1010  0.2772  0.65843  1.7359

Несколько условий должны быть объединены с помощью & или | (и круглых скобок!):

In [13]: df[(df['A'] > 1) | (df['B'] < -1)]
Out[13]: 
            A        B       C        D     
2000-01-05  2.80215 -0.1086 -1.62114 -0.2017
2000-01-13  1.74683 -1.5774 -0.02134  0.1160
2000-01-20  1.56441  0.6233 -0.26904  0.1195
2000-01-27  1.37620 -1.1062 -0.37411  0.7378
2000-02-04 -0.07068 -1.2917 -0.59877 -1.4564

Мне было бы очень интересно иметь какой-то API запросов, чтобы упростить эти вещи

Ответ 2

Существует несколько подходов к сокращению синтаксиса для этого в Pandas, пока он не получит полный API запросов по дороге (возможно, я попытаюсь присоединиться к проекту github и сделать это - разрешения времени, и если никто уже не запустился).

Ниже приведено несколько способов сокращения синтаксиса:

inds = df.apply(lambda x: x["A"]>10 and x["B"]<5, axis=1) 
print df[inds].to_string()

Чтобы полностью решить эту проблему, нужно было бы создать что-то вроде выбора SQL и where clauses в Pandas. Это совсем не тривиально, но один удар, который, как мне кажется, может работать, заключается в использовании встроенного модуля Python operator. Это позволяет вам рассматривать такие вещи, как больше, чем как функции вместо символов. Таким образом, вы можете сделать следующее:

def pandas_select(dataframe, select_dict):

    inds = dataframe.apply(lambda x: reduce(lambda v1,v2: v1 and v2, 
                           [elem[0](x[key], elem[1]) 
                           for key,elem in select_dict.iteritems()]), axis=1)
    return dataframe[inds]

Тогда пример проверки, такой как ваш, должен был бы сделать следующее:

import operator
select_dict = {
               "A":(operator.gt,10),
               "B":(operator.lt,5)                  
              }

print pandas_select(df, select_dict).to_string()

Вы можете еще больше сократить синтаксис путем создания большего количества аргументов в pandas_select для обработки различных общих логических операторов автоматически или путем импорта их в пространство имен с более короткими именами.

Обратите внимание, что вышеприведенная функция pandas_select работает только с логическими и цепочками ограничений. Вам нужно будет изменить его, чтобы получить другое логическое поведение. Или используйте not и законы DeMorgan.

Ответ 3

Функция запроса добавлена ​​в Pandas, так как этот вопрос задавали и отвечали. Пример приведен ниже.

Учитывая этот примерный кадр данных:

periods = 8
dates = pd.date_range('20170101', periods=periods)
rand_df = pd.DataFrame(np.random.randn(periods,4), index=dates, 
      columns=list('ABCD'))

Синтаксис запроса, приведенный ниже, позволит вам использовать несколько фильтров, например предложение WHERE в выражении select.

rand_df.query("A < 0 or B < 0")

Дополнительную информацию см. в Pandas документации.