Python Pandas - объединение на основе подстроки в строке

У меня есть 2 кадра данных в следующем формате:

df_search

SEARCH
part1
anotherpart
onemorepart


df_all

FILE             EXTENSION    PATH
part1_1         .prt    //server/folder1/part1_1
part1_2         .prt    //server/folder2/part1_2
part1_2         .pdf    //server/folder3/part1_2
part1_3         .prt    //server/folder2/part1_3
anotherpart_1   .prt    //server/folder1/anotherpart_1
anotherpart_2   .prt    //server/folder3/anotherpart_2
anotherpart_3   .prt    //server/folder2/anotherpart_3
anotherpart_3   .cgm    //server/folder1/anotherpart_3
anotherpart_4   .prt    //server/folder3/anotherpart_4
onemorepart_1   .prt    //server/folder2/onemorepart_1
onemorepart_2   .prt    //server/folder1/onemorepart_2
onemorepart_2   .dwg    //server/folder2/onemorepart_2
onemorepart_3   .prt    //server/folder1/onemorepart_3
onemorepart_4   .prt    //server/folder1/onemorepart_4

Полный df_search имеет 15 000 элементов. У df_all есть 550 000 предметов. Я пытаюсь объединить два кадра данных на основе строки элемента поиска, находящейся в строке файла. Мой желаемый вывод это:

SEARCH       FILE            EXTENSION  PATH    
part1        part1_1        .prt    //server/folder1/part1_1    
part1        part1_2        .prt    //server/folder2/part1_2    
part1        part1_2        .pdf    //server/folder3/part1_2    
part1        part1_3        .prt    //server/folder2/part1_3    
anotherpart anotherpart_1   .prt    //server/folder1/anotherpart_1  
anotherpart anotherpart_2   .prt    //server/folder3/anotherpart_2  
anotherpart anotherpart_3   .prt    //server/folder2/anotherpart_3  
anotherpart anotherpart_3   .cgm    //server/folder1/anotherpart_3  
anotherpart anotherpart_4   .prt    //server/folder3/anotherpart_4  
onemorepart onemorepart_1   .prt    //server/folder2/onemorepart_1  
onemorepart onemorepart_2   .prt    //server/folder1/onemorepart_2  
onemorepart onemorepart_2   .dwg    //server/folder2/onemorepart_2  
onemorepart onemorepart_3   .prt    //server/folder1/onemorepart_3  
onemorepart onemorepart_4   .prt    //server/folder1/onemorepart_4  

Простое объединение данных не работает, потому что строки никогда не совпадают точно (это всегда подстрока). Я также попробовал следующий метод, основанный на других вопросах здесь на stackru:

df_all[df_all.name.str.contains('|'.join(df_search.search))]

Это дало мне полный список всех найденных элементов в df_all, но я не знаю, какая строка поиска вернула какой результат.

Мне удалось заставить его работать с циклом for, но это медленно (67 минут) с моим набором данных:

super_df = []
for search_item in df_search.search:
     df_entire.loc[df_entire.file.str.contains(search_item), 'search'] = search_item
     temp_df = df_entire[df_entire.file.str.contains(search_item)]
super_df = pd.concat(super_df, axis=0, ignore_index=True)

Можно ли сделать это с помощью векторизации для повышения производительности?

Спасибо

2 ответа

Решение

Использование str.extract + insert:

pat = "|".join(df_search.SEARCH)
df_all.insert(0, 'SEARCH', df_all['FILE'].str.extract("(" + pat + ')', expand=False))
print (df_all)
         SEARCH           FILE EXTENSION                            PATH
0         part1        part1_1      .prt        //server/folder1/part1_1
1         part1        part1_2      .prt        //server/folder2/part1_2
2         part1        part1_2      .pdf        //server/folder3/part1_2
3         part1        part1_3      .prt        //server/folder2/part1_3
4   anotherpart  anotherpart_1      .prt  //server/folder1/anotherpart_1
5   anotherpart  anotherpart_2      .prt  //server/folder3/anotherpart_2
6   anotherpart  anotherpart_3      .prt  //server/folder2/anotherpart_3
7   anotherpart  anotherpart_3      .cgm  //server/folder1/anotherpart_3
8   anotherpart  anotherpart_4      .prt  //server/folder3/anotherpart_4
9   onemorepart  onemorepart_1      .prt  //server/folder2/onemorepart_1
10  onemorepart  onemorepart_2      .prt  //server/folder1/onemorepart_2
11  onemorepart  onemorepart_2      .dwg  //server/folder2/onemorepart_2
12  onemorepart  onemorepart_3      .prt  //server/folder1/onemorepart_3
13  onemorepart  onemorepart_4      .prt  //server/folder1/onemorepart_4

Я сделаю это так:

df_all['SEARCH'] = ''
for val in df_search.SEARCH:
    df_all.loc[df_all['FILE'].str.match(val), 'SEARCH'] = val
Другие вопросы по тегам