поиск подстроки pandas, для возврата нескольких значений (пометка ключевым словом) [python]

#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')
  

Это не быстро, и логика вряд ли будет оптимальной, но она выполняет свою работу. Если у кого-то есть более быстрый способ достижения цели, пожалуйста, не стесняйтесь вносить свой вклад 🙂