#python #python-3.x #pandas #dataframe
#python #python-3.x #pandas #фрейм данных
Вопрос:
Допустим, у меня есть 2 фрейма данных pandas:
df1 — содержит столбец с различными фразами:
keyword
---
foo
bar
baz
qux
quux
foo bar
foo baz
df2 — содержит 1 столбец со списком слов и столбцы с категориями
keyword tag1 tag2
---
foo abc def
bar 123 456
baz abc def
qux
Я ищу быстрый способ присвоить теги df2
фразам in df1
таким образом, чтобы, если значения в df1['A']
совпадают / содержат одно или несколько значений in df2['A']
, соответствующие теги in df2
будут добавлены в новые столбцы df1
.
Вывод должен выглядеть следующим образом:
keyword tag1 tag2
---
foo abc def
bar 123 456
baz abc def
qux
quu
foo bar abc,123 def,456
foo baz abc def
foo bar baz abc,123 def,456
Вы заметите в выводе выше, что:
qux
теги пусты, так как в них нет теговdf2
quux
теги пусты, поскольку они не появились вdf2
,foobar
было применено 2 набора тегов,- каждый тег был подписан только один раз (см.
foobaz
Иfoobarbaz
)
Фактические фреймы данных будут намного больше (по горизонтали / вертикали). Я искал ответы, но не нашел того, что мне нужно. Если вы знаете что-нибудь важное, пожалуйста, предоставьте ссылки. Если вы хотите, чтобы я что-нибудь прояснил, просто скажите.
Заранее спасибо! 🙂
Ответ №1:
Я кое-что понял в следующих строках:
tags = df2.loc[:,df2.columns.str.contains('tag')].columns # create list of new columns (allows # of columns to vary)
# format tags for potential errors
df2 = df2.replace(r'^s $', np.nan, regex=True) # adjust cells containing only whitespace to NaN
df2 = df2.replace(r'^s |s $', '', regex=True) # remove leading and trailing whitespace
df2 = df2.dropna(subset=tags, how='all').reset_index(drop=True) # drop ngrams from df2 that have no tags
# add tag columns from d2 to df1
for i in tags:
df1[i] = [[] for x in range(len(df1))] # create new columns in df1, adding empty list to each cell
# add tags from df2 to df1
cols = len(tags)
for i in tags:
print(f'nStarting column "{i}"...') # progress tracker
groups = df2.groupby(i, as_index=False).aggregate(lambda x : list(x)) # groupby 'tag' column and create list of corresponding keywords (to limit the iterations)
groups = groups[['keyword',i]]
groups = groups.dropna(axis=0, how='any') # drop rows with no tags
rows = len(groups)
for j in groups.index:
tag = groups[i][j]
if tag not in [np.nan, 'nan', '']: # skip empty tags
print (f'{j 1} of {rows} - {tag}') # progress tracker
substrings = groups['keyword'][j]
if len(substrings) > 1:
substrings = '|'.join(substrings) # create string from list for regex later
else:
substrings = substrings[0] # else get element from list as str
match = df1['keyword'].str.contains(substrings, regex=True, case=False)
df1.loc[match, i] = df1[i].apply(lambda x: list(dict.fromkeys(x [tag]))) # 'list(dict.fromkeys())' ensures the resulting list contains only unique values
print('nFormatting tags...')
for i in tags:
df1[i] = df1[i].str.join(',') # makes lists into strings separated by ','
print('nTagging complete')
Это не быстро, и логика вряд ли будет оптимальной, но она выполняет свою работу. Если у кого-то есть более быстрый способ достижения цели, пожалуйста, не стесняйтесь вносить свой вклад 🙂