2 Моя программа работает, но очень медленно, она также замедляется во время работы

вопрос создан в Wed, May 8, 2019 12:00 AM

Я извлекаю данные из API академических знаний Microsoft, а затем использую ответы json в качестве словарей для извлечения необходимой мне информации. Когда я делаю это, я добавляю информацию в массив Numpy и в конце я изменяю ее на фрейм данных pandas для экспорта. Программа работает просто отлично, но для ее запуска требуется огромное количество времени. Кажется, что он замедляется по мере запуска, хотя, как в первые несколько раз через циклы, это занимает всего несколько секунд, но позже это занимает минуты.

Я пытался максимально упростить операторы if else, и это помогло немного, но не настолько, чтобы добиться больших результатов. Я также сократил количество обращений к API столько, сколько смог. Каждый запрос может возвращать только 1000 результатов, но мне нужно около 35000 результатов.

rel_info = np.array([("Title", "Author_Name", "Jornal_Published_In", "Date")])

for l in range(0, loops):                        # loops is defined above to be 35
    offset = 1000 * l
    # keep track of progress
    print("Progress:" + str(round((offset/total_res)*100, 2)) + "%")
    # get data with request to MAK. 1000 is the max count
    url = "https://api.labs.cognitive.microsoft.com/academic/v1.0/evaluate?expr=And(Composite(AA.AfN=='brigham young university'),Y>=1908)&model=latest&count=1000&offset="+str(offset)+"&attributes=Ti,D,AA.DAfN,AA.DAuN,J.JN"
    response = req.get(url + '&subscription-key={key}')

    data = response.json()

    for i in range(0, len(data["entities"])):
        new_data = data["entities"][i]
        # get new data
        new_title = new_data["Ti"]                 # get title

        if 'J' not in new_data:                    # get journal account for if keys are not in dictionaries
            new_journ = ""
        else:
            new_journ = new_data["J"]["JN"] or ""

        new_date = new_data["D"]                   # get date

        new_auth = ""                              # get authors only affiliated with BYU account for if keys are not in dictionary
        for j in range(0, len(new_data["AA"])):
            if 'DAfN' not in new_data["AA"][j]:
                new_auth = new_auth + ""
            else:
                if new_data["AA"][j]["DAfN"] == "Brigham Young University" and new_auth == "":     # posibly combine conditionals to make less complex
                    new_auth = new_data["AA"][j]["DAuN"]
                elif new_data["AA"][j]["DAfN"] == "Brigham Young University" and new_auth != "":
                    new_auth = new_auth +", "+ new_data["AA"][j]["DAuN"]
        # keep adding new data to whole dataframe
        new_info = np.array([(new_title, new_auth, new_journ, new_date)])
        rel_info = np.vstack((rel_info, new_info))
    
- 1
  1. Пожалуйста, покажите несколько минимальных, полных и проверяемых примеров в своем вопросе
    2019-05-08 16: 09: 05Z
  2. Вы точно знаете, где происходит замедление? Возможно, удаленный API раздражает вас и ограничивает ваши запросы?
    2019-05-08 16: 12: 17Z
  3. Я вернулся и несколько раз распечатывал просмотренный прогон, и обнаружил, что увеличение произошло из-за того, что я использую функцию vstack из numpy. По мере увеличения массива на стек уходит больше времени. Но я все еще не знаю, как обойти это, поскольку мне все еще нужно добавить любую новую информацию, которую я извлекаю, в больший массив.
    2019-05-08 16: 54: 23Z
  4. Не использовать массив. Это не имеет смысла в этом случае, похоже, вы работаете со строками? Просто используйте обычный список с. добавьте, что даст вам линейное время, но использование массива numpy с vstack делает этот алгоритм квадратичным
    2019-05-08 17: 05: 14Z
  5. Что вы подразумеваете под "использованием панд для экспорта"? В любом случае вы можете построить информационный фрейм pandas из списка списков, но используете ли вы только pandas для выгрузки в csv?
    2019-05-08 17: 06: 40Z
2 ответа                              2                         

Попробуйте получить результаты в пуле рабочих потоков, используя concurrent.futures следующим образом:

import concurrent.futures
import urllib.request

URLS = ['http://www.foxnews.com/',
        'http://www.cnn.com/',
        'http://europe.wsj.com/',
        'http://www.bbc.co.uk/',
        'http://some-made-up-domain.com/']

# Retrieve a single page and report the URL and contents
def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()

# We can use a with statement to ensure threads are cleaned up promptly
with concurrent.futures.ThreadPoolExecutor() as executor:
    # Start the load operations and mark each future with its URL
    future_to_url = {executor.submit(load_url, url, 60): url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print('%r generated an exception: %s' % (url, exc))
        else:
            print('%r page is %d bytes' % (url, len(data)))

https://docs.python.org/3/library/concurrent .futures.html     

0
2019-05-08 16: 20: 47Z

В итоге я решил эту проблему, изменив способ добавления большого массива данных, которые я собирал. Вместо добавления одной строки данных в каждой итерации я создал временный массив, который будет содержать 1000 строк данных, а затем добавил бы этот временный массив к полному массиву данных. Это заняло время пробега примерно до минуты, в отличие от 43 минут, которые требовались раньше.

rel_info = np.array([("Title", "Author_Name", "Jornal_Published_In", "Date")])

for req_num in range(0, loops):
offset = 1000 * req_num
# keep track of progress
print("Progress:" + str(round((offset/total_res)*100, 2)) + "%")
# get data with request to MAK. 1000 is the max count
url = "https://api.labs.cognitive.microsoft.com/academic/v1.0/evaluate?expr=And(Composite(AA.AfN=='brigham young university'),Y>=1908)&model=latest&count=1000&offset="+str(offset)+"&attributes=Ti,D,AA.DAfN,AA.DAuN,J.JN"
response = req.get(url + '&subscription-key={key}')

data = response.json()

for i in range(0, len(data["entities"])):
    new_data = data["entities"][i]
    # get new data
    new_title = new_data["Ti"]                 # get title

    if 'J' not in new_data:                    # get journal account for if keys are not in dictionaries
        new_journ = ""
    else:
        new_journ = new_data["J"]["JN"] or ""

    new_date = new_data["D"]                   # get date

    new_auth = ""                              # get authors only affiliated with BYU account for if keys are not in dictionary
    for j in range(0, len(new_data["AA"])):
        if 'DAfN' not in new_data["AA"][j]:
            new_auth = new_auth + ""
        else:
            if new_data["AA"][j]["DAfN"] == "Brigham Young University" and new_auth == "":     # posibly combine conditionals to make less complex
                new_auth = new_data["AA"][j]["DAuN"]
            elif new_data["AA"][j]["DAfN"] == "Brigham Young University" and new_auth != "":
                new_auth = new_auth +", "+ new_data["AA"][j]["DAuN"]

    # here are the changes
    # keep adding to a temporary array for 1000 entities
    new_info = np.array([(new_title, new_auth, new_journ, new_date)])
    if (i == 0): work_stack = new_info
    else: work_stack = np.vstack((work_stack, new_info))
# add temporary array to whole array (this is to speed up the program)
rel_info = np.vstack((rel_info, work_stack))
    
0
2019-05-08 17: 43: 15Z
источник размещен Вот