Python – поиск строки в фрейме данных из списка

У меня есть следующий список:

search_list = ['STEEL','IRON','GOLD','SILVER']

который мне нужно искать в фрейме данных (df):

      a    b             
0    123   'Blah Blah Steel'
1    456   'Blah Blah Blah'
2    789   'Blah Blah Gold'

и вставьте совпадающие строки в новый фрейм данных (newdf), добавив новый столбец с соответствующим словом из списка:

      a    b                   c
0    123   'Blah Blah Steel'   'STEEL'
1    789   'Blah Blah Gold'    'GOLD'

Я могу использовать следующий код для извлечения соответствующей строки:

newdf=df[df['b'].str.upper().str.contains('|'.join(search_list),na=False)]

но я не могу понять, как добавить соответствующее слово из списка в столбец c.

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

Любая помощь или указатели будут очень признательны

Спасибо

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
4
0
4 013
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Вы можете использовать set.intersection, чтобы узнать, какие слова появляются в столбце b:

search_list = set(['STEEL','IRON','GOLD','SILVER'])
df['c'] = df['b'].apply(lambda x: set.intersection(set(x.upper().split(' ')), search_list))

Выход:

     a                b        c
0  123  Blah Blah Steel  {STEEL}
1  456   Blah Blah Blah       {}
2  789   Blah Blah Gold   {GOLD}

Используйте df[df['c'].astype(bool)], если вы хотите избавиться от строк без совпадения

     a                b        c
0  123  Blah Blah Steel  {STEEL}
2  789   Blah Blah Gold   {GOLD}
Ответ принят как подходящий

Вы можете использовать извлекать и отфильтровать те, которые nan (т.е. не совпадают):

search_list = ['STEEL','IRON','GOLD','SILVER']

df['c'] = df.b.str.extract('({0})'.format('|'.join(search_list)), flags=re.IGNORECASE)
result = df[~pd.isna(df.c)]

print(result)

Выход

              a       b      c
123 'Blah  Blah  Steel'  Steel
789 'Blah  Blah   Gold'   Gold

Обратите внимание, что вам необходимо импортировать модуль re, чтобы использовать флаг re.IGNORECASE. В качестве альтернативы вы можете использовать 2 напрямую, что является значением флага re.IGNORECASE.

ОБНОВИТЬ

Как уже упоминалось @user3483203, вы можете сохранить импорт, используя:

df['c'] = df.b.str.extract('(?i)({0})'.format('|'.join(search_list)))

Вам не нужен дополнительный импорт, df.b.str.extract('(?i)({0})'.format('|'.join(search_list))) работает просто отлично

user3483203 06.03.2019 18:19

Блестящий. Спасибо

Big_Daz 07.03.2019 09:57

Если бы в первой записи было сказано, скажем, «Бла-бла-бла-бла-бла», как вы могли бы указать оба этих слова в столбце с? В настоящее время у меня возникла эта проблема, когда я набираю несколько слов в своем списке поиска и хотел бы записать их все, предпочтительно через запятую.

CjV 30.09.2020 23:14

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

search_list = ['STEEL','IRON','GOLD','SILVER']
pat = r'\b|\b'.join(search_list)
pat2 = r'({})'.format('|'.join(search_list))

df_new= df.loc[df.b.str.contains(pat,case=False,na=False)].reset_index(drop=True)
df_new['new_col']=df_new.b.str.upper().str.extract(pat2)
print(df_new)

     a                  b new_col
0  123  'Blah Blah Steel'   STEEL
1  789   'Blah Blah Gold'    GOLD

Один из способов сделать это

def get_word(my_string):
    for word in search_list:
         if word.lower() in my_string.lower():
               return word
    return None

new_df["c"]= new_df["b"].apply(get_word)

Вы также можете сделать что-то вроде

new_df["c"]= new_df["b"].apply(lambda my_string: [word for word in search_list if word.lower() in my_string.lower()][0])

С первым у вас есть возможность сначала добавить столбец c в df, а затем отфильтровать None, а второй выдаст ошибку, если b не содержит ни одного слова.

Вы также можете увидеть этот вопрос: Получить первый элемент из итерации, соответствующий условию

Применение метода из ответа с самым высоким рейтингом даст

new_df["c"]= new_df["b"].apply(lambda my_string: next(word for word in search_list if word.lower() in my_string.lower())

С использованием

s=pd.DataFrame(df.b.str.upper().str.strip("'").str.split(' ').tolist())
s.where(s.isin(search_list),'').sum(1)
Out[492]: 
0    STEEL
1         
2     GOLD
dtype: object
df['New']=s.where(s.isin(search_list),'').sum(1)
df
Out[494]: 
     a                  b    New
0  123  'Blah Blah Steel'  STEEL
1  456   'Blah Blah Blah'       
2  789   'Blah Blah Gold'   GOLD

Здесь решение с конечным результатом, подобным вашему дисплею:

search_list = ['STEEL','IRON','GOLD','SILVER']

def process(x):
    for s in search_list:
        if s in x['b'].upper(): print("'"+ s +"'");return "'"+ s +"'"
    return ''

df['c']= df.apply(lambda x: process(x),axis=1)
df = df.drop(df[df['c'] == ''].index).reset_index(drop=True)

print(df)

выход:

     a                 b        c
0  123  'Blah Blah Steel  'STEEL'
1  789  'Blah Blah Gold'   'GOLD'

Есть ли способ изменить эту функцию, чтобы в столбце b было несколько слов из списка search_list, и все они возвращались бы в столбце c, скажем, через запятую?

CjV 06.10.2020 21:09

Вы также можете сделать:

import pandas as pd

search_list = ('STEEL','IRON','GOLD','SILVER')

df = pd.DataFrame({'a':[123,456,789],'b':['blah blah Steel','blah blah blah','blah blah Gold']})

df.assign(c = df['b'].apply(lambda x: [j for j in x.split() if j.upper() in search_list]))

Обновлено для скорости


import pandas as pd

search_list = set(['STEEL','IRON','GOLD','SILVER'])

df = pd.DataFrame({'a':[123,456,789],'b':['blah blah Steel','blah blah blah','blah blah Gold']})

df.assign(c = lambda d: d['b'].str.upper().str.split().map(lambda x: set(x).intersection(search_list)))

Результаты:

Используя этот ответ, я получаю сообщение об ошибке «Объект 'float' не имеет атрибута 'split'» - есть идеи, почему это может быть?

CjV 06.10.2020 16:17

Замените x.split на str(x).split

Prayson W. Daniel 06.10.2020 18:47

Когда я делаю эту замену, теперь я получаю сообщение об ошибке TypeError: объект 'builtin_function_or_method' не является итерируемым.

CjV 06.10.2020 19:24

Какой тип данных у вашего столбца и есть ли пропущенные значения?

Prayson W. Daniel 06.10.2020 19:31

Существует одно пустое значение, которое автоматически заполняется nan при импорте. Должен ли я заполнить его чем-то другим? Когда я делаю df.dtypes, столбец «b» говорит «объект». Единственная манипуляция, выполняемая с этим столбцом, — это str.upper() при импорте.

CjV 06.10.2020 19:42

Можете ли вы сделать df['b'].fillna('', inplace=True) перед применением функции?

Prayson W. Daniel 06.10.2020 20:05

Я знаю, что больше получаю ошибку, используя df['b'].fillna('', inplace=True), однако 'c' вообще не заполняется, хотя в моем списке поиска есть слова в 'b'. Может быть, это потому, что некоторые элементы в моем списке поиска представляют собой фразы, а не отдельные слова?

CjV 06.10.2020 20:19

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