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

Это пример фрейма данных, над которым я работаю:

df:

a      b     c
a1  P1,P3  abc
a2  P2,P4  def
a3  P2     ghi   `

Я хочу применить фильтры к нескольким столбцам в кадре данных, в котором есть значения, разделенные запятыми.

Данные фильтра представлены в виде series с именем df_filters, упомянутым ниже:

df_filters:
a    [a1]
b    [P1, P4]`

Данные фильтра содержат фрейм данных column name как string в первом столбце и filter values как list во втором столбце.

Используя указанную выше df_filters фильтруйте фрейм данных df1 и получите следующий результат:

Result1:
a      b     c
a1  P1,P3  abc
a2  P2,P4  def  `

Вывод: для столбца a в df1 учитывайте только те строки со значением a1, а для столбца b учитывайте только те строки, которые содержат значения P1 и P4. В столбце b, строка 1, P1 и P3 - два разных значения с разделением запятыми.

Могу ли я каким-либо образом достичь указанного Result за df?

для ссылки на аналогичный сценарий просмотрите следующую ссылку: Применить список фильтров к фрейму данных, полученному из списка с помощью pandas


person maninekkalapudi    schedule 28.11.2018    source источник
comment
Добро пожаловать в Stackoverflow. Можете ли вы уточнить и кратко написать, в чем вопрос и каковы ожидаемые результаты   -  person min2bro    schedule 28.11.2018
comment
@ min2bro: Я отредактировал вопрос и включил всю необходимую информацию   -  person maninekkalapudi    schedule 28.11.2018


Ответы (2)


Использовать:

df_filters = pd.Series([['a1'], ['P1', 'P4'],['s']], index=['a','b','z'])
print (df_filters)
a        [a1]
b    [P1, P4]
z         [s]
dtype: object

#filter only matched columns
df_filters = df_filters.loc[df_filters.index.intersection(df.columns)]

#convert to set and get intersection of each value
from itertools import repeat
m = [[bool(set(a.split(',')).intersection(b)) for a, b in zip(df[i], repeat(j))] 
      for i, j in df_filters.items()]
print (m)
[[True, False, False], [True, True, False]]

#flatten boolean masks and filter
df = df[pd.np.logical_or.reduce(m)]
print (df)
    a      b    c
0  a1  P1,P3  abc
1  a2  P2,P4  def
person jezrael    schedule 29.11.2018
comment
Привет @jezrael, спасибо за ответ. Я попробую сегодня и дам вам знать. Вы знаете, что старое решение, на которое вы ответили (упомянули ссылку в этом вопросе), работает нормально после публикации этого вопроса. Я виню VS Code в этой ошибке! - person maninekkalapudi; 29.11.2018

Для каждого значения вы проверяете, существует ли оно в соответствующем списке df_filters. Поскольку столбец может содержать список или отдельный элемент, его также необходимо проверить.
Поскольку это условие немного сложное, я переместил эту логику в отдельную функцию _filter_func.

def _filter_func(x, f_vals_set):
    if not isinstance(x, list):
        # This is needed becouse values in dataframe could be single object or a list of objects
        x = [x]
    # Check if the there is any matching value in filter set
    matching_vals = f_vals_set.intersection(x)
    return len(matching_vals) > 0

conditions = [df[col].apply(lambda x: _filter_func(x, set(f_vals))) for col, f_vals in filters.items()]
df.loc[pd.np.logical_or.reduce(conditions)]
person shanmuga    schedule 28.11.2018
comment
Привет @shanmuga, Спасибо, что ответили. Я не могу четко понять ваше решение, но я попытался его использовать и не смог получить требуемый результат. - person maninekkalapudi; 29.11.2018