Ответ 1
Используйте метод isin
. rpt[rpt['STK_ID'].isin(stk_list)]
.
У меня есть 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 не принимать команду выше, как достичь цели?
Используйте метод isin
. rpt[rpt['STK_ID'].isin(stk_list)]
.
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
и т.д.
вы также можете использовать диапазоны, используя:
b = df[(df['a'] > 1) & (df['a'] < 5)]
Вы также можете напрямую query свой DataFrame для этой информации.
rpt.query('STK_ID in (600809,600141,600329)')
Или аналогичным образом найдите диапазоны:
rpt.query('60000 < STK_ID < 70000')
Для такого кадра данных:
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
. Вы можете создать маску, которая дает вам ряд операторов 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'
Вы можете использовать query
, т.е.:
b = df.query('a > 1 & a < 5')
Вы также можете добиться аналогичных результатов, используя "запрос" и @:
например:
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