Есть ли способ сделать этот код быстрее? - PullRequest
1 голос
/ 03 мая 2019

У меня есть датафрейм pandas, содержащий подробности некоторых документов с примерно 4 миллионами записей. Мне нужно найти 50 лучших авторов, которые имеют наибольшее количество публикаций в этом наборе данных. У меня есть два файла, содержащих эти данные, поэтому я должен прочитать оба из них в кадрах данных и сложить их вместе, чтобы получить один кадр данных для работы. Я использовал только столбец автора из фрейма данных, так как есть еще 32 столбца, которые не требуются.

Пока что я придумала следующее решение. Кроме того, это назначение алгоритмов, поэтому я не могу использовать встроенные алгоритмы. В настоящее время я использую словарь для хранения количества публикаций каждого автора, а затем перебираю подсказки, чтобы найти наиболее опубликованных авторов. Кроме того, в одной строке может быть несколько авторов, например 'Auth 1 | Auth 2 | Auth 3 | ' вот почему я разделяю строку.

Я хотел знать, есть ли более быстрый метод для выполнения всего этого. Есть ли способ найти максимум во время цикла данных? Опять же, мне не разрешено использовать встроенные алгоритмы для поиска или сортировки. Любые предложения помогут.

Спасибо.

start_time = ti.default_timer()

only_authors_article = pd.DataFrame(articles['author'])
only_authors_inproceedings = pd.DataFrame(proceedings['author'])
all_authors = only_authors_article.append(only_authors_inproceedings, ignore_index = True)
all_authors = all_authors.dropna(how = 'any')

auth_dict = defaultdict(int)

for auth_list in zip(all_authors['author']):
    auth_list = auth_list[0]

    if '|' in auth_list:
        auths = auth_list.split('|')

        for auth in auths:
            auth_dict[auth] += 1
    else:
        auth_dict[auth_list] += 1


most_pub_authors = []

for i in range(0, 50):
    max_pub_count = 0
    max_pub_auth = None

    for author, pub_count in auth_dict.items(): 
        if pub_count > max_pub_count:
            max_pub_count = pub_count
            max_pub_auth = author

    most_pub_authors.append( (max_pub_auth, max_pub_count) ) 
    del auth_dict[max_pub_auth]

print(most_pub_authors) 


elapsed_time = ti.default_timer() - start_time
print("Total time taken: " + str(elapsed_time))

Редактировать 1: некоторые примеры данных из all_authors

    author
0   Sanjeev Saxena
1   Hans Ulrich Simon
2   Nathan Goodman|Oded Shmueli
3   Norbert Blum
4   Arnold Schönhage
5   Juha Honkala
6   Christian Lengauer|Chua-Huang Huang
7   Alain Finkel|Annie Choquet
8   Joachim Biskup
9   George Rahonis|Symeon Bozapalidis|Zoltán Fülöp...
10  Alex Kondratyev|Maciej Koutny|Victor Khomenko|...
11  Wim H. Hesselink
12  Christian Ronse
13  Carol Critchlow|Prakash Panangaden
14  Fatemeh Ghassemi|Ramtin Khosravi|Rosa Abbasi
15  Robin Milner
16  John Darlington
17  Giuseppe Serazzi|M. Italiani|Maria Calzarossa
18  Vincent Vajnovszki
19  Christian Stahl|Richard Müller 0001|Walter Vogler
20  Luc Devroye
21  K. C. Tan|T. C. Hu
22  William R. Franta
23  Ekkart Kindler
24  Demetres D. Kouvatsos
25  Christian Lengauer|Sergei Gorlatch
26  Roland Meyer
27  Stefan Reisch
28  Erzsébet Csuhaj-Varjú|Victor Mitrana
29  Lila Kari|Manasi S. Kulkarni

Ответы [ 2 ]

1 голос
/ 03 мая 2019

Проблема с этой частью:

for i in range(0, 50):
    . . .
    for author, pub_count in auth_dict.items(): 
        . . .

Это повторяет весь набор данных 50 раз.

Вместо этого вы можете использовать накопительный подход: иметь список топ-50 авторов, сначала заполняют его первыми 50 авторами и перебирают auth_dict один раз, заменяя самый нижний элемент, если вы нашли тот, который выше этого.

Примерно так:

top_authors = []
lowest_pub_count = 0
top_n = 50
for author, pub_count in auth_dict.items():
    if pub_count > lowest_pub_count:        # found element that is larger than the smallest in top-N so far
        if len(top_authors) < top_n:        # not reached N yet - just append to the list
            top_authors.append([author, pub_count])
            if len(top_authors) < top_n:    # keep lowest_pub_count at 0 until N is reached
                continue
        else:                               # replace the lowest element with the found one
            for i in range(len(top_authors)):
                if top_authors[i][1] == lowest_pub_count:
                    top_authors[i] = [author, pub_count]
                    break
        lowest_pub_count = pub_count
        for i in range(len(top_authors)):   # find the new lowest element
            if top_authors[i][1] < lowest_pub_count:
                lowest_pub_count = top_authors[i][1]

Последовательный поиск самого низкого элемента в списке топ-50 амортизируется тем фактом, что он выполняется редко.

1 голос
/ 03 мая 2019
auth_dict = defaultdict(int)

for auth_list in zip(all_authors['author']):
    auth_list = auth_list[0]

    if '|' in auth_list:
        auths = auth_list.split('|')

        for auth in auths:
            auth_dict[auth] += 1
    else:
        auth_dict[auth_list] += 1

- это сложный способ записи

auth_dict = defaultdict(int)

for auth_list in all_authors['author']:
    for auth in auth_list.split('|'):
        auth_dict[auth] += 1

, и это может быть быстрее:

Counter(itertools.chain.from_iterable(
    auth_list.split('|') for auth_list in all_authors['author']))

, где itertools равно import itertools и Counter равно from collections import Counter.


most_pub_authors = []

for i in range(0, 50):
    max_pub_count = 0
    max_pub_auth = None

    for author, pub_count in auth_dict.items(): 
        if pub_count > max_pub_count:
            max_pub_count = pub_count
            max_pub_auth = author

    most_pub_authors.append( (max_pub_auth, max_pub_count) ) 
    del auth_dict[max_pub_auth]

print(most_pub_authors)

проходит через целый ряд довольно много раз.Попробуйте один проход:

most_pub_authors = heapq.nlargest(50, auth_dict.items(), key=itemgetter(1))

, где itemgetter равно from operator import itemgetter.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...