Фильтрация строк данных данных, если значение в столбце указано в списке значений

У меня есть Python pandas DataFrame rpt:

rpt
<class 'pandas.core.frame.DataFrame'>
MultiIndex: 47518 entries, ('000002', '20120331') to ('603366', '20091231')
Data columns:
STK_ID                    47518  non-null values
STK_Name                  47518  non-null values
RPT_Date                  47518  non-null values
sales                     47518  non-null values

Я могу фильтровать строки, чей идентификатор запаса '600809' выглядит следующим образом: rpt[rpt['STK_ID'] == '600809']

<class 'pandas.core.frame.DataFrame'>
MultiIndex: 25 entries, ('600809', '20120331') to ('600809', '20060331')
Data columns:
STK_ID                    25  non-null values
STK_Name                  25  non-null values
RPT_Date                  25  non-null values
sales                     25  non-null values

и я хочу собрать все строки некоторых акций, например ['600809','600141','600329']. Это означает, что я хочу иметь такой синтаксис:

stk_list = ['600809','600141','600329']

rst = rpt[rpt['STK_ID'] in stk_list] # this does not works in pandas 

Так как pandas не принимать команду выше, как достичь цели?

Ответ 1

Используйте метод isin. rpt[rpt['STK_ID'].isin(stk_list)].

Ответ 2

isin() идеально подходит, если у вас есть список точных совпадений, но если у вас есть список частичных совпадений или подстрок, которые вы ищете, вы можете фильтровать с помощью str.contains и регулярные выражения.

Например, если мы хотим вернуть DataFrame, где все идентификаторы запаса, начинающиеся с '600', затем сопровождаются любыми тремя цифрами:

>>> rpt[rpt['STK_ID'].str.contains(r'^600[0-9]{3}$')] # ^ means start of string
...   STK_ID   ...                                    # [0-9]{3} means any three digits
...  '600809'  ...                                    # $ means end of string
...  '600141'  ...
...  '600329'  ...
...      ...   ...

Предположим теперь, что у нас есть список строк, которые мы хотим, чтобы значения в 'STK_ID' заканчивались, например.

endstrings = ['01$', '02$', '05$']

Мы можем присоединить эти строки с помощью регулярного выражения или символа | и передать строку в str.contains для фильтрации DataFrame:

>>> rpt[rpt['STK_ID'].str.contains('|'.join(endstrings)]
...   STK_ID   ...
...  '155905'  ...
...  '633101'  ...
...  '210302'  ...
...      ...   ...

Наконец, contains может игнорировать регистр (путем установки case=False), позволяя вам быть более общим при указании строк, которые вы хотите сопоставить.

Например,

str.contains('pandas', case=False)

будет соответствовать PANDAS, PANDAS, paNdAs123 и т.д.

Ответ 3

вы также можете использовать диапазоны, используя:

b = df[(df['a'] > 1) & (df['a'] < 5)]

Ответ 4

Вы также можете напрямую query свой DataFrame для этой информации.

rpt.query('STK_ID in (600809,600141,600329)')

Или аналогичным образом найдите диапазоны:

rpt.query('60000 < STK_ID < 70000')

Ответ 5

Данные обрезки с помощью pandas

Для такого кадра данных:

    RPT_Date  STK_ID STK_Name  sales
0 1980-01-01       0   Arthur      0
1 1980-01-02       1    Beate      4
2 1980-01-03       2    Cecil      2
3 1980-01-04       3     Dana      8
4 1980-01-05       4     Eric      4
5 1980-01-06       5    Fidel      5
6 1980-01-07       6   George      4
7 1980-01-08       7     Hans      7
8 1980-01-09       8   Ingrid      7
9 1980-01-10       9    Jones      4

Существует несколько способов выбора или резки данных.

Использование .isin

Наиболее очевидной является функция .isin. Вы можете создать маску, которая дает вам ряд операторов True/False, которые могут применяться к файлу данных следующим образом:

mask = df['STK_ID'].isin([4, 2, 6])

mask
0    False
1    False
2     True
3    False
4     True
5    False
6     True
7    False
8    False
9    False
Name: STK_ID, dtype: bool

df[mask]
    RPT_Date  STK_ID STK_Name  sales
2 1980-01-03       2    Cecil      2
4 1980-01-05       4     Eric      4
6 1980-01-07       6   George      4

Маскировка - это специальное решение проблемы, но не всегда хорошо работает с точки зрения скорости и памяти.

С индексированием

Установив индекс в столбец STK_ID, мы можем использовать встроенный срезающий объект pandas .loc

df.set_index('STK_ID', inplace=True)
         RPT_Date STK_Name  sales
STK_ID                           
0      1980-01-01   Arthur      0
1      1980-01-02    Beate      4
2      1980-01-03    Cecil      2
3      1980-01-04     Dana      8
4      1980-01-05     Eric      4
5      1980-01-06    Fidel      5
6      1980-01-07   George      4
7      1980-01-08     Hans      7
8      1980-01-09   Ingrid      7
9      1980-01-10    Jones      4

df.loc[[4, 2, 6]]
         RPT_Date STK_Name  sales
STK_ID                           
4      1980-01-05     Eric      4
2      1980-01-03    Cecil      2
6      1980-01-07   George      4

Это быстрый способ сделать это, даже если индексирование может занять некоторое время, это экономит время, если вы хотите сделать несколько запросов, подобных этому.

Объединение фреймов данных

Это также можно сделать, объединив данные. Это будет больше соответствовать сценарию, в котором у вас гораздо больше данных, чем в этих примерах.

stkid_df = pd.DataFrame({"STK_ID": [4,2,6]})
df.merge(stkid_df, on='STK_ID')
   STK_ID   RPT_Date STK_Name  sales
0       2 1980-01-03    Cecil      2
1       4 1980-01-05     Eric      4
2       6 1980-01-07   George      4

Примечание

Все вышеперечисленные методы работают, даже если существует несколько строк с тем же 'STK_ID'

Ответ 6

Вы можете использовать query, т.е.:

b = df.query('a > 1 & a < 5')

Ответ 7

Вы также можете добиться аналогичных результатов, используя "запрос" и @:

например:

df = pd.DataFrame({'A': [1, 2, 3], 'B': ['a', 'b', 'f']})
df = pd.DataFrame({'A' : [5,6,3,4], 'B' : [1,2,3, 5]})
list_of_values = [3,6]
result= df.query("A in @list_of_values")
result
   A  B
1  6  2
2  3  3