У меня есть такой фрейм данных:
Я хочу выбрать несколько строк по нескольким условиям, например:
dirty_data = df[
(df['description'] == '') # condition 1
| (df['description'] == 'Test') # condition 2
| (df['shareClassFIGI'] == '') # condition 3
| ...
]
Такое расположение кода позволяет мне закомментировать некоторые условия для легкого просмотра:
dirty_data = df[
(df['description'] == '')
# | (df['description'] == 'Test')
# | (df['shareClassFIGI'] == '')
| ...
]
но комментирование первого условия вызывает ошибку:
dirty_data = df[
# (df['description'] == '')
| (df['description'] == 'Test') # Invalid syntax! There is a `|` before the first condition
| (df['shareClassFIGI'] == '')
| ...
]
Я добавляю False
перед всеми условиями, и это решает мою проблему:
dirty_data = df[
False
| (df['description'] == '') # Now I can comment out this line without errors
| (df['description'] == 'Test')
| (df['shareClassFIGI'] == '')
| ...
]
Но иногда я хочу закомментировать все условия, чтобы показать и проверить исходный фрейм данных, но это вызывает KeyError
:
dirty_data = df[
False # KeyError: False
# | (df['description'] == '')
# | (df['description'] == 'Test')
# | (df['shareClassFIGI'] == '')
# | ...
]
dirty_data = df[False]
неверный синтаксис.
Есть ли выражение для замены False
, которое могло бы соответствовать моей потребности?
Редактировать:
Я думаю, что мой исходный логический код был неправильным. Нелегко вернуть истинность, если нет условия, сделать ее ложной, если есть какое-либо условие.
ИМХО, комментарии не должны быть частью кода, поэтому я бы максимально старался не делать то, о чем вы просите. Если вы должны нарезать фрейм данных с другим списком условий, почему бы не составить такую функцию:
def slice_with_cond(df: pd.DataFrame, conditions: List[pd.Series]=None) -> pd.DataFrame:
if not conditions:
return df
# or use `np.logical_or.reduce` as in cs95's answer
agg_conditions = False
for cond in conditions:
agg_conditions = agg_conditions | cond
return df[agg_conditions]
Затем вы можете нарезать:
# return df
slice_with_cond(df)
# return a slice
slice_with_cond(df, [cond1])
Спасибо, но это только в Jupyter Notebook для исследования данных (игровая площадка). Я не буду развертывать этот код.
Хотя я согласен с @Quang Hoang, вот один из вариантов, как добиться того, чего вы хотите:
True
длины len(df.index)
, которая, следовательно, всегда будет выбирать все данные&
вместо |
Это должно гарантировать, что всякий раз, когда вы удаляете (или комментируете) все условия, кроме первого, будет выбран весь фрейм данных.
Пример:
import pandas as pd
data = {
'currency': ['USD', 'USD', 'USD', 'USD', 'USD'],
'displaySymbol': ['GDNRW', 'DCHPF', 'RAYE', 'TRNIF', 'POTN'],
'figi': ['BBG014HVCMB9', 'BBG00D8RQQS7', 'BBG0142KKR10', 'BBG01FZS3RZ4', 'BBG000BXHT20'],
'isin': ['None', 'None', 'None', 'None', 'None'],
'mic': ['XNAS', 'AHA', 'ARCX', 'OOTC', 'OOTC'],
'shareClassFIGI': ['', 'BBG001SG1ZV8', 'BBG0142KKSD5', 'BBG00M1B7Y30', 'BBG001S7BTV1'],
'symbol': ['GDNRW', 'DCHPF', 'RAYE', 'TRNIF', 'POTN'],
'type': ['Equity WRT', 'Common Stock', 'ETP', 'Closed-End Fund', 'Common Stock']
}
df = pd.DataFrame(data)
mask_true = [True] * len(df.index)
Выбор данных с определенными условиями:
df[
(mask_true) # make sure to return all data
& ( # define remaining conditions
(df['type'] == 'ETP')
| (df['mic'] == 'OOTC')
)
]
Выход
currency displaySymbol figi isin mic shareClassFIGI symbol type
2 USD RAYE BBG0142KKR10 None ARCX BBG0142KKSD5 RAYE ETP
3 USD TRNIF BBG01FZS3RZ4 None OOTC BBG00M1B7Y30 TRNIF Closed-End Fund
4 USD POTN BBG000BXHT20 None OOTC BBG001S7BTV1 POTN Common Stock
Выбор данных со всеми удаленными условиями, но с логической маской по умолчанию
df[
(mask_true) # make sure to return all data
# & ( # define remaining conditions
# (df['type'] == 'ETP')
# | (df['mic'] == 'OOTC')
# )
]
Выход
currency displaySymbol figi isin mic shareClassFIGI symbol type
0 USD GDNRW BBG014HVCMB9 None XNAS GDNRW Equity WRT
1 USD DCHPF BBG00D8RQQS7 None AHA BBG001SG1ZV8 DCHPF Common Stock
2 USD RAYE BBG0142KKR10 None ARCX BBG0142KKSD5 RAYE ETP
3 USD TRNIF BBG01FZS3RZ4 None OOTC BBG00M1B7Y30 TRNIF Closed-End Fund
4 USD POTN BBG000BXHT20 None OOTC BBG001S7BTV1 POTN Common Stock
Надеюсь, это то, что вы искали.
Как просто закомментировать первое условие без ошибки?
Вы можете снова создать mask_false
и использовать его в качестве первого ввода для набора настраиваемых условий, например: df[(mask_true) & ((mask_false) | (df['type'] == 'ETP') | (df['mic'] == 'OOTC'))]
Просто обратите внимание, что когда вы захотите удалить все настраиваемые условия, вам нужно будет закомментировать весь блок настраиваемых условий. (все после &
)
У меня появилась идея, создав для этого вспомогательную функцию:
def hp(df, empty_selection, boolean_indexing):
if type(boolean_indexing) == pd.core.series.Series:
return boolean_indexing
if type(boolean_indexing) == bool:
return [empty_selection] * len(df)
raise Exception('boolean_indexing type error')
# Show all data (without any condition)
dirty_data = df[ hp(df, True, False
# | (df['description'] == '') # condition 1
# | (df['description'] == 'Test') # condition 2
# | (df['shareClassFIGI'] == '') # condition 3
# | ...
)]
# Show the results for condition 3
dirty_data = df[ hp(df, True, False
# | (df['description'] == '') # condition 1
# | (df['description'] == 'Test') # condition 2
| (df['shareClassFIGI'] == '') # condition 3
# | ...
)]
Чтобы упростить код и улучшить читаемость, функцию можно добавить в класс DataFrame:
def search(df, boolean_indexing):
if type(boolean_indexing) == pd.core.series.Series:
return df[boolean_indexing]
if type(boolean_indexing) == bool:
return df
raise Exception('boolean_indexing type error')
# Show all data (without any condition)
r = search(df, False
# | (df['description'] == '') # condition 1
# | (df['description'] == 'Test') # condition 2
# | (df['shareClassFIGI'] == '') # condition 3
)
# Show the results for condition 3
r = search(df, False
# | (df['description'] == '') # condition 1
# | (df['description'] == 'Test') # condition 2
| (df['shareClassFIGI'] == '') # condition 3
)
# You can also bind the function to the class DataFrame
pd.core.frame.DataFrame.search = search
# Show the results for condition 3
r = df.search(False
# | (df['description'] == '') # condition 1
# | (df['description'] == 'Test') # condition 2
| (df['shareClassFIGI'] == '') # condition 3
)
Теперь расположение кода похоже на строку поиска. По умолчанию отображаются все данные и отображаются результаты при наличии любого входного условия. Вы можете включить/выключить любое условие. Вы можете попробовать любое условие, просто добавив строку в код без написания стандартного кода (создав ячейку Jupyter Notebook, снова напишите df[...]
), и оставьте условие в истории поиска, просто закомментировав его. Таким образом, вы можете сосредоточиться на условиях и результатах, чтобы понять данные.
Какие-либо предложения?
Хорошо, если это подходит для вашего варианта использования :) - я бы просто предложил isinstance для проверки типов вместо type == <something>
. Лично я предпочитаю вместо этого определять «красиво» именованные маски, хранящиеся в переменных, потому что я могу легко повторно использовать их в любом месте кода, но это кажется хорошим небольшим решением для того, что вы хотите сделать.
проголосуйте за «ИМХО, комментарии не должны быть частью кода», но, тем не менее, это интересный вопрос