Как увеличить скорость поиска панд?

Я хотел бы выполнить поиск по ключевым словам в столбце фрейма данных, который называется «строка».

Ключевые слова содержатся в словаре.

Для каждого ключа значение представляет собой массив из нескольких ключевых слов.

Меня беспокоит то, что скорость очень низкая и на это уходит много времени.

Возможно, задействовано много петель, и df.str.contains нельзя использовать.

Как ускорить процесс?

def match(string, keyword):
        m = len(string)
        n = len(keyword)
        idx = string.find(keyword)
        if idx == -1:
            return 0
        if len(re.findall('[a-zA-Z]', string[idx])) > 0:
            if idx > 0:
                if len(re.findall('[a-zA-Z]', string[idx - 1])) > 0:
                    return 0
        if len(re.findall('[a-zA-Z]', string[idx+n-1])) > 0:
            if idx + n < m:
                if len(re.findall('[a-zA-Z]', string[idx + n])) > 0:
                    return 0
        return 1

def match_keyword(df, keyword_dict, name):
        df_new = pd.DataFrame()
        for owner_id, keyword in keyword_dict.items():
            try:
                for index, data in df.iterrows():
                    a = [match(data['string'], word) for word in keyword]
                    t = int(np.sum(a))
                    if t > 0:
                        df_new.loc[index, name+'_'+str(owner_id)] = 1
                    else:
                        df_new.loc[index, name+'_'+str(owner_id)] = 0  
            except:
                df_new[name+'_'+str(owner_id)] = 0
        return df_new.astype(int)

Вход:

  String
0 New Beauty Company is now offering 超級discounts
1 Swimming is good for children and adults
2 Children love food though it may not be good

keywords:{'a':['New', 'is', '超級'], 'b':['Swim', 'discounts', 'good']}

Полученные результаты:

     'New'  'is'  '超級'   result(or relation)
0     1       1      1        1
1     0       1      0        1
2     0       0      0        0

     'Swim'  'discounts'  'good' result(or relation)
0     0          1          0        1
1     0          0          1        1
2     0          0          1        1

Окончательные результаты:

    'a'    'b'
0    1      1
1    1      1
2    0      1

Можете ли вы привести пример ваших входов и ожидаемых результатов?

asongtoruin 12.06.2018 09:21

Алгоритм Pandas является базовым. Вы можете использовать регулярное выражение, но для большого ускорения вам, вероятно, понадобится специальная библиотека, например см. этот ответ.

jpp 12.06.2018 10:17

Спасибо, jpp. Это интересно.

Chan 12.06.2018 10:33
За пределами сигналов Angular: Сигналы и пользовательские стратегии рендеринга
За пределами сигналов Angular: Сигналы и пользовательские стратегии рендеринга
TL;DR: Angular Signals может облегчить отслеживание всех выражений в представлении (Component или EmbeddedView) и планирование пользовательских...
Sniper-CSS, избегайте неиспользуемых стилей
Sniper-CSS, избегайте неиспользуемых стилей
Это краткое руководство, в котором я хочу поделиться тем, как я перешел от 212 кБ CSS к 32,1 кБ (сокращение кода на 84,91%), по-прежнему используя...
1
3
48
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я считаю, что нужен str.contains в цикле по dict с word bondaries по \b с соединением по | для регулярного выражения OR:

for k, v in keywords.items():
    pat = '|'.join(r"\b{}\b".format(x) for x in v)
    #print (pat)
    df[k] = df['String'].str.contains(pat).astype(int)

print (df)
                                         String  a  b
0  New Beauty Company is now offering discounts  1  1
1      Swimming is good for children and adults  1  1
2  Children love food though it may not be good  0  1

При необходимости также столбцы по каждому значению и создать MultiIndex в столбцах:

df = df.set_index('String')
for k, v in keywords.items():
    for x in v:
        df[(k, x)] = df.index.str.contains(x).astype(int)

df.columns = pd.MultiIndex.from_tuples(df.columns)
print (df)
                                               a       b               
                                             New is Swim discounts good
String                                                                 
New Beauty Company is now offering discounts   1  1    0         1    0
Swimming is good for children and adults       0  1    1         0    1
Children love food though it may not be good   0  0    0         0    1

И тогда можно получить max по MultiIndex:

df = df.max(axis=1, level=0)
print (df)
                                              a  b
String                                            
New Beauty Company is now offering discounts  1  1
Swimming is good for children and adults      1  1
Children love food though it may not be good  0  1

Спасибо, Джезраэль. А если есть китайские иероглифы?

Chan 12.06.2018 10:32

@Chan - Сложный вопрос, правда, понятия не имею. Но тогда второе решение должно быть лучше.

jezrael 12.06.2018 10:33

Я не знаком с регулярным выражением. Я поискал в Интернете и обнаружил, что есть (?(?=regex)then|else). Как написать регулярное выражение: если первый символ [a-zA-Z], то поставить первый \b, иначе ничего не поставить. Более того, если последний символ [a-zA-Z], то ставить последний \b, иначе ничего не ставить?

Chan 12.06.2018 11:27

@Chan - К сожалению, у меня такая же проблема со сложным регулярным выражением, возможно, лучше всего создать для этого новый вопрос :( Извините.

jezrael 12.06.2018 11:28

Другие вопросы по теме