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






Вы можете использовать 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)))
Блестящий. Спасибо
Если бы в первой записи было сказано, скажем, «Бла-бла-бла-бла-бла», как вы могли бы указать оба этих слова в столбце с? В настоящее время у меня возникла эта проблема, когда я набираю несколько слов в своем списке поиска и хотел бы записать их все, предпочтительно через запятую.
Вы можете использовать:
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, скажем, через запятую?
Вы также можете сделать:
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'» - есть идеи, почему это может быть?
Замените x.split на str(x).split
Когда я делаю эту замену, теперь я получаю сообщение об ошибке TypeError: объект 'builtin_function_or_method' не является итерируемым.
Какой тип данных у вашего столбца и есть ли пропущенные значения?
Существует одно пустое значение, которое автоматически заполняется nan при импорте. Должен ли я заполнить его чем-то другим? Когда я делаю df.dtypes, столбец «b» говорит «объект». Единственная манипуляция, выполняемая с этим столбцом, — это str.upper() при импорте.
Можете ли вы сделать df['b'].fillna('', inplace=True) перед применением функции?
Я знаю, что больше получаю ошибку, используя df['b'].fillna('', inplace=True), однако 'c' вообще не заполняется, хотя в моем списке поиска есть слова в 'b'. Может быть, это потому, что некоторые элементы в моем списке поиска представляют собой фразы, а не отдельные слова?
Вам не нужен дополнительный импорт,
df.b.str.extract('(?i)({0})'.format('|'.join(search_list)))работает просто отлично