замените циклы векторными операциями

#python #pandas

Вопрос:

Это пример проблемы, которую мне нужно решить. У меня есть 2 таблицы, и я должен найти подстроку(dff2) в строке(dff). И если подстрока в строке существует, добавьте эту строку в выходной кадр данных. Проблема в том, что я написал код с использованием циклов, и он работает слишком медленно для тысяч строк. Как я мог переписать код, используя методы pandas?

 data = {'long string column': ['aaaabbbbccccdddd', 'bbbbccccddddeeee','ccccddddeeeeffff','ddddeeeeffffgggg'],}
dff = pd.DataFrame(data, columns = ['long string column'])


data2 = {'substring_column': ['aaaa', 'bbbb','cccc','dddd'], 'status': ['best', 'good','bad','worst'],}
dff2 = pd.DataFrame(data2, columns = ['substring_column','status'])


df_output = pd.DataFrame()
df_output_small = pd.DataFrame()


for i in range(len(dff2)):
    df_output_small = dff[(dff['long string column'].str.contains(dff2['substring_column'].iloc[i]))]
                          
    df_output_small['status'] = dff2['status'].iloc[i]

    df_output = df_output.append(df_output_small, ignore_index=True)
                          
df_output
 

Ответ №1:

Используйте Series.str.extractall для всех подстрок, а затем справа merge :

 pat = f'({"|".join(dff2["substring_column"])})'
 

Если есть некоторые подстроки, которые должны быть регулярными выражениями, используйте re.escape :

 import re
pat = '|'.join(re.escape(x) for x in dff2['substring_column'])
 

 df = (dff.set_index('long string column', drop=False)['long string column']
         .str.extractall(pat)[0]
         .reset_index(level=1, drop=True)
         .reset_index(name='substring_column'))
df = df.merge(dff2, on='substring_column', how='right')
print (df)
  long string column substring_column status
0   aaaabbbbccccdddd             aaaa   best
1   aaaabbbbccccdddd             bbbb   good
2   bbbbccccddddeeee             bbbb   good
3   aaaabbbbccccdddd             cccc    bad
4   bbbbccccddddeeee             cccc    bad
5   ccccddddeeeeffff             cccc    bad
6   aaaabbbbccccdddd             dddd  worst
7   bbbbccccddddeeee             dddd  worst
8   ccccddddeeeeffff             dddd  worst
9   ddddeeeeffffgggg             dddd  worst
 

Последний substring_column столбец удаления:

 df = df.drop('substring_column', axis=1)
 

Комментарии:

1. Это сработало для примера, который я написал выше, но это вызывает ошибку для подзвенков, таких как «aa(aa» (говорит, что отсутствует»)»). К сожалению, в моей проблеме есть такие глупые подстроки. Как бы я переписал код? P.S. В любом случае спасибо за помощь. И поскольку ваш код работает для wxample, я подтверждаю это!)