Как выбрать фрейм данных Pandas с дополнительным условием, которое не изменит результаты?

У меня есть такой фрейм данных:

валюта дисплейсимвол фиги в микрофон поделитьсяКлассFIGI символ тип 0 доллар США GDNRW BBG014HVCMB9 Никто XNAS GDNRW Эквити WRT 1 доллар США ДЧПФ BBG00D8RQQS7 Никто OOTC BBG001SG1ZV8 ДЧПФ Обыкновенные акции 2 доллар США РАЙ ББГ0142ККР10 Никто АРККС ББГ0142ККСД5 РАЙ ЭТП 3 доллар США ТРНИФ ББГ01ФЗС3РЗ4 Никто OOTC BBG00M1B7Y30 ТРНИФ Закрытый фонд 4 доллар США ПОТН BBG000BXHT20 Никто OOTC ББГ001С7БТВ1 ПОТН Обыкновенные акции ... ... ... ... ... ... ... ... ... 28030 доллар США АС BBG000BCMDR8 Никто XNYS BBG001S5NYW0 АС ДОПОГ 28031 доллар США ECCC BBG011DWM8Z1 Никто XNYS ECCC ОБЩЕСТВЕННЫЙ 28032 доллар США БЗЛФФ BBG000C0V028 Никто OOTC ББГ001С61С32 БЗЛФФ Обыкновенные акции 28033 доллар США ДРЕВ BBG00KLHY7D7 Никто XNAS BBG00KLHY836 ДРЕВ ЭТП 28034 доллар США АХАХФ BBG00CSP14G0 Никто OOTC BBG001S9YD10 АХАХФ Обыкновенные акции

Я хочу выбрать несколько строк по нескольким условиям, например:

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, которое могло бы соответствовать моей потребности?


Редактировать:

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

1
0
56
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

ИМХО, комментарии не должны быть частью кода, поэтому я бы максимально старался не делать то, о чем вы просите. Если вы должны нарезать фрейм данных с другим списком условий, почему бы не составить такую ​​​​функцию:

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])

проголосуйте за «ИМХО, комментарии не должны быть частью кода», но, тем не менее, это интересный вопрос

cs95 11.04.2023 22:09

Спасибо, но это только в Jupyter Notebook для исследования данных (игровая площадка). Я не буду развертывать этот код.

Xaree Lee 11.04.2023 22:14

Хотя я согласен с @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


Надеюсь, это то, что вы искали.

Как просто закомментировать первое условие без ошибки?

Xaree Lee 12.04.2023 01:24

Вы можете снова создать mask_false и использовать его в качестве первого ввода для набора настраиваемых условий, например: df[(mask_true) & ((mask_false) | (df['type'] == 'ETP') | (df['mic'] == 'OOTC'))] Просто обратите внимание, что когда вы захотите удалить все настраиваемые условия, вам нужно будет закомментировать весь блок настраиваемых условий. (все после &)

mcvincekova 12.04.2023 08:45
Ответ принят как подходящий

У меня появилась идея, создав для этого вспомогательную функцию:

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>. Лично я предпочитаю вместо этого определять «красиво» именованные маски, хранящиеся в переменных, потому что я могу легко повторно использовать их в любом месте кода, но это кажется хорошим небольшим решением для того, что вы хотите сделать.

mcvincekova 12.04.2023 16:58

Другие вопросы по теме